WPF数据绑定:如何检测项目更改?

时间:2011-08-01 08:16:26

标签: wpf data-binding

我在WPF数据绑定方面存在一些问题,我希望在我的解释中明确一点,因为我担心这个问题非常微妙。

我基本上有一个带有一堆ComboBox的WPF UserControl,每个ComboBox都相互链接。我的意思是第一个组合框填充了一些元素,当用户选择和项目时,第二个组合框填充基于先前选择的元素,依此类推与其他combox。 所有组合框都与UpdateSourceTrigger = LostFocus绑定。

组合的ItemsSource属性的代码如下所示:

    private ICollectionView allTicketTypesView;
    public IEnumerable<TicketTypeBase> AllTicketTypes
    {
        get { return this.allTicketTypesView.SourceCollection.Cast<TicketTypeBase>(); }
        private set
        {
            IEnumerable<TicketTypeBase> enumerable = value ?? new TicketTypeBase[0];
            ObservableCollection<TicketTypeBase> source = new ObservableCollection<TicketTypeBase>(enumerable);
            this.allTicketTypesView = CollectionViewSource.GetDefaultView(source);
            this.OnPropertyChanged("AllTicketTypes");
        }
    }

组合的SelectedItem属性的代码与此代码类似:

private TicketTypeBase ticketType;
public TicketTypeBase TicketType
{
    get { return this.ticketType; }
    set
    {
        this.ticketType = value;
        this.OnPropertyChanged("TicketType");
        this.UpdateConcessions();
    }
}    

我遇到了一个微妙的问题: 当我用键盘和/或鼠标移动到我的组合上时,我发现当我实际上不更改列表中的任何项目时,通常也会调用propertychanged。 我的意思是一个组合充满了元素,并且选择了一个项目:使用键盘触发组合触发属性(并且让另一个组合更新,这是一个被认可的行为),但元素本身是相同的。 我在一个与字符串列表绑定的组合框中看到了这种行为(所以我认为Equals / GetHashCode实现没有错误)并且这种行为每次都会发生,除了第一次。

我用这个修复了代码:

    private string category;
    public string Category
    {
        get { return this.category; }
        set
        {
            bool actuallyChanged = !String.Equals(this.category, value);
            this.category = value;
            this.OnPropertyChanged("Category");

            if (!actuallyChanged)
            {
                string format = String.Format("Category '{0}' isn't changed actually", value);
                Trace.WriteLine(format);
            }
            else this.UpdateTicketTypes():
        }
    }

但是我当然不喜欢这个为设置者添加逻辑的代码。

有关如何避免此行为的任何建议? 我希望能够清楚明白,如果有人不清楚,我愿意更好地解释我的问题。

2 个答案:

答案 0 :(得分:1)

您的模型检查属性设置器中使用的值是否实际上与当前值不同是不合理的。但是,更“标准”的实现如下所示:

private string category;
public string Category
{
    get { return this.category; }
    set
    {
        // check this is a new value
        if(Object.Equals(this.category, value))
            return;

        // set the value
        this.category = value;
        // raise change notification
        this.OnPropertyChanged("Category");
        // compute related changes
        this.UpdateTicketTypes():
    }
}

答案 1 :(得分:0)

只是猜测但你能实现SelectedValue绑定而不是SelectedItem吗? SelectedValue(对于int,string,bool等值类型)不会在键盘或鼠标焦点上刷新,甚至当ItemsSource(使用CollectionView)发生更改时,源(或模型)中的更改通知也不会触发,因为值类型不会更改通过引用。