如何在代码中设置控件模板?

37

我在XAML中有以下内容

<ControlTemplate TargetType="{x:Type Button}">
    <Image ...>
</ControlTemplate>

我希望在 C# 代码中实现同样的功能。我该如何实现?

ControlTemplate ct = new ControlTemplate();..
Image img = new Image();..
现在该如何将此图像分配给控件模板?我们可以这样做吗,还是我漏掉了什么概念?
3个回答

36

在代码后端创建模板不是一个好主意,理论上,应该通过定义 ControlTemplate.VisualTree 来完成这一过程,它是一个 FrameworkElementFactory

ControlTemplate template = new ControlTemplate(typeof(Button));
var image = new FrameworkElementFactory(typeof(Image));
template.VisualTree = image;

属性分配非常迂回,因为您需要使用SetValueSetBinding

image.SetValue(Image.SourceProperty, ...);

关于之前被接受的答案和引用的内容:

以编程方式设置ControlTemplate与使用XAML是一样的,因为我们必须使用XamlReader类。

这个说法是错误的,我们并不“必须”使用它。


如果我在运行时分配模板,我会将它们定义为资源,需要时可以加载它们。


编辑:根据文档 FrameworkElementFactory 已经被弃用:

  

这个类是一个被弃用的程序化创建模板的方式,它是 FrameworkTemplate 的子类,例如 ControlTemplate 或 DataTemplate;当您使用此类创建模板时,并非所有模板功能都可用。建议以从字符串或内存流中使用 XamlReader 类的 Load 方法来以编程方式创建模板。

我想知道这个建议是否好。如果可以避免使用字符串和 XamlReader,我个人仍然会选择在XAML中将模板定义为资源。


谢谢,完美地解决了问题...我知道这不是一个好主意,但在某些特定情况下我别无选择。 - Haris Hasan
好的,我只是引用了我发现的网站上的文本。使用XamlReader.Parse有什么问题吗? - obenjiro
@Ai_boy:这只是对XAML的解析,既不必要也不是我推荐的做法。如果您有静态的XAML,最好将其创建为XAML资源,而不是将XML字符串搞到代码后面。 - H.B.
@h-b 哦,我明白了... 我认为“动态”Xaml不适用于商业应用程序,所以... 无论如何,感谢您的回答。 - obenjiro

25

http://www.eggheadcafe.com/sample-code/SilverlightWPFandXAML/73fdb6a2-6044-4c43-8766-afa12618ddc1/set-controltemplate-programmatically.aspx

通过编程设置ControlTemplate就像使用XAML一样,因为我们必须使用XamlReader类。例如,以下是设置按钮模板的代码,假设我们想在加载后设置按钮模板。

private void Button_Loaded(object sender, RoutedEventArgs e) {
    var button = sender as Button;
    string template =
        "<ControlTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
            TargetType=\"Button\">" +
            "<Border>" +
                 "<ContentPresenter/>" +
            "</Border>" +
        "</ControlTemplate>";
    button.Template = (ControlTemplate)XamlReader.Parse(template);
}

由于我们使用字符串来指定模板的XAML代码,因此可以使用XamlReader的Parse方法。XamlReader还有一个Load方法,主要用于流或XAML或XML读取器。请注意,我们必须包括XML命名空间http://schemas.microsoft.com/winfx/2006/xaml/presentation,因为我们需要的ControlTemplate、Border和其他控件都在那里定义。如果我们没有包括它,我们将遇到运行时异常。基本上,我们必须放置模板所需的命名空间。

0

如果您只需要更改按钮图像,则可以这样做。

  1. 创建一个依赖属性,它将表示您何时要更改图像(布尔值),或者您可以创建一个枚举,其中包含所有可能的图像,例如
  2. 枚举Images { Image1 = 0,Image2 = 1,Image2 = 3 }。创建此类型的依赖属性“CurrentButtonImage”,该属性将与按钮关联。

现在在XAML中在按钮模板中使用它

在CurrentButtonImage的属性更改时,使用代码更新按钮的图像(在代码后台中)

CurrentImagePropertyChangedhandler(....,...)  
{  
    switch(CurrentButtonImage)  
    {  
        case "Image1" :  
          this._ButtonImage.Fill = (DrawingBrush)csd.FindResource("Image1DrawingBrush");
          break;
    }
}

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