0

我有一个安装了Fody PropertyChanged包的 C# Windows Phone 8 MVVM 应用程序。我在类声明之前添加了ImplementPropertyChanged指令:

[CompilerGenerated]
[GeneratedCode("Radarc", "4.0")]
[ImplementPropertyChanged]
public partial class MilitaryRobots_VideosViewModel : ViewModelsBase.VMBase, IViewModels.IMilitaryRobots_VideosViewModel, INotifyPropertyChanged

我在将 View 元素绑定到的类中有以下两个属性:

    private Visibility _showDetailsVideo = Visibility.Collapsed;

    public Visibility ShowDetailsVideo 
    { 
        get
        {
            return this._showDetailsVideo;
        }

        set
        {
            this._showDetailsVideo = value;
            this.ShowMainScreen = value == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
        }
    }

    private Visibility _showMainScreen = Visibility.Visible;

    /// <summary>
    /// Never set this property, instead set ShowDetailsVideo instead.
    /// </summary>
    public Visibility ShowMainScreen
    {
        get
        {
            return this._showMainScreen;
        }

        private set
        {
            this._showMainScreen = value;
        }
    }

一个View元素的 Visibility 属性绑定到 View Model 的ShowDetailsVideo属性。另一个View元素的 Visibility 属性绑定到 View Model 的ShowMainScreen属性。在运行时,两个属性getter都被访问,表明这对绑定的 View 元素至少访问了一次属性。此外,两个 View 元素确实具有正确的可见性状态。但是,如果我在运行时更改ShowDetailsVideo属性,则访问的是setter,但不会访问getter,表明属性和视图元素属性之间的连接不起作用,尽管我使用了 Fody PropetyChanged 包。属性访问行为与 Fody 包不存在时相同。

如何解决此问题并使其正常工作,以便在运行时正确更新 Visibility 属性的视图元素对?我认为 Fody PropertyChanged 包应该使实现属性更改通知变得不必要。

4

1 回答 1

0

我添加了这个答案,因为这个问题花了我几个小时来寻找和修复。我将答案标记为社区 wiki,因为我不是为它寻求信誉,只是为了避免其他人在诊断它时遇到的麻烦。

下面是更正后的视图模型代码,以使属性更改通知正常工作。当视图模型中的可绑定属性发生更改时,视图没有更新,因为我没有在属性设置器中调用基本的 SetProperty() 方法,而是我只进行了直接分配,因此不会触发属性更改通知。您可以在我原始帖子的属性设置器中看到这一点。只需添加 SetProperty() 调用即可解决所有问题。

因此,如果您的 View Model 类来自 BindableBase 之类的类(见下文),则您根本不需要 Fody PropertyChanged 插件,但请确保您在属性设置器中调用 SetProperty() 而不是直接分配给数据支持该财产的成员。

更新了属性设置器/获取器

    private Visibility _showDetailsVideo = Visibility.Collapsed;

    public Visibility ShowDetailsVideo 
    { 
        get
        {
            return this._showDetailsVideo;
        }

        set
        {
            SetProperty(ref this._showDetailsVideo, value);
            this.ShowMainScreen = value == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
        }
    }

    private Visibility _showMainScreen = Visibility.Visible;

    /// <summary>
    /// Never set this property, instead set ShowDetailsVideo instead.
    /// </summary>
    public Visibility ShowMainScreen
    {
        get
        {
            return this._showMainScreen;
        }

        private set
        {
            SetProperty(ref this._showMainScreen, value);
        }
    }

我的视图模型所继承的 BindableBase 类

/// <summary>
/// Abstraction of data-binder that notifies properties changes to the suitable View.
/// </summary>
public abstract class BindableBase : INotifyPropertyChanged
{
    /// <summary>
    /// Event launched when a property of the bindable object has changed.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Sets the value of the binded property.
    /// </summary>
    /// <typeparam name="T">The generic type.</typeparam>
    /// <param name="storage">The type of the property.</param>
    /// <param name="value">The value of the property.</param>
    /// <param name="propertyName">The name of the property.</param>
    /// <returns>A boolean indicating the success of the assignation.</returns>
    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName]String propertyName = null)
    {
        if (Equals(storage, value)) return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    /// <summary>
    /// Event handler for the PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The name of the property that has changed.</param>
    protected void OnPropertyChanged(string propertyName = null)
    {
        //if (Debugger.IsAttached)
        //    Debug.WriteLine("Property changed: " + propertyName);

        var eventHandler = PropertyChanged;
        if (eventHandler != null)
            eventHandler(this, new PropertyChangedEventArgs(propertyName));
    }

    /// <summary>
    /// Initializes the bindable object.
    /// </summary>
    /// <param name="parameters">Dictionary with the parameters.</param>
    public virtual void Initialize(IDictionary<string, string> parameters)
    {

    }
}
于 2013-12-08T15:25:27.590 回答