【问题标题】:WPF - How to refresh view with nested ObservableCollectionWPF - 如何使用嵌套的 ObservableCollection 刷新视图
【发布时间】:2014-06-06 10:02:47
【问题描述】:

我有一个DataGrid 绑定到SelectedQueryView.SelectedColumns,其中SelectedQueryView 是:

public QueryViewItem SelectedQueryView { get; set; }

而 QueryViewItem 是:

public class QueryViewItem : ViewModelBase
{
    private string _viewIcon;
    private string _viewName;
    private string _tableName;

    public string ViewIcon
    {
        [DebuggerStepThrough]
        get { return _viewIcon; }
        [DebuggerStepThrough]
        set
        {
            if (value != _viewIcon)
            {
                _viewIcon = value;
                OnPropertyChanged("ViewIcon");
            }
        }
    }
    public string ViewName
    {
        [DebuggerStepThrough]
        get { return _viewName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _viewName)
            {
                _viewName = value;
                OnPropertyChanged("ViewName");
            }
        }
    }

    public string TableName
    {
        [DebuggerStepThrough]
        get { return _tableName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _tableName)
            {
                _tableName = value;
                OnPropertyChanged("TableName");
            }
        }
    }

    public ObservableCollection<TableColumn> SelectedColumns { get; set; }
}

而且,TableColumn 是:

public class TableColumn : ViewModelBase
{
    private string _tableSource;
    public string TableSource
    {
        [DebuggerStepThrough]
        get { return _tableSource; }
        [DebuggerStepThrough]
        set
        {
            if (value != _tableSource)
            {
                _tableSource = value;
                OnPropertyChanged("TableSource");
            }
        }
    }
    private string _colName;
    public string ColName
    {
        [DebuggerStepThrough]
        get { return _colName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _colName)
            {
                _colName = value;
                OnPropertyChanged("ColName");
            }
        }
    }
    private string _customName;
    public string CustomName
    {
        [DebuggerStepThrough]
        get { return _customName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _customName)
            {
                _customName = value;
                OnPropertyChanged("CustomName");
            }
        }
    }

    public override string ToString()
    {
        string sRet;

        if(ColName.Equals("*"))
            sRet = TableSource + "." + ColName;
        else
            sRet = TableSource + "." + ColName + " AS " + CustomName;
        return sRet;
    }
}

最后,ViewModelBase 是:

公共类 ViewModelBase:INotifyPropertyChanged { 公共事件 PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(sender, e);
    }

    protected virtual void OnPropertyChanged(string PropertyName)
    {
        OnPropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
    }
}

问题是,当我向SelectedQueryView.SelectedColumns 添加字段时,关联的DataGrid 不会更新,即使SelectedColumnsObservableCollection

Xaml

<DataGrid Grid.Row="0" Grid.Column="2" ItemsSource="{Binding Path=SelectedQueryView.SelectedColumns}" BorderBrush="Black" Margin="5" SelectedItem="{Binding Path=SelectedDestColumn}" AutoGenerateColumns="False" GridLinesVisibility="None" CanUserAddRows="False" RowEditEnding="DataGrid_RowEditEnding" RowHeaderWidth="0" Background="White">
<DataGrid.Columns>
    <DataGridTextColumn Header="Name" Width="*" Binding="{Binding Path=ColName}" IsReadOnly="True"/>
     <DataGridTextColumn Header="Custom Name" Width="*" Binding="{Binding Path=CustomName}" />
 </DataGrid.Columns>
</DataGrid>

谁能解释一下为什么以及如何解决这个问题?

【问题讨论】:

  • QueryViewItem 类需要实现属性更改通知。你需要看一下如何开始的sn-p吗?
  • 好的,谢谢;会很有用的。
  • 看看这个答案是否能帮助你“明白”
  • @Riccardo 如果它是一个 observablecollection 那么向它添加对象应该在 UI 上自动更新..在这种情况下你不需要调用 PropertyChanged 来在视图上添加项目..你能分享一下你的情况吗在集合中添加元素并将您的集合绑定到视图
  • @nit 这是我在集合中添加元素的方法: SelectedQueryView.SelectedColumns.Add(column);其中 column 是 TableColumn 对象

标签: wpf xaml datagrid observablecollection


【解决方案1】:

您的类需要继承自 INotifyPropertyChanged。首先,将您的 TableColumn 类更改为此...

   public class TableColumn : INotifyPropertyChanged
    {
        private string _tableSource;
        public string TableSource
        {
            [DebuggerStepThrough]
            get { return _tableSource; }
            [DebuggerStepThrough]
            set
            {
                if (value != _tableSource)
                {
                    _tableSource = value;
                    OnPropertyChanged("TableSource");
                }
            }
        }
        private string _colName;
        public string ColName
        {
            [DebuggerStepThrough]
            get { return _colName; }
            [DebuggerStepThrough]
            set
            {
                if (value != _colName)
                {
                    _colName = value;
                    OnPropertyChanged("ColName");
                }
            }
        }
        private string _customName;
        public string CustomName
        {
            [DebuggerStepThrough]
            get { return _customName; }
            [DebuggerStepThrough]
            set
            {
                if (value != _customName)
                {
                    _customName = value;
                    OnPropertyChanged("CustomName");
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string name)
        {
            var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }

这将导致您的类向 WPF 绑定引擎发出通知,以便将更改应用于用户界面。出于这个原因,强烈建议在所有视图模型类上使用通知模式。

此代码在 VS2013 中编译干净。必须将相同的模式应用于您的 QueryViewItem 类,以便绑定引擎可以找到该类(但不适用于 SelectedColumns 成员,因为它已经实现了 INPC)。

它看起来像这样......

public class QueryViewItem : INotifyPropertyChanged
{
    public ObservableCollection<TableColumn> SelectedColumns { get; set; }
    private string _viewIcon;
    public string ViewIcon
    {
        [DebuggerStepThrough]
        get { return _viewIcon; }
        [DebuggerStepThrough]
        set
        {
            if (value != _viewIcon)
            {
                _viewIcon = value;
                OnPropertyChanged("ViewIcon");
            }
        }
    }
    private string _viewName;
    public string ViewName
    {
        [DebuggerStepThrough]
        get { return _viewName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _viewName)
            {
                _viewName = value;
                OnPropertyChanged("ViewName");
            }
        }
    }
    private string _tableName;
    public string TableName
    {
        [DebuggerStepThrough]
        get { return _tableName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _tableName)
            {
                _tableName = value;
                OnPropertyChanged("TableName");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
    {
        var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

【讨论】:

  • @Riccardo,请看修改
  • 是的,我听从了你的建议(有修正),但即使我在每个 setter 中触发 PropChanged,DataGrid 也不会显示字段......太奇怪了。
【解决方案2】:

让我看看我是否理解这个问题的症结所在。从您的编辑来看,我相信最初,您的问题是您没有实现INotifyPropertyChanged 接口,因此感谢@GayotFow 指出这一点。但是,既然您已经添加了 ViewModelBase 类,现在您的问题似乎是当您将元素添加到您的 SelectedQueryView.SelectedColumns 集合时您的 UI 没有更新。

如果这是正确的,那么我认为您的问题仍然归结为缺少更新通知。根据您的一位 cmets,您将元素添加到您的收藏中,如下所示:

SelectedQueryView.SelectedColumns.Add(column); 

我相信是你的问题。尽管每个人都在说ObservableCollection 自动更新 UI,但我认为如果您在此处添加对 OnPropertyChanged 方法的调用,那么您会在 UI 中看到更新。试试这个:

SelectedQueryView.SelectedColumns.Add(column); 
OnPropertyChanged("SelectedColumns");

【讨论】:

  • 一如既往地感谢您的赞誉和出色的回答。但是对于这个,你需要解释为什么 ObservableCollection 的内置通知没有被调用。否则,它会向人们暗示 ObservableCollection 在某种程度上是不可靠的或损坏的。我的 DataGrid 食谱书有一个关于这个确切问题的工作示例(即嵌套的 observables),其中不需要 OnPropertyChanged。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
相关资源
最近更新 更多