设置Label.Content以控制DataTrigger

时间:2018-02-10 19:54:19

标签: c# .net wpf

最近我尝试制作标签样式,允许根据设置的属性显示图像或文本块。我已将正确的对象绑定到标签的DataContext,并为这些标签准备了可重用的样式。默认内容是使用Name作为文本的文本块,但如果IsIconSet属性为true,则内容将更改为具有相应IconPath作为源的图像。

类似的方法与标签的属性(如背景或光标)完美配合,但在描述的场景中,当IsIconSet在两个实例中具有相同的值时,它会中断。然后它不会显示第一个标签的内容,也不显示第二个标签的文本块/图像。

我试图将转换器附加到样式中的Name和IconPath绑定,以便检查传递的值,但似乎甚至没有在第一个标签上调用它。

有没有人设法做类似的事情?我错过了什么基本的东西?或许这种行为还有另一种方法吗? 任何帮助将不胜感激。

简化代码:

主窗口

<StackPanel DataContext="{Binding First}">
    <Label Style="{StaticResource LabelStyle}" />
</StackPanel>
<StackPanel DataContext="{Binding Second}">
    <Label Style="{StaticResource LabelStyle}" />
</StackPanel>

风格

<Style x:Key="LabelStyle" TargetType="Label">
    <Setter Property="Content">
        <Setter.Value>
            <TextBlock Text="{Binding Name}"/>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsIconSet}" Value="True">
            <Setter Property="Content">
                <Setter.Value>
                    <Image Source="{Binding IconPath}"/>
                </Setter.Value>
            </Setter> 
        </DataTrigger>
    </Style.Triggers>
</Style>

public class ViewModel : INotifyPropertyChanged
{
    private LabelClass _first;
    private LabelClass _second;

    public LabelClass First
    {
        get => _first;
        set
        {
            _first = value;
            OnPropertyChanged();
        }
    }
    public LabelClass Second
    {
        get => _second;
        set
        {
            _second = value;
            OnPropertyChanged();
        }
    }

    public ViewModel()
    {
        First = new LabelClass("First", "Resources/first.png");
        Second = new LabelClass("Second", "Resources/second.png");
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class LabelClass : INotifyPropertyChanged
{
    private string _name;
    private string _iconPath;

    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }
    public string IconPath
    {
        get => _iconPath;
        set
        {
            _iconPath = value;
            OnPropertyChanged();
            OnPropertyChanged("IsIconSet");
        }
    }
    public bool IsIconSet => !string.IsNullOrEmpty(IconPath);

    public LabelClass(string name, string iconPath = null)
    {
        Name = name;
        IconPath = iconPath;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

1 个答案:

答案 0 :(得分:0)

LabelStyle可以被多个标签使用,但TextBlock和Image from Content setter只创建一次,所有标签只有一个实例,但不能在多个地方显示。所以它只显示一个。

修复问题使用ContentTemplate,如下所示。

<Setter Property="Content" Value="{Binding}"/>行表示整个DataContext被视为标签内容。在ContentTemplate

中绑定是必要的
<Style x:Key="LabelStyle" TargetType="Label">
    <Setter Property="Content" Value="{Binding}"/>
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsIconSet}" Value="True">
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <Image Source="{Binding IconPath}"/>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

或者,将TextBlock和Image转换为非共享资源:

<Image Source="{Binding IconPath}" x:Key="Img" x:Shared="False"/>
<TextBlock Text="{Binding Name}" x:Key="Txt" x:Shared="False"/>

<Style x:Key="LabelStyle" TargetType="Label">
    <Setter Property="Content" Value="{StaticResource Txt}"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsIconSet}" Value="True">
            <Setter Property="Content" Value="{StaticResource Img}"/>
        </DataTrigger>
    </Style.Triggers>
</Style>