[英]How to Change Button Foreground Color Conditionally in WPF?
I have a button inside ItemsControl
(pagination kind control) I have a property named current_page
in my view model.我在ItemsControl
(分页类型控件)中有一个按钮,我的视图模型中有一个名为current_page
的属性。
I want to compare current_page
value to Content
of Button
that is (1 / 2 / 3) and want to change the foreground color of a button.我想将current_page
值与 (1 / 2 / 3) 的Button
Content
进行比较,并想更改按钮的前景色。
Please have a look at the code.请看一下代码。
My ViewModel我的视图模型
public PaginationModel pagination
{
get { return _pagination; }
set { _pagination = value; OnPropertyChanged("pagination"); }
}
My Pagination Model我的分页模型
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");
}
}
}
My Layout我的布局
<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>
Button Style Template按钮样式模板
<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>
You cannot bind the Value
of a DataTrigger
to a property, because it is not a dependency property.您不能将DataTrigger
的Value
绑定到属性,因为它不是依赖属性。 You can work around this by creating a custom multi-value converter that checks pages for equality.您可以通过创建一个用于检查页面是否相等的自定义多值转换器来解决此问题。
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();
}
}
The first value passed to the converter is the current page as int
and the second value is the page on the Button
as string
.传递给转换器的第一个值是作为int
的当前页面,第二个值是作为string
的Button
上的页面。 It is a bit odd that your current_page
is of type int
, but the PageList
is a collection of type string
, that is why we need to convert the second value.您的current_page
是int
类型有点奇怪,但PageList
是string
类型的集合,这就是我们需要转换第二个值的原因。
Create an instance of the converter in your resources before your style, so you can reference it.在样式之前在资源中创建转换器的实例,以便您可以引用它。
<local:PageEqualityToBooleanConverter x:Key="PageEqualityToBooleanConverter"/>
Finally, replace your DataTrigger
with the one below.最后,用下面的替换你的DataTrigger
。 We are using a MultiBinding
to be able to bind more than one value.我们正在使用MultiBinding
来绑定多个值。 The converter will convert both values to True
, if the page values match, otherwise False
.如果页面值匹配,转换器会将两个值都转换为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>
The first binding will find the parent ItemsControl
to access the view model that contains the current_page
.第一个绑定将找到父项ItemsControl
以访问包含current_page
的视图模型。 The second binding will bind to the data context of the associated button, which is the page string.第二个绑定将绑定到关联按钮的数据上下文,即页面字符串。 If you change the PageList
item type to int
this will still work.如果您将PageList
项目类型更改为int
这仍然有效。
I want to point out some observations on your code that might help you to improve it.我想指出一些对您的代码的观察,可能会帮助您改进它。
int
or creating a separate page item view model if you plan on having other properties than the page number in it.如果您计划在其中包含除页码以外的其他属性,请考虑将其int
或创建单独的页面项视图模型。Button
, which gets applied to all Button
controls in scope.您正在为Button
定义隐式样式,该样式应用于范围内的所有Button
控件。 If you use it in your pagination control only this might be ok, but if you intend to use it in other places, the DataTrigger
should not be included in it, as it is specific to this data context only.如果您仅在分页控件中使用它,这可能没问题,但如果您打算在其他地方使用它, DataTrigger
应将DataTrigger
包含在其中,因为它仅特定于此数据上下文。 Create separate style based on this one.在此基础上创建单独的样式。 Consider @BionicCode's comment about this.考虑@BionicCode 对此的评论。ListBox
could be a better fit for a paginator, because it has the notion of a SelectedItem
(and IsSelected
properties on its item containers that can be bound in a DataTrigger
), which is what you are trying to do here manually.正如@Andy 在评论中指出的那样, ListBox
可能更适合分页器,因为它具有SelectedItem
的概念(以及可以绑定在DataTrigger
项目容器上的IsSelected
属性),这就是您的想法试图在这里手动完成。The Value
property of a DataTrigger
cannot be data-bound. DataTrigger
的Value
属性不能是数据绑定的。
What you should do is to create a type that represents a Page
, add a Number
and IsCurrentPage
property to it and change the type of PageList
to be an ObservableCollection<Page>
instead of an ObservableCollection<string>
.你应该做的是创建一个代表一个类型Page
,一个加Number
和IsCurrentPage
属性并更改类型PageList
是一个ObservableCollection<Page>
代替ObservableCollection<string>
。
You could then simply look up the corresponding Page
in the PageList
and set its IsCurrentPage
property from the view model whenever the current_page
property is set.然后,您可以简单地查找相应的Page
中PageList
并设置其IsCurrentPage
每当从视图模型属性current_page
属性设置。
You should also make sure that the getter of the PageList
property doesn't create a new collection each time it's invoked.您还应该确保PageList
属性的 getter 不会在每次调用时创建新集合。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.