首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何正确地从包含的对象触发CollectionChanged通知?

如何正确地从包含的对象触发CollectionChanged通知?
EN

Stack Overflow用户
提问于 2011-03-14 15:22:43
回答 3查看 1.5K关注 0票数 1

以下是对本质上是一个简单问题的冗长的解释。我使用的是Telerilk RadDropDownButton,它显示带有复选框的列表项。

代码语言:javascript
复制
                    <Controls:RadDropDownButton AutoOpenDelay="0:0:0.0" x:Name="Urgency" VerticalAlignment="Center" Width="150" Content="{Binding Path=ItemsSource, ElementName=UrgencyList, Mode=TwoWay, Converter={StaticResource ButtonTextConverter}}" HorizontalContentAlignment="Left">
                    <Controls:RadDropDownButton.DropDownContent>
                        <ListBox x:Name="UrgencyList">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <CheckBox Content="{Binding Name}" ClickMode="Press" IsChecked="{Binding IsChecked, Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
                                    </StackPanel>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </Controls:RadDropDownButton.DropDownContent>
                </Controls:RadDropDownButton>

如您所见,我将Content属性绑定到转换器。我想要的是,如果没有被选中,内容要读“全部”,如果检查了某一项,则显示选中(选中)项的#列表。

代码语言:javascript
复制
    public class ButtonTextConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Debug.WriteLine("I'm Binding");
        int numChecked = 0;
        if (value != null)
            numChecked = ((ObservableCollection<UrgencyItem>) value).Count(urgencyItem => urgencyItem.IsChecked);
        return numChecked > 0 ? string.Format("{0} Items Selected", numChecked) : "All";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

根据需要,我绑定到的类实现了INotifyPropertyChanged。部分清单如下:

代码语言:javascript
复制
    public class UrgencyItem : INotifyPropertyChanged
{
    private int _id;
    private bool _isChecked;
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            NotifyPropertyChanged("Name");
        }
    }

我将ListBox绑定到代码隐藏中的数据,如下所示:

代码语言:javascript
复制
        private void SearchParamsVertical_Loaded(object sender, RoutedEventArgs e)
    {
        urgencyList = new ObservableCollection<UrgencyItem>
                          {
                              new UrgencyItem {ID = 1, IsChecked = false, Name = "Non Emergent"},
                              new UrgencyItem {ID = 2, IsChecked = false, Name = "Emergent"},
                              new UrgencyItem {ID = 3, IsChecked = false, Name = "Stat Emergent"},
                              new UrgencyItem {ID = 4, IsChecked = false, Name = "Stroke Protocol"}
                          };

        urgencyList.CollectionChanged += urgencyList_CollectionChanged;
        UrgencyList.ItemsSource = urgencyList;
    }

,所以问题是.

选中复选框时,应更新内容的值。事实并非如此。

原因不是因为,尽管通知触发了IsChecked被更改,但通知基本上是无处可寻的。UrgencyItem对象不知道它是ObservableCollection的一部分。关于ObservableCollection的问题是,只有当项被添加/移除到集合/从集合中删除时,它才会向它的绑定发送通知。换句话说,更改集合中项的属性不会触发CollectionChanged事件,因为没有添加/删除任何对象。

我需要做的是在修改集合的属性时触发collectionChanged事件。我以前知道怎么做,但是离Silverlight太远了,我忘了怎么做。

有没有人?

EN

回答 3

Stack Overflow用户

发布于 2011-03-14 16:29:39

简而言之,我认为您的诊断是正确的:如果ObservableCollection中的一个对象发生了更改,即使该对象实现了INotifyPropertyChanged,通常也不会得到一个INotifyPropertyChanged通知。据我所知,没有一种简单的方法可以通过内置Silverlight类获得您想要的行为。

我知道有三种可能的方法来解决这个问题:

(1)一个选项是为urgencyList创建自己的集合,继承自ObservableCollection,实现此行为,即订阅添加到集合中的每个对象的INPC通知,并在发生这种情况时触发CollectionChanged事件。

(2)第二种选择是使用类似于ReactiveUI框架的东西,它有自己的ReactiveCollection来实现这种行为。

(3)第三种选择是通过类似于urgencyList的东西创建Obtics还是连续Linq。它们返回的集合自动实现此行为。

票数 1
EN

Stack Overflow用户

发布于 2011-08-25 14:31:34

这就是我要用的东西。肯恩在nr (1)中所建议的是:

代码语言:javascript
复制
public class Person: INotifyPropertyChanged
{
private string _name;
public string Name
    {
        get { return _name; }
        set { 
            _name = value;
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Name"));
        }
    }
public event PropertyChangedEventHandler PropertyChanged;
}

我将这些对象放在PLObservableNotifyList<Person>中,并将其设置为ItemsControl上的ItemsSource。一旦我更新值(使用setter),绑定就会自动更新。

代码语言:javascript
复制
public class PLObservableNotifyList<T> :
            ObservableCollection<T> where T : INotifyPropertyChanged
{
    public ItemPropertyChangedEventHandler ItemPropertyChanged;
    public EventHandler CollectionCleared;

    protected override void OnCollectionChanged(
                                NotifyCollectionChangedEventArgs args)
    {
        base.OnCollectionChanged(args);

        if (args.NewItems != null)
            foreach (INotifyPropertyChanged item in args.NewItems)
                item.PropertyChanged += OnItemPropertyChanged;

        if (args.OldItems != null)
            foreach (INotifyPropertyChanged item in args.OldItems)
                item.PropertyChanged -= OnItemPropertyChanged;
    }

    void OnItemPropertyChanged(object sender,
                               PropertyChangedEventArgs args)
    {
        if (ItemPropertyChanged != null)
            ItemPropertyChanged(this,
                new PLItemPropertyChangedEventArgs(sender,
                                                 args.PropertyName));
    }

    protected override void ClearItems()
    {
        foreach (INotifyPropertyChanged item in Items)
            item.PropertyChanged -= OnItemPropertyChanged;

        if (CollectionCleared != null)
            CollectionCleared(this, EventArgs.Empty);

        base.ClearItems();
    }
}
票数 0
EN

Stack Overflow用户

发布于 2019-11-21 12:02:52

你需要我的ObservableComputations库。使用该库,您可以编写以下代码:

代码语言:javascript
复制
            private Computing<string> _checkedUrgencyItemsText;
            public Computing<string> CheckedUrgencyItemsText = _selectedUrgencyItemsText ?? 
                 Expr.Is(() => UrgencyItems.Filtering(urgencyItem => urgencyItem.IsChecked)
                   .Using(checkedUrgencyItems => 
                        checkedUrgencyItems.Count > 0 
                        ?  string.Format("{0} Items Selected", checkedUrgencyItems.Count) 
                        : "All")).Computing();
代码语言:javascript
复制
                    <Controls:RadDropDownButton Content="{Binding Path=CheckedUrgencyItemsText.Value}" AutoOpenDelay="0:0:0.0" x:Name="Urgency" VerticalAlignment="Center" Width="150"  HorizontalContentAlignment="Left">
                    <Controls:RadDropDownButton.DropDownContent>
                        <ListBox x:Name="UrgencyList">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <CheckBox Content="{Binding Name}" ClickMode="Press" IsChecked="{Binding IsChecked, Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
                                    </StackPanel>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </Controls:RadDropDownButton.DropDownContent>
                </Controls:RadDropDownButton>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5300635

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档