如何在Style中的WPF DataTemplate中使用Binding

3

我对WPF数据绑定/样式/模板很陌生,现在我想使用一个样式(Style)应用一组属性值到按钮上。该样式绑定到一个类的字段。如您所见,这对BackColor属性起作用。但是,当我尝试设置TextBlock的文本时,它不起作用(也没有绑定错误)。我的最终目标是能够将图像设置为内容。

如果我不使用DataTemplate,并使用SetterProperty =“Content”而不是“ContentTemplate”,它将适用于一个按钮,但是添加第二个按钮时会给出运行时错误“指定的元素已成为另一个元素的逻辑子元素,请先断开连接。”

我漏掉了什么?我应该把什么放入“TextBlock Text=”中?

顺便说一句,一旦完成,我希望将样式移到全局范围内,因此我不想使用任何明确引用MyClass的东西。

<Window.Resources>
    <Style TargetType="Button" x:Key="MyStyle">
        <Setter Property="Background" Value="{Binding BackColor}"/>
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="XYZ-"/>
                        <TextBlock Text="{Binding Text}"/>
                    </StackPanel>                        
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<StackPanel Orientation="Horizontal" Height="30">
    <Button Style="{StaticResource MyStyle}" DataContext="{Binding Action1}"/>
    <Button Style="{StaticResource MyStyle}" DataContext="{Binding Action1}"/>
    <Button Style="{StaticResource MyStyle}" DataContext="{Binding Action2}"/>
    <Button Style="{StaticResource MyStyle}" DataContext="{Binding Action2}"/>
</StackPanel>

并且

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DataContext = this;

        Action1 = new MyClass() { Text = "ACTION1", BackColor = new SolidColorBrush(Colors.Red) };
        Action2 = new MyClass() { Text = "ACTION2", BackColor = new SolidColorBrush(Colors.Green) };
    }
    public MyClass Action1{get; private set;}
    public MyClass Action2{get; private set;}
}

public class MyClass
{
    public string Text { get; set; }
    public Brush BackColor { get; set; }
}
1个回答

5
在您的原始问题中,您需要
<Setter Property="Background" Value="{Binding BackColor}"/>
<Setter Property="Content" Value="{Binding Text}"/>

现在您需要使用相对来源绑定。
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
           AncestorType=Button}, Path=DataContext.Text}"/>

然而,你最好使用以下的ItemsControl来实现:
Xaml
<Page.Resources>
    <DataTemplate x:Key="ItemTemplate" DataType="{x:Type Samples:MyClass}">
        <Button Background="{Binding BackColor}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="XYZ-"/>
                <TextBlock Text="{Binding Text}"/>
            </StackPanel>
        </Button>
    </DataTemplate>
  <ItemsPanelTemplate x:Key="ItemsPanelTemplate">
        <StackPanel Orientation="Horizontal"/>
    </ItemsPanelTemplate>
</Page.Resources>
<Page.DataContext>
    <Samples:DataTemplateItemsControlViewModel/>
</Page.DataContext>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <ItemsControl 
        ItemsSource="{Binding Items}" 
        ItemsPanel="{StaticResource ItemsPanelTemplate}"
        ItemTemplate="{StaticResource ItemTemplate}"/>
</Grid>

C#

public class DataTemplateItemsControlViewModel
{
    public DataTemplateItemsControlViewModel()
    {
        Items =
            new Collection<MyClass>
                {
                    new MyClass
                        {
                            Text = "ACTION1", 
                            BackColor = new SolidColorBrush(Colors.Red)
                        },
                    new MyClass
                        {
                            Text = "ACTION2", 
                            BackColor = new SolidColorBrush(Colors.Blue)
                        },
                    new MyClass
                        {
                            Text = "ACTION3", 
                            BackColor = new SolidColorBrush(Colors.Green)
                        },
                    new MyClass
                        {
                            Text = "ACTION4", 
                            BackColor = new SolidColorBrush(Colors.Yellow)
                        },
                };
    }

    public IList<MyClass> Items { get; private set; }
}

谢谢您的回答。是的,这个可以用,但是我需要在内容下面有更多可见的对象。我编辑了我的代码示例以澄清这一点。 - Night94
不使用相对源绑定,结果与我上面的代码相同。当我将样式应用于一个按钮时,它可以工作,但是在多个按钮中仍然会出现相同的异常:“指定的元素已经是另一个元素的逻辑子级。请先断开连接。” - Night94
我已经完全复制了你的代码,并修改了DataTemplate为 <StackPanel Orientation="Horizontal"> <TextBlock Text="XYZ-"/> <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}, Path=DataContext.Text}"/> </StackPanel> 它运行良好。 - Phil
是的,你说得对。我做了一些其他的修改,搞乱了它。你的解决方案百分之百有效。非常感谢! - Night94

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