【问题标题】:ObservableCollection don't modify viewObservableCollection 不修改视图
【发布时间】:2013-08-23 10:03:56
【问题描述】:

我有奇怪的 WPF ObservableCollection 行为。由于不明确的原因,当集合被修改并且我的类的某些属性中的 getter-method 中存在另一个条件时,它不会修改 View。虽然调用了 CollectionChanged 事件! 在 getter 方法集合中没有条件效果很好。

在这里解释我在我的工作项目中所做的事情过于复杂和冗长。因此,我做了小简化项目并模拟相同的行为。这个项目比千字更好地向您展示问题。

要查看问题 - 启动项目,看看它是如何工作的。这真的很简单,2 个单选按钮,datagrid,仅此而已。然后转到 MainWindowViewModel、GridItems-property,取消注释代码并再次启动项目。看到不同。修改集合时,不会调用 GridItems-property 的 get 方法(我用调试器检查它)。未调用的方法如何影响某些东西???我对此没有任何想法。请帮忙。

项目链接: http://www.megafileupload.com/en/file/443850/ObservableCollection-zip.html

class MainWindowViewModel : ViewModelBase
    {
        private ObservableCollection<GridItem>  _totalStorage;

        private ObservableCollection<GridItem> _gridItems;
        public ObservableCollection<GridItem> GridItems
        {
            get
            {
                //if (_gridItems.Count == 0)
                //{
                //    return _totalStorage;
                //}
                return _gridItems;
            }
            set
            {
                _gridItems = value;
                RaisePropertyChanged("GridItems");
            }
        }

        public MainWindowViewModel()
        {
            _totalStorage = new ObservableCollection<GridItem>();
            _gridItems = new ObservableCollection<GridItem>();

            GridItemsInit();
            _gridItems.CollectionChanged += CollectionChanged;
        }

        /// <summary>
        /// Collection change event handler
        /// </summary>
        /// <param name="o"></param>
        /// <param name="e"></param>
        private void CollectionChanged(object o, NotifyCollectionChangedEventArgs e)
        {

        }


        private void GridItemsInit()
        {
            _totalStorage.Add(new GridItem
            {
                Name = "Igor",
                LastName = "Balachtin",
                FilerField = FileStatusEnum.All
            });

            _totalStorage.Add(new GridItem
            {
                Name = "Misha",
                LastName = "Ivanov",
                FilerField = FileStatusEnum.All
            });

            _totalStorage.Add(new GridItem
            {
                Name = "Ahmed",
                LastName = "Magamed",
                FilerField = FileStatusEnum.All
            });

            _totalStorage.Add(new GridItem
            {
                Name = "abrek",
                LastName = "cheburek",
                FilerField = FileStatusEnum.All
            });

            _totalStorage.Add(new GridItem
            {
                Name = "Irka",
                LastName = "Dirka",
                FilerField = FileStatusEnum.All
            });
        }

        private void RefreshGridSource(string statusParam)
        {
            _gridItems.Clear();

            //Если нажали на баттон new
            if (statusParam.Equals(FileStatusEnum.All.ToString()))
            {
                foreach (var item in _totalStorage)
                {
                    _gridItems.Add(item);
                }
            }

            //Если нажали на archived
            else if (statusParam.Equals(FileStatusEnum.Filtered.ToString()))
            {
                foreach (var item in _totalStorage.Where(g => g.FilerField == FileStatusEnum.Filtered))
                {
                    _gridItems.Add(item);
                }    
            }
        }


        private RelayCommand<object> _radioCommand;

        public RelayCommand<object> RadioCommand
        {
            get { return _radioCommand ?? (_radioCommand = new RelayCommand<object>(HandlerFileRadio)); }
        }

        private void HandlerFileRadio(object obj)
        {
            if (obj == null)
                return;

            var statusParam = obj.ToString();

            RefreshGridSource(statusParam);
        }

    }


Look at this sample.
//if (_gridItems.Count == 0)
//{
//    return _totalStorage;
//}

Model:

 public enum FileStatusEnum
    {
        All = 0,
        Filtered
    }

    public class GridItem
    {
        public String Name { get; set; }
        public String LastName { get; set; }

        public FileStatusEnum FilerField
        {
            get; set;
        }
    }

Xaml:

<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="3*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="0">
            <RadioButton Margin="5" IsChecked="True" Command="{Binding RadioCommand}"
                                     CommandParameter="All">All</RadioButton>
            <RadioButton Margin="5" Command="{Binding RadioCommand}"
                                     CommandParameter="Filtered">Filtered</RadioButton>
        </StackPanel>
        <DataGrid Grid.Column="1" ItemsSource="{Binding GridItems}" CanUserAddRows="False" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}" IsReadOnly="True" />
                <DataGridTextColumn Header="LastName" Binding="{Binding LastName}" IsReadOnly="True" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

在这里发布所有代码而不是链接真的更好吗? :/

【问题讨论】:

  • 你能把 ViewModel 代码贴在这里吗?
  • @monstr,大多数人没有资源来下载 zip 文件并执行规定的一系列步骤。这意味着您的问题属于“过于宽泛”的类别,因此我会为您标记它。请编辑您的问题,将重点放在视图模型中行为不端的特定片段上。格式化的源代码将有助于您快速解决此问题。
  • 您可能应该只拥有整个集合并绑定到其顶部的 CollectionView 进行过滤。

标签: wpf observablecollection


【解决方案1】:

一旦您更改记录,之后您的财产没有通知。所以请在更改集合后通知。

集合更改后在 RefreshGridSource 方法中添加以下行。

RaisePropertyChanged("GridItems");

【讨论】:

  • ObservableCollection 会自动通知它是否发生变化。无论如何它都不起作用......
  • 所以如果我没有过滤记录,它就不能正常工作。 Thx,但它没有解决问题)
  • 已检查。我明白你的意思。但正如我告诉你的那样,在通常情况下,你的建议是没有解决方案的,因为我的项目中没有过滤记录。而且您的变体将不起作用。您尝试使用特殊情况解决问题,但在常见情况下我需要一个解决方案。无论如何,我很感激你的回答
  • 嗯,我看到了 RaisePropertyChanged("GridItems"); get-method GridItems 现在调用,如果我没有过滤器记录,则 getter 中的条件有效,并且我将 _totalStorage 作为我的网格的源。 IE。所有列表和视觉网格都没有变化。至少在逻辑上是这样。那么为什么没有调用 RaisePropertyChanged("GridItems") 的 ObservableCollection 不通知 WPF 关于集合已更改?满了又空了。为什么只有当我在吸气剂中有这种情况时才会发生这种情况??
【解决方案2】:

您的GridItems 属性可以根据条件返回_totalStorage 或_gridItems; _totalStorage 和 _gridSettings 是 ObservableCollection 的两个不同实例。最初,当_gridItems 没有项目时,您的GridItems 属性将_totalStorage 返回给WPF,并且WPF 会在此实例上侦听任何CollectionChanged 事件。

在您的 RefreshGridSource 方法中,您正在更新 WPF 不知道的 _gridItems(与 _totalStorage 不同的实例)。

但是,当您从 RefreshGridSource 方法更改 GridItems 属性的 rasie 属性时,WPF 将重新读取属性 GridItems - 这一次,WPF 获取 _gridItems 集合,它可以按预期工作。

希望,我已经解释得很好了。

【讨论】:

  • 我填得太笨了……让我们一步一步来吧。为什么当我调用 _gridItems.Clear(); _gridItems 不告诉 WPF 更新网格内容?因为 _gridItems 是 ObservableCollection 并且必须通知 WPF 关于它的任何更改。
  • 正如我在回答中提到的那样,WPF 还不知道您的 _gridItems,因为 WPF 在读取 GridItems 属性时已经获得了 _totalStorage。尝试GridItems.Clear() 它将清除网格,因为GridItems 将在_gridItems.Count = 0 时指向_totalStorage。
  • 我明白了。 WPF 存储第一个吸引人的 ObservableCollection。并将 GridItems 与它相关联。我很惊讶。太好了!
猜你喜欢
  • 2017-02-23
  • 2021-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-15
  • 1970-01-01
  • 2011-10-28
相关资源
最近更新 更多