将ControlTemplate XAML转换为C#

3

我一直在努力将以下代码转换为纯C#,这段XAML代码来自Cavanagh的博客,介绍如何在任何东西上制作圆角。这段代码可以正常工作,但有时需要它具有动态性,因此需要将其转换为C#。如果您能帮忙,那就太好了。

<Setter Property="Template">
<Setter.Value>
    <ControlTemplate TargetType='{x:Type ListViewItem}'>
        <Grid>
            <Border CornerRadius="15" Name="mask" Background="White"/>
            <StackPanel Background="Beige">
                <StackPanel.OpacityMask>
                    <VisualBrush Visual="{Binding ElementName=mask}"/>
                </StackPanel.OpacityMask>
                <GridViewRowPresenter Content="{TemplateBinding Content}" Columns="{TemplateBinding GridView.ColumnCollection}"/>
                <TextBlock Background="LightBlue" Text="{Binding News}" />
            </StackPanel>
        </Grid>
    </ControlTemplate>
</Setter.Value>

到目前为止,我已经有了以下内容,但是我遇到了错误。

FrameworkElementFactory border = new FrameworkElementFactory(typeof(Border));
border.SetValue(Border.BackgroundProperty, Brushes.White);
border.SetValue(Border.CornerRadiusProperty, new CornerRadius(8, 8, 8, 8));
border.SetValue(Border.NameProperty, "roundedMask");

据我所知,我无法将VisualBrush作为FrameworkElementFactory(会崩溃),但如果我将其声明为常规元素VisualBrush,我无法将border作为Visual传递进去,因为它是FrameworkElementFactory。
简单地说,我迷失了方向,任何帮助都将不胜感激。 感谢您的任何帮助。

1
你知道在XAML中可以为元素提供名称,然后在代码后台引用它,以提供所需的动态功能。你不需要在代码后台构建整个元素。 - Aaron McIver
为了以后的参考,XAML会被解析成C#(或在VB项目中是VB)。编译后,在.obj文件夹中查找MyXamlFile.g.cs。它包含了解析后的代码。 - Tergiver
2
@Tergiver 这不准确(至少不再准确)- XAML 生成 .BAML(在 WPF 中),而 Codebehind C#/VB 等代码用于将命名引用分配给类变量(codebehind 是一个补充 BAML 的部分类)。 - George Birbilis
2个回答

6

您实际上并不需要将其转换为C#代码以便动态应用。如果您将其添加到应用程序资源中,在App.xaml文件中按照以下方式进行操作:

<Application.Resources>
    <ControlTemplate TargetType='{x:Type ListViewItem}' x:Key="MyListViewItemTemplate">
        <Grid>
            <Border CornerRadius="15" Name="mask" Background="White"/>
            <StackPanel Background="Beige">
                <StackPanel.OpacityMask>
                    <VisualBrush Visual="{Binding ElementName=mask}"/>
                </StackPanel.OpacityMask>
                <GridViewRowPresenter Content="{TemplateBinding Content}" Columns="{TemplateBinding GridView.ColumnCollection}"/>
                <TextBlock Background="LightBlue" Text="{Binding News}" />
            </StackPanel>
        </Grid>
    </ControlTemplate>
</Application.Resources>

请注意x:Key属性,该属性为此项提供键值。
然后您可以在代码中的任何位置查找它...
ControlTemplate template = this.Findresource("MyListViewItemTemplate") as ControlTemplate

您随时可以使用它!


是的,没错,我可以这样做,但我的好奇心驱使着我,我真的想知道这个C#代码会是什么样子。我只是觉得在代码中做这件事要困难得多。有时候它并不是那么显而易见。谢谢你提供的想法。 - Nithos
据我所知,以前有一个名为XamlIt的工具,应该能够将这样的XAML转换为C#,但现在在网上找不到它了。 - George Birbilis

3

您不想知道这个。说真的,你不想知道,这是一个噩梦。

编辑:如果我没有犯错,这就是您代码的翻译...

Setter setter = new Setter();
setter.Property = ListViewItem.TemplateProperty;
ControlTemplate template = new ControlTemplate(typeof(ListViewItem));
var grid = new FrameworkElementFactory(typeof(Grid));
var border = new FrameworkElementFactory(typeof(Border));
border.SetValue(Border.BackgroundProperty, Brushes.White);
border.SetValue(Border.NameProperty, "mask");
border.SetValue(Border.CornerRadiusProperty, new CornerRadius(15));
grid.AppendChild(border);
var stackPanel = new FrameworkElementFactory(typeof(StackPanel));
stackPanel.SetValue(StackPanel.BackgroundProperty, Brushes.Beige);
var visualBrush = new FrameworkElementFactory(typeof(VisualBrush));
visualBrush.SetBinding(VisualBrush.VisualProperty, new Binding() { ElementName = "mask" });
stackPanel.SetValue(StackPanel.OpacityMaskProperty, visualBrush);
var gridViewRowPresenter = new FrameworkElementFactory(typeof(GridViewRowPresenter));
gridViewRowPresenter.SetValue(GridViewRowPresenter.ContentProperty, new TemplateBindingExtension(GridViewRowPresenter.ContentProperty));
gridViewRowPresenter.SetValue(GridViewRowPresenter.ColumnsProperty, new TemplateBindingExtension(GridView.ColumnCollectionProperty));
stackPanel.AppendChild(gridViewRowPresenter);
var textBlock = new FrameworkElementFactory(typeof(TextBlock));
textBlock.SetValue(TextBlock.BackgroundProperty, Brushes.LightBlue);
textBlock.SetBinding(TextBlock.TextProperty, new Binding("News"));
stackPanel.AppendChild(textBlock);
grid.AppendChild(stackPanel);
template.VisualTree = grid;
setter.Value = template;

编辑:仍然有一个错误,VisualBrush不能像那样创建,其他部分似乎可以工作。


没错,这就是我卡住的地方。看起来你需要直接创建VisualBrush,即VisualBrush vbrush = new VisualBrush。但是我无法直接将边框传递进去,因为它不是一个Visual而是一个FrameworkElementFactory...这就是让我困惑的部分...还是谢谢你的帮助。 - Nithos
卡在同一个地方了。似乎FrameworkFactory中没有应用子工厂到公开属性的逻辑。这可能就是有关该类过时的免责声明的原因。有各种示例显示嵌入的XAML代码,但那也存在问题。 - Quark Soup
可能他们在内部使用了一个值转换器,你可以尝试找到它是哪一个并调用它。 - George Birbilis
@GeorgeBirbilis:(工厂方法已经过时了。) - H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接