如何在WPF中有条件地更改按钮前景颜色



我在ItemsControl(分页类型控件(中有一个按钮,在我的视图模型中我有一个名为current_page的属性。

我想将current_page的值与ButtonContent进行比较,即(1/2/3(,并想更改按钮的前景色。

请看一下代码。

我的ViewModel

public PaginationModel pagination
{
get { return _pagination; }
set { _pagination = value; OnPropertyChanged("pagination"); }
}

我的分页模型

public class PaginationModel: INotifyPropertyChanged {
private int _total_items;
public int total_items {
get {
return _total_items;
}
set {
_total_items = value;
OnPropertyChanged("total_items");
}
}
private int _items_per_page;
public int items_per_page {
get {
return _items_per_page;
}
set {
_items_per_page = value;
OnPropertyChanged("items_per_page");
}
}
private int _current_page;
public int current_page {
get {
return _current_page;
}
set {
if (value <= total_pages + 1 && value > 0) {
_current_page = value;
OnPropertyChanged("current_page");
}
}
}
private int _total_pages;
public int total_pages {
get {
return _total_pages;
}
set {
_total_pages = value;
OnPropertyChanged("total_pages");
}
}
private ObservableCollection < string > _PageList;
public ObservableCollection < string > PageList {
get {
_PageList = new ObservableCollection < string > ();
for (int i = 0; i < total_pages; i++) {
_PageList.Add((i + 1).ToString());
}
return _PageList;
}
set {
_PageList = value;
OnPropertyChanged("PageList");
}
}
}

我的布局

<ItemsControl ItemsSource="{Binding pagination.PageList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0">
<Button Content="{Binding}"  CommandParameter="{Binding RelativeSource={RelativeSource Self}}"
Command="{Binding DataContext.ChangePage, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
Width="20"
Margin="10,0"></Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

按钮样式模板

<Style TargetType="{x:Type Button}" >
<Setter Property="Foreground" Value="{StaticResource WordOrangeBrush}"  />
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="FontFamily" Value="{StaticResource HelveticaNeue}"></Setter>
<Setter Property="FontSize" Value="14"></Setter>
<Setter Property="Foreground" Value="#ff9f00"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="Foreground" Value="#ff9f00" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="Foreground" Value="White" />
</Trigger>
<!--I want to bind current page value in place of 1-->
<DataTrigger Binding="{Binding}" Value="1">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>

价值转换器解决方案

不能将DataTriggerValue绑定到属性,因为它不是依赖属性。您可以通过创建一个自定义的多值转换器来检查页面是否相等来解决此问题。

public class PageEqualityToBooleanConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return (int)values[0] == System.Convert.ToInt32(values[1]);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}

传递给转换器的第一个值是作为int的当前页面,第二个值是Button上作为string的页面。有点奇怪的是,您的current_pageint类型,但PageListstring类型的集合,这就是为什么我们需要转换第二个值。

在您的风格之前,在您的资源中创建转换器的实例,以便您可以引用它。

<local:PageEqualityToBooleanConverter x:Key="PageEqualityToBooleanConverter"/>

最后,将您的DataTrigger替换为下面的。我们使用MultiBinding来绑定多个值。如果页面值匹配,转换器将两个值转换为True,否则为False

<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource PageEqualityToBooleanConverter}">
<Binding Path="DataContext.pagination.current_page" RelativeSource="{RelativeSource AncestorType={x:Type ItemsControl}}"/>
<Binding/>
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>

第一个绑定将找到父ItemsControl以访问包含current_page的视图模型。第二个绑定将绑定到关联按钮的数据上下文,即页面字符串。如果将PageList项目类型更改为int,此操作仍然有效。

建议

我想指出一些对你的代码的观察,可能会帮助你改进它

  • 正如我已经提到的,您的集合项类型与当前项属性类型不同似乎很奇怪。如果您计划在其中包含页码以外的其他属性,请考虑将其设为int,或者创建一个单独的页面项视图模型
  • 您正在为Button定义一个隐式样式,该样式将应用于范围中的所有Button控件。如果您仅在分页控件中使用它,则可能可以,但如果您打算在其他地方使用它,DataTrigger不应包含在其中,因为它仅特定于此数据上下文。在此基础上创建单独的样式。考虑一下@BionicCode对此的评论
  • 正如@Andy在评论中指出的那样,ListBox可能更适合分页器,因为它有SelectedItem的概念(以及可以绑定到DataTrigger中的项目容器上的IsSelected属性(,这正是您在这里手动尝试做的

DataTriggerValue属性不能进行数据绑定。

您应该创建一个代表Page的类型,向其添加NumberIsCurrentPage属性,并将PageList的类型更改为ObservableCollection<Page>而不是ObservableCollection<string>

然后,只要设置了current_page属性,就可以在PageList中查找相应的Page,并从视图模型中设置其IsCurrentPage属性。

您还应该确保PageList属性的getter不会在每次调用时创建新的集合。

最新更新