繁体   English   中英

如何在初始化控件时阻止PropertyChanged触发

[英]How to prevent PropertyChanged from firing while controls are being initialized

这个问题已经引起了一段时间的麻烦,并且阻止了项目的进展。 考虑一个WPF XAML表单,其中包含绑定到ViewModel的控件。 (我正在使用Caliburn.Micro MVVM框架和Entity Framework来获取数据)。 shell调用Initialize()方法从数据库加载表单的数据并设置PropertyChanged事件处理程序。 有一个IsDirty标志,用于跟踪表单中是否有更改的数据。 有一个“保存”按钮绑定到IsDirty属性,以便在数据更改时启用它。

// Sample code; forms have many controls....

// this is the property that the controls are bound to
public Entity BoundData { get; set; }

public void Initialize()
{
    // this is an example line where I query the database from the Entity Framework ObjectContext...
    BoundData = objectContext.DataTable.Where(entity => entity.ID == 1).SingleOrDefault();

    // this is to cause the form bindings to retrieve data from the BoundData entity
    NotifyOfPropertyChange("BoundData");

    // wire up the PropertyChanged event handler
    BoundData.PropertyChanged += BoundData_PropertyChanged;

    IsDirty = false;
}

void BoundData_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    IsDirty = true;
}

// implementation of the IsDirty flag
public bool IsDirty
{
    get
    {
        return _isDirty;
    }
    set
    {
        _isDirty = value;
        NotifyOfPropertyChange("IsDirty");
    }
}

问题是,由于在Initialize()方法完成后从数据库初始化表单,因此BoundData_PropertyChangedBoundData_PropertyChanged事件处理程序。 因此, IsDirty标志设置为true,并且启用了“保存”按钮,即使表单刚刚加载且用户没有更改任何内容。 我错过了什么? 当然这是一个常见的问题,但我一直无法找到一个好的解决方案。 这是我的第一个MVVM项目,所以我完全有可能错过一些基本概念。

更新:为了澄清,我认为问题是我需要能够挂钩一个事件或回调,当所有绑定都完成更新时将触发,因此我可以连接PropertyChanged事件处理程序。

您可以做的一件事可能有帮助,就是设置触发更改的属性,如下所示:

    public virtual bool Prop1
    {
       get
       {
            return _prop1;
       }
       set
       {
            if (_prop1 != value)
            {
                _prop1 = value;
                NotifyOfPropertyChange("IsDirty");
            }
       }

这样,只有在实际更改了值时才会触发事件,而不仅仅是冗余设置。 这当然假设在您的情况下该值实际上没有变化。

我建议你设计一个通用的方法调用。 就像ValueChanged事件处理程序(自定义事件处理程序),它反过来调用BoundData_PropertyChanged。 这意味着,只要控件发生更改,就可以调用此ValueChanged方法/处理程序。

例如

    void ValueChanged(object sender, EventArgs e)
    {
    BoundData_PropertyChanged();
    }

   textBox.TextChanged += new System.EventHandler(ValueChanged);

语法可能不准确,但你可以猜到我在这里提出的建议。

这个解决方案可能不是绝对可靠的,但它在我使用的有限测试用例中对我有用。

在第一次输入时,EntityKey值将为null。 检查一下。

/// <summary>
/// Log the invoice status change
/// </summary>
/// <param name="value">The value that the invoice status is changing to</param>
partial void OnInvoiceStatusValueChanging(string value)
{
    var newStatus = ConvertInvoiceStatus(value);
    if (this.EntityKey != null && InvoiceStatus != newStatus)
    {
        AddNewNote(string.Format("Invoice status changing from [{0}] to [{1}]", InvoiceStatus.GetDescription(), newStatus.GetDescription()));
    }
}

/// <summary>
/// Log the invoice status change
/// </summary>
partial void OnInvoiceStatusValueChanged()
{
    if (this.EntityKey != null)
        AddNewNote(string.Format("Invoice status changed to [{0}]", InvoiceStatus.GetDescription()));
}

我知道这个问题很古老,但我遇到了同样的问题,很难搞清楚。 我是WPF / MVVM的新手,可能不知道谷歌或者问的正确的事情。 这是我的解决方案。 希望它可以帮助某人。

我的IsDirty标志几乎与原帖中的标志相同。 唯一的区别是我在视图完成渲染时添加了一个命令将其重置为false。 当呈现/实例化View时 ,基本思想来自Notify ViewModel

在视图中触发Loaded事件:

<UserControl x:Class="MyUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding Path=OnLoadedCommand}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

然后在视图模型中,在事件触发时将IsDirty标志设置为false。

public ICommand OnLoadedCommand { get; private set; }

// Constructor
public MyUserControlViewModel()
{
    OnLoadedCommand = new DelegateCommand(OnLoaded);
}

public void OnLoaded()
{
  // Ignore any PropertyChanged events that fire 
  // before the UserControl is rendered.  
   IsDirty = false; 
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM