INotifyPropertyChanged“双”绑定

发布于 2024-11-26 05:00:30 字数 1353 浏览 0 评论 0原文

我正在尝试将一些 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 的当前状态?

I'm trying to bind some XAML code to a property in my ViewModel.

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

My ViewModel is setup like this:

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

In the constructor of the ViewModel, I set the HasMovies link:

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

in 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");
        }

What am I doing wrong? How should I change this binding so that it reflects the current state of CP.Connection.HasMovies?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你又不是我 2024-12-03 05:00:30

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

例如

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

Either directly expose the object in the ViewModel and bind directly through that (so that the value is not just copied once which is what happens now) or subscribe to the PropertyChanged event and set HasMovies to the new value every time it changes in your source object.

e.g.

CP.Connection.PropertyChanged += (s,e) =>
    {
        if (e.PropertyName = "HasMovies") this.HasMovies = CP.Connection.HasMovies;
    };
千仐 2024-12-03 05:00:30

首先,当您更改集合的内容(即添加/删除项目)时,不会调用集合类型(例如 MovieList 属性)的 setter 。

这意味着 MovieList 属性的所有 setter 代码都是毫无意义的。

其次,这是非常愚蠢的代码。更好的解决方案是使用 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));
        }
    }
}

First of all, the setter for a collection type, such as your MovieList property, is not called when you change the content of the collection (ie. Add/Remove items).

This means all your setter code for the MovieList property is pointless.

Secondly, it's very silly code. A much better solution, is to use NotifyPropertyWeaver. Then your code would look like this, in the viewmodel:

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

public ObservableCollection<Movie> MovieList
{
    get;
    private set;
}

Alternatively you would have to add a listener for the CollectionChanged event when you initialize the MovieList property the first time (no reason to have a backing property, really really no reason!), and then call RaisePropertyChanged("HasMovies") in the event handler.

Example:

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));
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文