通知 ViewModel 上的所有属性均已更改

发布于 2024-11-08 21:00:19 字数 2056 浏览 0 评论 0原文

我正在使用 MVVM Light Toolkit V3 SP1 开发 Silverlight 应用程序。

我的申请完全是法语/英语。所有 UI 元素(按钮、标签等)和所有数据(模型)。我需要动态语言切换,这已经完全实现并且可以与来自资源文件的任何内容一起使用。我正在努力解决的是 ViewModels。

模型具有特定于语言的属性(DescriptionEn、DescriptionFr)和一个附加属性调用 LocalizedDescription,它使用当前区域性来返回调用特定于语言的属性。

当语言更改(通过单击按钮)时,我会引发并广播(通过 Messenger)属性更改事件。

在我的每个 ViewModel 中,我注册以接收语言交换的属性更改消息。

我想通知 ViewModel 的所有属性某些内容已发生更改。

来自: http://msdn.microsoft.com/en -us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx

PropertyChanged 事件可以通过使用 null 或 String.Empty 作为 PropertyChangedEventArgs 中的属性名称来指示对象上的所有属性已更改。

但是,由于工具包使用 RaisePropertyChanged(...) 抽象了更改事件的引发,因此我无法让它工作。我还检查了 takeit 的来源,发现 RaisePropertyChanged 调用了VerifyPropertyName(..),这又返回一个错误,即该属性不属于 ViewModel。我还注意到,VerifyPropertyName 方法归因于 Conditional("DEBUG"),但即使我选择 Release 配置,仍然会引发 ArgumentException("Property not found")。

除了为 ViewModel 的每个属性手动调用 RaisePropertyChanged 之外,有谁知道使用工具包使其正常工作的方法吗?

后续:

根据 Simon 的评论,我尝试创建自己的类来扩展 ViewModelBase。我查看了 CodePlex 上的源代码,并决定创建一个名为 RaiseAllPropertyChanged() 的方法。它只是 RaisePropertyChanged(string propertyName) 的副本,但没有参数,也没有调用VerifyPropertyName(...)。我无法让它工作。这是我所拥有的。

public class ViewModelBaseExtended : ViewModelBase
{
    protected void RaiseAllPropertyChanged()
    {
        var handler = this.PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(String.Empty));
        }
    }
}

但我收到编译器错误:事件 'GalaSoft.MvvmLight.ViewModelBase.PropertyChanged' 只能出现在 += 或 -= 的左侧。这是 ViewModelBase 中使用的代码的副本。

有人可以提供一些关于如何使其发挥作用的建议吗?

解决方案:

我将 ViewModelBase 中的所有代码复制到一个新类中。然后,我添加了上面提到的方法 RaisePropertyChanged(),该方法使用 String.Empty 实例化 PropertyChangedEventArgs 类。现在这是我的 ViewModel 的新子类。

再次感谢西蒙的带路!

I am working on a Silverlight application using V3 SP1 of MVVM Light Toolkit.

My application is fully French/English. All UI elements (buttons, labels, etc.) and all the data (models). I need dynamic language switching and this is fully implemented and works with anything coming from a resource file. What I am struggling with is the ViewModels.

The Models have language specific prperties (DescriptionEn, DescriptionFr) and an additional property call LocalizedDescription which uses the current culture to return call the language specific property.

When the language changes (via a button click) I raise and broadcast (via the Messenger) a property changed event.

In each of my ViewModels, I register to receive the property changed message for the language swap.

I want to notify all the properties of the ViewModel that something has changed.

From: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx

The PropertyChanged event can indicate all properties on the object have changed by using either null or String.Empty as the property name in the PropertyChangedEventArgs.

However, since the toolkit abstracts the raising of the changed event with RaisePropertyChanged(...) I cannot get this to work. I have also examined the source of the tookit and discovered that RaisePropertyChanged calls VerifyPropertyName(..) which in turn returns an error is the property does not belong to the ViewModel. I also noticed that the VerifyPropertyName method is attributed with Conditional("DEBUG"), but even if I choose the Release configuration, the ArgumentException("Property not found") is still raised.

Does anyone know of a way to get this to work using the toolkit aside from manually calling RaisePropertyChanged for every property of the ViewModel?

Follow-up:

Based on the comment from Simon, I attempted to create my own class that extends ViewModelBase. I looked at the source on CodePlex and decided to create a single method called RaiseAllPropertyChanged(). It would simply be a copy of the RaisePropertyChanged(string propertyName) but without the parameter and without the call to VerifyPropertyName(...). I cannot get it to work. Here is what I have.

public class ViewModelBaseExtended : ViewModelBase
{
    protected void RaiseAllPropertyChanged()
    {
        var handler = this.PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(String.Empty));
        }
    }
}

But I get a compiler error: The event 'GalaSoft.MvvmLight.ViewModelBase.PropertyChanged' can only appear on the left hand side of += or -=. This is a copy of the code that is used in the ViewModelBase.

Can someone offer some advice as to how to get this to work?

Solution:

I copied all the code from ViewModelBase into a new class. I then added the method RaisePropertyChanged() mentioned above which instantiates the PropertyChangedEventArgs class with String.Empty. This is now the new subclass for my ViewModels.

Thanks again to Simon for leading the way!

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

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

发布评论

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

评论(3

随心而道 2024-11-15 21:00:19

如果您在 2016 年阅读本文,您可以使用 ObservableObject 并通过执行以下操作来通知所有属性已更改:

RaisePropertyChanged(string.Empty);

In case you're reading this in 2016, you can use ObservableObject and notify that all of the properties have changed by doing:

RaisePropertyChanged(string.Empty);
慕巷 2024-11-15 21:00:19

不幸的是,这对于 MVVMLight 的当前代码库来说是不可能的。

短期内您有 2 个选择:

  1. 使用您自己的自定义基类。我所说的自定义基类是指“不要从 MVVMLight 类继承”。

  2. 在Release模式下下载并编译MVVMLight。这将强制排除“VerifyPropertyName”方法。当然,这样你就得不到属性名称检查的值。

我确信 Laurent Bugnion 很快就会解决这个问题。

Unfortunately this is not possible with the current code-base of MVVMLight

In the short term your have 2 options:

  1. User your own custom base class. And by custom base class I mean "Do not inherit from the MVVMLight class".

  2. Download and compile MVVMLight in Release mode. This will force the "VerifyPropertyName" method to be excluded. Of course then you don't get the value of property name checks.

I am sure Laurent Bugnion will have this fixed soon.

碍人泪离人颜 2024-11-15 21:00:19

解决此问题的一个更简单的解决方案是在类中重写 RaisePropertyChanged(string propertyName) :

protected override void RaisePropertyChanged(string propertyName)
    {
        if (propertyName != null)
        {
            base.RaisePropertyChanged(propertyName);
        }
        else
        {
            var handler = PropertyChangedHandler;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(null));
            }

        }
    }

A lighter solution to this problem would have been to override RaisePropertyChanged(string propertyName) in your class :

protected override void RaisePropertyChanged(string propertyName)
    {
        if (propertyName != null)
        {
            base.RaisePropertyChanged(propertyName);
        }
        else
        {
            var handler = PropertyChangedHandler;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(null));
            }

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