【问题标题】:INotifyPropertyChanged 'Double' bindingINotifyPropertyChanged '双重'绑定
【发布时间】:2011-07-24 23:01:06
【问题描述】:

我正在尝试将一些 XAML 代码绑定到我的 ViewModel 中的属性。

<Grid Visibility="{Binding HasMovies, Converter={StaticResources VisibilityConverter}}">
...
</Grid>

我的 ViewModel 是这样设置的:

private bool _hasMovies;
        public bool HasMovies
        {
            get { return _hasMovies; }
            set { _hasMovies = value; RaisePropertyChanged("HasMovies"); }
        }

在 ViewModel 的构造函数中,我设置了 HasMovies 链接:

MovieListViewModel()
{
   HasMovies = CP.Connection.HasMovies;
}

在CP中:

public bool HasMovies
        {
            get { return MovieList != null && MovieList.Count > 0; }
        }

private ObservableCollection<Movie> _movies;
        public ObservableCollection<Movie> MovieList
        {
            get { return _movies; }
            set
            {
                _movies = value;
                RaisePropertyChanged("MovieList");
                RaisePropertyChanged("HasMovies");
                _movies.CollectionChanged += MovieListChanged;
            }
        }

        private void MovieListChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            RaisePropertyChanged("HasMovies");
        }

我做错了什么?我应该如何更改此绑定以使其反映CP.Connection.HasMovies 的当前状态?

【问题讨论】:

    标签: c# wpf xaml windows-phone-7 mvvm-light


    【解决方案1】:

    要么直接在 ViewModel 中公开对象并通过它直接绑定(这样该值不只是复制一次,这就是现在发生的情况),要么订阅 PropertyChanged 事件并在每次它时将 HasMovies 设置为新值源对象的变化。

    例如

    CP.Connection.PropertyChanged += (s,e) =>
        {
            if (e.PropertyName = "HasMovies") this.HasMovies = CP.Connection.HasMovies;
        };
    

    【讨论】:

    • 这看起来像我正在寻找的东西,但是直接绑定到对象的第一个想法听起来是个好主意,因为我在很多地方都使用了这个属性。您有如何在 XAML 中进行此绑定的示例吗?
    • 这是一个非常愚蠢的解决方案,但仍然无法正常工作,因为在从集合中添加或删除项目时调用 PropertyChanged 事件!
    • @willmel:您可以只使用代码后面的路径进行绑定,如果您将连接对象公开为名为@9​​87654323@ 的属性,则绑定将只是{Binding Connection.HasMovies, Converter=...}。跨度>
    • @H.B. :所以我尝试这样做并创建一个新属性,但它似乎不起作用..它不会随属性更新。有什么我做错了吗? {Binding Context.HasMovies, Converter={StaticResource OnOffConverter}}
    • @willmel:我不知道你的完整代码;值是否一开始就被绑定并且不更新或绑定失败(请参阅 VS 中的输出窗口)?
    【解决方案2】:

    首先,当您更改集合的内容(即添加/删除项目)。

    这意味着您的 MovieList 属性的所有设置器代码都是没有意义的。

    其次,这是非常愚蠢的代码。一个更好的解决方案是使用NotifyPropertyWeaver。然后您的代码在视图模型中将如下所示:

    [DependsOn("MovieList")]
    public bool HasMovies
    {
        get { return MovieList != null && MovieList.Count > 0; }
    }
    
    public ObservableCollection<Movie> MovieList
    {
        get;
        private set;
    }
    

    或者,当您第一次初始化 MovieList 属性时,您必须为 CollectionChanged 事件添加一个侦听器(没有理由拥有支持属性,真的没有理由!),然后调用 RaisePropertyChanged("HasMovies")事件处理程序。

    例子:

    public class CP : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        public CP()
        {
            MovieList = new ObservableCollection<Movie>();
            MovieList.CollectionChanged += MovieListChanged;
        }
    
        public bool HasMovies
        {
            get { return MovieList != null && MovieList.Count > 0; }
        }
    
        public ObservableCollection<Movie> MovieList
        {
            get;
            private set;
        }
    
        private void MovieListChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            RaisePropertyChanged("HasMovies");
        }
    
        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

    【讨论】:

    • 你看过集合的setter吗?有一个处理程序连接到 CollectionChanged 事件,它应该可以工作......
    • 考虑到他正在使用支持字段,我发现上述 setter 不太可能被调用。此外, RaisePropertyChanged("HasMovies");在 setter 中永远不会做任何有用的事情。无论哪种方式,使用 NotifyProperWeaver 都是最漂亮的方式。
    • @克劳斯。 [DependsOn("MovieList")] 实际上是多余的,因为 NPW 将派生该依赖项
    猜你喜欢
    • 2011-04-12
    • 1970-01-01
    • 2018-08-31
    • 1970-01-01
    • 2016-01-30
    • 1970-01-01
    • 2013-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多