【问题标题】:WPF MVVM Background UIElement doesn't change on NotifyPropertyChangedWPF MVVM 背景 UIElement 在 NotifyPropertyChanged 上没有改变
【发布时间】:2014-02-28 06:12:24
【问题描述】:

首先解释一下我想做什么。

我正在创建一个过滤器,用于显示具有相同实体类型 (ProvisionalOrder) 的多个对象。该实体有一个属性 DateTime Date。有了这个日期,我想过滤。例如:如果用户点击日期 X ,视图将显示所有日期为 X 的临时订单。

对于每个日期,我都会在视图中创建一个按钮。我想像这样设置按钮的背景: 橙红色 = 已激活。 LightSkyBlue = 未激活。

当我启动程序时,背景很好。但是,如果我单击该按钮,则背景不会变为应有的颜色。

数据触发器有问题?

查看:

 <!-- Grid with date buttons -->
    <ItemsControl Grid.Row="1" ItemsSource="{Binding DatePairs}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Content="{Binding Path=Key}" 
                        Command="{Binding RelativeSource={RelativeSource  Mode=FindAncestor, AncestorType={x:Type this:ProvisionalOrderSelecterView} }, 
                                Path=DataContext.FilterDateCommand}" 
                        CommandParameter="{Binding Path=Key}">
                    <Button.Style>
                        <Style TargetType="Button">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Path=Value}" Value="True">
                                    <Setter Property="Background" Value="OrangeRed"/>
                                </DataTrigger>

                                <DataTrigger Binding="{Binding Path=Value}" Value="False">
                                    <Setter Property="Background" Value="LightSkyBlue"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Button.Style>
                </Button>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
<!-- End Grid with date buttons -->

代码隐藏视图:

public partial class ProvisionalOrderSelecterView : UserControl
{
    public ProvisionalOrderSelecterView(ProvisionalOrderSelecterViewModel provisionalOrderSelecterViewModel)
    {
        InitializeComponent();
        this.DataContext = provisionalOrderSelecterViewModel;
    }
}

视图模型:

public class ProvisionalOrderSelecterViewModel : INotifyPropertyChanged
{
    private RelayCommand<DateTime> filterDateCommand; 

    private SortedDictionary<DateTime, bool> datePairs;
    private ObservableCollection<ProvisionalOrder> provisionalOrders; 

    public ProvisionalOrderSelecterViewModel(ObservableCollection<ProvisionalOrder> provisionalOrders)
    {
        this.ProvisionalOrders = provisionalOrders;

        if(datePairs == null)
            datePairs = new SortedDictionary<DateTime, bool>();

        FillDates();
        datePairs.Add(DateTime.Now.Date, true);

    }

    void FillDates()
    {
        var copy = datePairs;
        datePairs = new SortedDictionary<DateTime, bool>();

        foreach (var provisionalOrder in this.provisionalOrders.Where(provisionalOrder => !datePairs.ContainsKey(provisionalOrder.Date.Date)))
        {
            datePairs.Add(provisionalOrder.Date.Date, copy.ContainsKey(provisionalOrder.Date.Date) && copy[provisionalOrder.Date.Date]);
        }
    }

    private void ProvisionalOrders_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        OnPropertyChanged("ProvisionalOrders");
    }

    public ObservableCollection<ProvisionalOrder> ProvisionalOrders
    {
        get { return this.provisionalOrders; }
        set
        {
            this.provisionalOrders = value;
            this.provisionalOrders.CollectionChanged += ProvisionalOrders_CollectionChanged;
            OnPropertyChanged("ProvisionalOrders");
        }
    }

    public SortedDictionary<DateTime, bool> DatePairs
    {
        get { return this.datePairs; }
        set
        {
            this.datePairs = value;
            OnPropertyChanged("DatePairs");
        }
    } 

    public ICommand FilterDateCommand
    {
        get { return this.filterDateCommand ?? (this.filterDateCommand = new RelayCommand<DateTime>(FilterDate)); }
    }

    void FilterDate(DateTime date)
    {
        datePairs[date] = !datePairs[date];
        OnPropertyChanged("DatePairs");
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion // INotifyPropertyChanged Members
}

编辑:我做了一个混乱的解决方案。如果有人仍然知道答案,如果您能与 stackoverflow 分享,我将不胜感激。

回答: 在我的按钮上,我做了一个点击事件。

 private void DateButton_Click(object sender, RoutedEventArgs e)
    {
        var button = sender as Button;

        if (button != null)
        {
            var background = button.Background as SolidColorBrush;

            if (background != null)
            {
                button.Background = background.Color.Equals(Colors.OrangeRed)
                                        ? new SolidColorBrush(Colors.LightSkyBlue)
                                        : new SolidColorBrush(Colors.OrangeRed);
            }
        }

        e.Handled = true;
    }

【问题讨论】:

  • 这里有两个问题。首先,当您绑定到 Dictionary 以有效地绑定到 IEnumerable&lt;KeyValuePair&lt;DateTime, bool&gt;&gt;KeyValuePair 是结构,所以值类型,因此 WPF 将复制它的值而不是保持对它的引用。它也没有实现INotyfyPropertyChanged,你不能/不能改变它的Value

标签: wpf mvvm background datatrigger


【解决方案1】:

属性“值”应从 false 更改为 true。您需要一种在单击按钮时将“Value”的值更改为 true 的方法。您在触发器中使用它,但没有将“值”绑定到任何东西以使其更改。更好的解决方案是使用切换按钮并将 ischecked 属性绑定到“值”。此外,您不需要有 2 个触发器。 检查此切换按钮: WPF ToggleButton IsChecked Trigger

【讨论】:

  • 属性“值”更改为: datePairs[date] = !datePairs[date];我已经阅读了 dkozl 他的答案,问题确实是 KeyValuePair。也许使用切换按钮是一个很好的解决方案。我会检查一下。谢谢
猜你喜欢
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 2015-07-15
  • 1970-01-01
  • 2021-04-05
  • 2018-10-14
  • 2011-10-06
  • 2021-12-22
相关资源
最近更新 更多