简体   繁体   English

设置Label.Content以控制DataTrigger

[英]Setting Label.Content to Control on DataTrigger

recently I've tried to make label style which would allow to display image or textblock depending on property being set or not. 最近,我尝试制作标签样式,该样式将允许显示图像或文本块,具体取决于是否设置了属性。 I've bound proper objects to labels' DataContext and prepared reusable style for these labels. 我已经将适当的对象绑定到标签的DataContext并为这些标签准备了可重用的样式。 Default content is textblock with Name as its text but if IsIconSet property is true, then content would change into image with corresponding IconPath as source. 默认内容为文本块,其名称为Name,但如果IsIconSet属性为true,则内容将变为具有相应IconPath作为源的图像。

Similar approach works perfectly with label's properties like background or cursor but in described scenario it breaks up when IsIconSet has the same value in both instances. 类似的方法可以完美地与标签的属性(例如背景或光标)配合使用,但是在上述情况下,当IsIconSet在两个实例中具有相同的值时,该方法就会中断。 Then it displays nothing for first label and correct textblock/image for second label. 然后,它对第一个标签不显示任何内容,而对第二个标签显示正确的文本块/图像。

I've tried to attach converter to Name and IconPath bindings in style in order to check what value is being passed but it seems that it isn't even invoked on first label. 我尝试以样式将转换器附加到Name和IconPath绑定,以检查正在传递的值,但似乎甚至没有在第一个标签上调用它。

Has anyone managed to do something similar? 有没有人设法做类似的事情? Am I missing something fundamental? 我缺少基本的东西吗? Or maybe there is another approach for such behaviour? 也许还有另一种方法来处理这种行为? Any help will be appreciate. 任何帮助将不胜感激。

Simplified code: 简化代码:

MainWindow 主窗口

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

Style 样式

<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>

Classes 班级

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));
    }
}

LabelStyle can be used by multiple Labels, but TextBlock and Image from Content setter are created just once, there is only one instance for all labels, but it cannot be displayed in multiple places. LabelStyle可以由多个Label使用,但是TextBlock和Content setter中的Image只能创建一次,所有标签只有一个实例,但是不能在多个位置显示。 so it is displayed in only one. 因此它仅显示在一个中。

to fix the issue use ContentTemplate, like shown below. 要解决此问题,请使用ContentTemplate,如下所示。

<Setter Property="Content" Value="{Binding}"/> line means that entire DataContext is considered as Label Content. <Setter Property="Content" Value="{Binding}"/>行表示整个DataContext被视为标签内容。 Is is necessary for bindings in ContentTemplate 对于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>

alternatively, convert TextBlock and Image to non-shared resources: 或者,将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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM