简而言之:我有Style
。它使用TemplateBinding
一点点来使其参数化,而不是一遍又一遍地重复自己。但是,当使用该样式的触发器并且在该触发器中的setter中使用资源时,它就不会显示出来!甚至没有显示默认值。这是一个复制这个问题的小程序:
TestDictionary.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lcl="clr-namespace:MyNamespace">
<Style TargetType="Button" x:Key="BtnTest">
<Style.Resources>
<Label Content="{TemplateBinding lcl:TestClass.String}" x:Key="innerLabel"/>
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Content" Value="{DynamicResource innerLabel}"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
MainWindow.xaml
<Window x:Class="MyNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lcl="clr-namespace:MyNamespace"
Title="Test" Width="500" Height="350">
<Window.Resources>
<ResourceDictionary Source="TestDictionary.xaml"/>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="Enable/Disable" Click="Click"/>
<Button Grid.Column="1" x:Name="btn" Style="{DynamicResource BtnTest}" lcl:TestClass.String="TESTING"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
namespace MyNamespace
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Click(object sender, RoutedEventArgs e)
{
btn.IsEnabled = !btn.IsEnabled;
}
}
public class TestClass
{
public static string GetString(DependencyObject obj)
{
return (string)obj.GetValue(StringProperty);
}
public static void SetString(DependencyObject obj, string value)
{
obj.SetValue(StringProperty, value);
}
public static readonly DependencyProperty StringProperty =
DependencyProperty.RegisterAttached("String", typeof(string), typeof(TestClass), new PropertyMetadata("Default!"));
}
}
我没有使用TemplateBinding
,而是尝试了这个:
{Binding Path=lcl:TestClass.String, RelativeSource={RelativeSource AncestorType={x:Type Button}}}
它仍然无效。 我知道我可能做错了什么,但问题是:它是什么?
答案 0 :(得分:1)
现在我看到了细节。在相对来源之前你应该写的是:
Binding Path=(lcl:TestClass.String)
不要忘记添加括号。
答案 1 :(得分:1)
您真正需要做的就是在绑定中使用RelativeSource
。由于您在Button
上设置附加属性,在您的样式触发器中,您只需绑定到self上的附加属性:
<Style TargetType="Button" x:Key="BtnTest">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Content"
Value="{Binding Path=(lcl:TestClass.String), RelativeSource={RelativeSource Self}}"/>
</Trigger>
</Style.Triggers>
</Style>
使用您的方法很酷,因为Button
是ContentControl
,您附加的属性可以是任何对象,而不仅仅是字符串。
并澄清你之前的方法出了什么问题 -
TemplateBinding
仅适用于ControlTemplates
。只有在为您创建模板的类上定义DependencyProperty
时,它才有效(例如,您永远不能TemplateBinding
到Grid.Row
)RelativeSource
绑定很接近!Label
里面有一个Button
作为内容,它可能有用(我没有测试过),但这似乎不是最好的主意,因为您的Button
可以托管您想要的任何对象。 编辑更复杂的例子
因此,如果您需要显示多个动态属性,我建议您使用DataTemplate
:
<Style TargetType="Button" x:Key="BtnTest">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Label Content="{Binding Path=(lcl:TestClass.String), RelativeSource={RelativeSource AncestorType={x:Type Button}}}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
此外,我想指出,如果您有多个不同的标准来更改内容的外观,DataTemplateSelector
可能更适用。
答案 2 :(得分:0)
您的示例不起作用,因为TemplateBinding
仅适用于ControlTemplate
。要获得类似于TemplateBinding
Resources
的内容,您需要做其他事情。 Here's an example.
为了让TemplateBinding
起作用,你需要稍微修改一下代码(这只是一个没有资源的例子):
<Style x:Key="BtnTest" TargetType="{x:Type Button}">
<Setter Property="MinHeight" Value="100" />
<Setter Property="MinWidth" Value="200" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="Blue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2" Background="{TemplateBinding Background}">
<ContentPresenter RecognizesAccessKey="True" Content="{TemplateBinding lcl:TestClass.String}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</Style.Triggers>
</Style>
有关此主题的有用链接:Here, and here too.
修改强>
您也可以使用应用程序设置而不是TestClass
。打开“项目 - &gt;属性:MyNamespace ... - &gt;设置”并添加您的设置:
命名强> --------的类型强> --------的范围强> ------- - 的值强>
LabelText的--- --------串用户----------默认
在代码中设置LabelText
的值。例如:
public MainWindow()
{
InitializeComponent();
MyNamespace.Properties.Settings.Default.LabelText = "Testing";
}
并使用此ResourceDictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:MyNamespace.Properties"
xmlns:lcl="clr-namespace:MyNamespace">
<Style TargetType="Button" x:Key="BtnTest">
<Style.Resources>
<Label x:Key="innerLabel" Content="{Binding Source={x:Static properties:Settings.Default}, Path=LabelText, Mode=TwoWay}" />
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Content" Value="{DynamicResource innerLabel}"/>
</Trigger>
</Style.Triggers>
</Style>