在数据模板中使用样式

8

我有一个名为item的类,它只包含两个属性。我将把它们显示在屏幕上,作为具有样式的按钮。这个问题涉及到如何根据IsSelected值来设置按钮的样式,当我想要影响的元素在样式而不是数据模板中时。我已经尝试过使用触发器,但无法使其工作。

以下是该类:

public class Item : ObservableObject
{
    private string _title;
    private bool _isSelected;

    public string Title
    {
        get { return _title; }
        set
        {
            _title = value;
            RaisePropertyChanged("Title");
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            RaisePropertyChanged("IsSelected");
        }
    }
}

我使用数据模板在ItemsControls中展示这些项。

<ItemsControl ItemsSource="{Binding Path=Items}" ItemTemplate="{StaticResource ResourceKey=ItemTemplate}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

使用以下样式和数据模板。
<Style x:Key="ItemButton" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Name="ButtonBorder" BorderThickness="2,2,2,0" BorderBrush="#AAAAAA"  CornerRadius="6,6,0,0"  Margin="2,20,0,0" Background="Black">
                    <ContentPresenter
                            VerticalAlignment="Center"  
                            HorizontalAlignment="Center"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<DataTemplate x:Key="ItemTemplate">
    <Button Height="60" Style="{StaticResource ItemButton}" Name="Button">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=Title}" 
                       HorizontalAlignment="Left" Margin="5,5,5,3" FontSize="25" Foreground="#6B6B6B" FontFamily="Arial" />
                <Button Style="{StaticResource NoChromeButton}" Margin="0,0,5,0">
                <Button.Content>
                    <Image Height="20" Source="/WpfApplication1;component/Image/dialogCloseButton.png"></Image>
                </Button.Content>
                <Button.ToolTip>
                    Close    
                </Button.ToolTip>
            </Button>
        </StackPanel>
    </Button>
</DataTemplate>

当IsSelected为True时,我需要将对象Item的"ButtonBorder"背景从黑色更改为白色。

我在数据模板中添加了触发器:

但这并没有起作用,我想是因为样式覆盖了数据模板,所以背景仍然保持为白色。但是当我尝试在样式中使用触发器时,我无法访问属性IsSelected?

数据模板触发器

    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding IsSelected}" Value="True">
            <Setter TargetName="Button" Property="Background" Value="White"/>
        </DataTrigger>
    </DataTemplate.Triggers>
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsSelected}" Value="True">
            <Setter Property="Background" Value="White"/>
        </DataTrigger>
    </Style.Triggers>

我有什么遗漏吗?

如果ItemButton仅用于Item对象,那么为什么不将样式合并到Item的DataTemplate中呢? - Jake Berger
这是一个公正的评论,我已经养成了将所有内容分开到单独的资源中的习惯,不确定这是否是一个好习惯,但我一直坚持着 :) - JonWillis
@jberger 如果不混杂内联模板和样式,这也使得资源和UI布局更易于阅读和修改。 - Rachel
1
我通常只是使用 Ctrl M,L 来“清理”一下。 - Jake Berger
2个回答

11

将你的ButtonBorder.Background设置为{TemplateBinding Background},这意味着它将使用分配给模板化按钮的任何背景颜色,然后您可以基于触发器更改按钮的背景

<Style x:Key="ItemButton" TargetType="Button">
    <Setter Property="Background" Value="Black" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Name="ButtonBorder" Background="{TemplateBinding Background}" ... >
                    <ContentPresenter ... "/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style x:Key="SelectableItemButton" TargetType="Button" BasedOn="{StaticResource ItemButton}">
    <Setter Property="Background" Value="Black" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsSelected}" Value="True">
            <Setter Property="Background" Value="White"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

<DataTemplate x:Key="ItemTemplate">
    <Button Height="60" Style="{StaticResource SelectableItemButton}">
        ...
    </Button>
</DataTemplate>

我还在制作一个SelectableItemButton样式,它继承自ItemButton,只实现了触发器。


那个很有效,我忘记了TemplateBinding,这是因为我在使用WPF时时间非常有限。但是{Binding IsSelected}如何知道它与我的对象相关,而不是与其他GUI控件(如复选框)上的IsSelected相关呢? - JonWillis
1
@JonWillis,由于您正在使用DataTrigger,绑定正在查看Button.DataContext.IsSelected,如果该值存在且为True,则更改背景颜色。您可以在技术上创建一个Button并将其DataContext设置为CheckBox对象,这可能会起作用,尽管我不建议这样做 :) - Rachel

0
在这句话中,目标应该是“ButtonBorder”,而不是“Button”吧?
<Setter TargetName="Button"....

此外,要访问属性IsSelected,您需要在样式中设置TargetType....


你说得对,我的确弄错了名字。但是TargetName不起作用。在DataTemplate中,ButtonBorder不存在,因为该名称在样式中定义。在样式中,TargetName不是可在触发器中使用的有效属性(这是Visual Studio告诉我的)。 - JonWillis
TargetType 被设置在样式上,它被设置为 "Button"。数据模板创建一个按钮和其中的内容,然后创建的按钮应用了 ItemButton 样式。 - JonWillis

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