【问题标题】:Binding ObservableCollection contained in ViewModel to ListView将 ViewModel 中包含的 ObservableCollection 绑定到 ListView
【发布时间】:2012-11-15 09:43:27
【问题描述】:

我已经搜索和搜索,但无法获得正确、有用的答案。

我有一个 MainWindow wpf 窗口。它的 DataContext 设置为它的 ViewModel。

我有一个绑定到 ViewModel 中的 ObservableCollection 的 ListView:

        <ListView Grid.Row="1" Grid.Column="0" Margin="2" Name="sources_ListView" Grid.RowSpan="1" ItemsSource="{Binding Path=Sources}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Width="290" Header="Name"
                                    DisplayMemberBinding="{Binding Path=OriginalPath}"/>
                    <GridViewColumn Width="80" Header="Type" 
                                    DisplayMemberBinding="{Binding Path=Type}"/>
                </GridView>
            </ListView.View>
        </ListView>

中继命令:

        public ICommand BrowseFileFolderCommand
        {
            get
            {
                if (_browseFileFolderCommand == null)
                {
                    _browseFileFolderCommand = new RelayCommand(o => 
                               {
                                  _sources.Add(new SourceItem(selectedPath, new DirectoryInfo(selectedPath)));
                               }, null);
                }
                return _browseFileFolderCommand;
            }
        }

现在显然 Lambda 函数的作用在现实世界中不起作用,因为我已将其脱离上下文,但接受它确实将 SourceItem 添加到 ObservableCollection _sources 并且有一个 Public Sources 的事实_sources。我还使 ObservableCollection 采用的类型使用 INotifyChangedProperty。

当我使用按钮内的 RelayCommand 将源添加到 ObservableCollection 时,ListView 不会更新?

感谢您的帮助

编辑源项:

public class SourceItem : ISourceItem, INotifyPropertyChanged
{
    DirectoryInfo _sourceFolder;
    public DirectoryInfo SourceFolder { get { return _sourceFolder; } private set { _sourceFolder = value; } }

    FileInfo _sourceFile;
    public FileInfo SourceFiles { get { return _sourceFile; } private set { _sourceFile = value; } }

    string _originalPath;
    public string OriginalPath { get { return _originalPath; } private set { _originalPath = value; OnPropertyChanged("OriginalPath"); } }

    bool _isFolder;
    public bool IsFolder { get { return _isFolder; } }

    // display friendly property of IsFolder
    public string Type { get { return _isFolder == true ? "Folder" : "File"; } }

    public SourceItem(string originalPath, DirectoryInfo sourceFolder)
    {
        _originalPath = originalPath;
        _sourceFolder = sourceFolder;
        _sourceFile = null;

        _isFolder = true;
    }

    public SourceItem(string originalPath, FileInfo sourceFile)
    {
        _originalPath = originalPath;
        _sourceFile = sourceFile;
        _sourceFolder = null;

        _isFolder = false;
    }



    #region INotifyPropertyChanged Members

    /// <summary>
    /// Raised when a property on this object has a new value.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Raises this object's PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The property that has a new value.</param>
    protected virtual void OnPropertyChanged(string propertyName)
    {
        this.VerifyPropertyName(propertyName);

        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

    #endregion // INotifyPropertyChanged Members

    #region Debugging Aides

    /// <summary>
    /// Warns the developer if this object does not have
    /// a public property with the specified name. This 
    /// method does not exist in a Release build.
    /// </summary>
    [Conditional("DEBUG")]
    [DebuggerStepThrough]
    public void VerifyPropertyName(string propertyName)
    {
        // Verify that the property name matches a real.
        // public, instance property on this object
        if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        {
            string msg = String.Format("Invalid property name: {0}", propertyName);

            if (this.ThrowOnInvalidPropertyName)
                throw new Exception(msg);
            else
                Debug.Fail(msg);
        }
    }

    /// <summary>
    /// Returns whether an exception is thrown, or if a Debug.Fail() is used
    /// when an invalid property name is passed to the VerifyPropertyName method.
    /// The default value is false, but subclasses used by unit tests might 
    /// override this property's getter to return true.
    /// </summary>
    protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

    #endregion
}

【问题讨论】:

  • 1 - 发布您的 Observablecollection 定义。 2 - 您查看 VS 调试输出是否有任何绑定错误?
  • 1.完成,2. 没有出现错误

标签: c# wpf mvvm visual-studio-2012


【解决方案1】:

使用公共版本的属性添加新项目

Sources.Add(new SourceItem(selectedPath, new DirectoryInfo(selectedPath)));

您当前正在将项目添加到属性的私有版本 (_sources),而您的 UI 绑定到属性的公共版本 (Sources),因此您的 UI 不会获得 CollectionChanged通知属性的私有版本提出,所以不知道它需要更新。

另一种方法是简单地手动为您的类引发PropertyChanged 事件,以告知 UI 进行更新。这通常是我想同时向我的收藏中添加大量项目但只更新一次 UI 时所做的。

_sources.Add(new SourceItem(selectedPath, new DirectoryInfo(selectedPath)));
RaisePropertyChanged("Sources");

【讨论】:

  • 但是实例化呢?
  • @No1_Melman 我不确定我是否理解您的要求。实例化呢?通常我的 ObservableCollections 要么在构造函数中创建,要么在属性的 get 方法中创建,如果属性的私有版本是 null
  • RaisePropertyChanged 是从哪里来的?
  • AHHHHHHHH,这行得通,我猜 RaisePropertyChanged 是我的 OnPropertyChanged,它在我的 ViewModelBase 中实现了 INotifyPropertyChanged 并且它有效。天才
  • @No1_Melman ViewModel 中的 PropertyChanged 仅处理您的 ObservableCollection Sources 更改为新的 ObservableCollectionnull 并且 ObservableCollection 类本身处理更改的情况在从集合中添加或删除项目的情况下发出通知。如果SourceItem 上的属性发生更改,SourceItem 上的 PropertyChange 代码将提醒 UI,因此如果它们有可能发生更改并且该更改需要反映在 UI 中,则应保留 INotifyPropertyChange在那堂课上
猜你喜欢
  • 2018-05-10
  • 2012-12-16
  • 2012-05-26
  • 2018-05-21
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
相关资源
最近更新 更多