【问题标题】:How to Change Button Foreground Color Conditionally in WPF?如何在 WPF 中有条件地更改按钮前景色?
【发布时间】:2020-10-06 07:55:18
【问题描述】:

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

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

请看一下代码。

我的视图模型

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>

【问题讨论】:

  • 由于触发器无法触发Button 的属性,因此DataTrigger 不应该是按钮ControlTemplate 的一部分,这是一个“内部”控制上下文,独立于任何数据类型。由于触发器在当前按钮的DataContext 的属性上触发,因此DataTrigger 必须在Button 之外,它可以访问DataContext,就像在Style 中针对Button 或者在DataTemplate 的项目模板。在这里,您处于专门针对特定 DataContext 即数据类型的上下文中。
  • 你可以把它变成一个列表框而不是itemscontrol 绑定Foreground到selecteditem的一个属性。使 PageList 成为视图模型列表,而不仅仅是字符串。为其添加一个画笔属性。或使用转换器将数字转换为画笔。具有 WordOrangeBush 的后备值。

标签: c# wpf xaml data-binding


【解决方案1】:

价值转​​换器解决方案

您不能将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 在 cmets 中指出的那样,ListBox 可能更适合分页器,因为它具有 SelectedItem 的概念(以及可以绑定的项目容器上的 IsSelected 属性) DataTrigger),这是您在此处尝试手动执行的操作。

【讨论】:

    【解决方案2】:

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

    你应该做的是创建一个代表Page的类型,添加一个NumberIsCurrentPage属性并将PageList的类型更改为ObservableCollection&lt;Page&gt;而不是@987654328 @。

    然后,您只需在PageList 中查找相应的Page,并在设置current_page 属性时从视图模型中设置其IsCurrentPage 属性。

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

    【讨论】:

      猜你喜欢
      • 2017-03-24
      • 1970-01-01
      • 1970-01-01
      • 2016-12-11
      • 2018-01-06
      • 2014-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多