- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
是否有类似 INotifyPropertyChanged 的接口(interface),其中事件参数包含正在更改的属性的旧值,或者我是否必须扩展该接口(interface)来创建一个接口(interface)?
例如:
public String ProcessDescription
{
get { return _ProcessDescription; }
set
{
if( value != ProcessDescription )
{
String oldValue = _ProcessDescription;
_ProcessDescription = value;
InvokePropertyChanged("ProcessDescription", oldvalue);
}
}
}
InvokePropertyChanged(String PropertyName, OldValue)
{
this.PropertyChanged( new ExtendedPropertyChangedEventArgs(PropertyName, OldValue) );
}
我也会满足于提供此信息的类似 PropertyChanging 的事件,无论它是否支持 e.Cancel。
最佳答案
如答案所示,我必须实现自己的解决方案。为了其他人的利益,我在这里展示了它:
扩展的 PropertyChanged 事件
此事件经过专门设计,可向后兼容旧的 propertyChanged 事件。调用者可以将它与简单的 PropertyChangedEventArgs 互换使用。当然,在这种情况下,事件处理程序有责任检查传递的 PropertyChangedEventArgs 是否可以向下转换为 PropertyChangedExtendedEventArgs,如果他们想使用它的话。如果他们只对 PropertyName 属性感兴趣,则无需向下转型。
public class PropertyChangedExtendedEventArgs<T> : PropertyChangedEventArgs
{
public virtual T OldValue { get; private set; }
public virtual T NewValue { get; private set; }
public PropertyChangedExtendedEventArgs(string propertyName, T oldValue, T newValue)
: base(propertyName)
{
OldValue = oldValue;
NewValue = newValue;
}
}
示例 1
用户现在可以指定一个更高级的 NotifyPropertyChanged
方法,允许属性 setter 传入它们的旧值:
public String testString
{
get { return testString; }
set
{
String temp = testString;
testValue2 = value;
NotifyPropertyChanged("TestString", temp, value);
}
}
新的 NotifyPropertyChanged
方法如下所示:
protected void NotifyPropertyChanged<T>(string propertyName, T oldvalue, T newvalue)
{
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(propertyName, oldvalue, newvalue));
}
OnPropertyChanged
和往常一样:
public virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(sender, e);
}
示例 2
或者如果您更喜欢使用 lambda 表达式并完全取消硬编码的属性名称字符串,您可以使用以下内容:
public String TestString
{
get { return testString; }
private set { SetNotifyingProperty(() => TestString, ref testString, value); }
}
这是由以下魔术支持的:
protected void SetNotifyingProperty<T>(Expression<Func<T>> expression, ref T field, T value)
{
if (field == null || !field.Equals(value))
{
T oldValue = field;
field = value;
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(GetPropertyName(expression), oldValue, value));
}
}
protected string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression memberExpression = (MemberExpression)expression.Body;
return memberExpression.Member.Name;
}
性能
如果性能是一个问题,请看这个问题:Implementing NotifyPropertyChanged without magic strings .
总而言之,开销很小。添加旧值并切换到扩展事件大约减速 15%,仍然允许每秒大约一百万个属性通知,切换到 lambda 表达式是减速 5 倍,允许每秒大约十万个属性通知第二。这些数字远不能在任何 UI 驱动的应用程序中形成瓶颈。
(可选)扩展的 PropertyChanged 接口(interface)
注意:您不必这样做。您仍然可以只实现标准的 INotifyPropertyChanged 接口(interface)。
如果程序员想要创建一个需要通知属性包含旧值和新值的事件,他们需要定义和实现以下接口(interface):
// Summary: Notifies clients that a property value is changing, but includes extended event infomation
/* The following NotifyPropertyChanged Interface is employed when you wish to enforce the inclusion of old and
* new values. (Users must provide PropertyChangedExtendedEventArgs, PropertyChangedEventArgs are disallowed.) */
public interface INotifyPropertyChangedExtended<T>
{
event PropertyChangedExtendedEventHandler<T> PropertyChanged;
}
public delegate void PropertyChangedExtendedEventHandler<T>(object sender, PropertyChangedExtendedEventArgs<T> e);
现在任何 Hook PropertyChanged 事件的人都需要提供上面定义的扩展参数。请注意,根据您的用例,您的 UI 可能仍需要您实现基本的 INotifyPropertyChanged 接口(interface)和事件,这会与此冲突。例如,如果您要构建自己的依赖于此行为的 UI 元素,您就会这样做。
8 年后的常见问题解答 - 如何使用它?
以上示例展示了您将如何发送新的属性信息,但并未展示您将如何使用它们。晚了 8 年,但这里有一个事件实现的例子(感谢@Paddy 填补过去 6 年的不足):
myNotifyingClass.PropertyChanged += OnSomePropertyChanged;
private void OnSomePropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Without casting 'e' is a standard PropertyChanged event
Debug.WriteLine($"'{e.PropertyName}' has changed.");
// If you just care to check whether a certain properties changed, do so as usual
if (e.PropertyName == nameof(SomeClass.Description))
{
myNotifyingClass.MarkAsDirty(); // For example
}
// If the old/new value are if interest, you can cast in those situations
if (e.PropertyName == nameof(SomeClass.SortKey))
{
// For example, use it to order by some new property first, but by the last property second.
if(e is PropertyChangedExtendedEventArgs<string> sortKeyChanged)
myNotifyingClass.OrderBy(sortKeyChanged.NewValue, then_by: sortKeyChanged.OldValue);
else
throw new Exception("I must have forgotten to use the extended args!");
}
// To support more general operations, see the note below on creating interfaces
}
正如我们在上面的示例中所注意到的,如果不先进行强制转换,我们对这些通用参数无能为力。那是因为 8 年前,我可能甚至不知道什么是协方差。如果您希望它更有用,定义一些接口(interface)可能是有意义的,您可以使用这些接口(interface)进行类型检查并在不知道运行时类型的情况下提取属性值:
public interface IPropertyChangedExtendedEventArgs<out T> : IPropertyChangedEventArgs
{
public virtual T OldValue { get; }
public virtual T NewValue { get; }
}
public class PropertyChangedExtendedEventArgs<T> : IPropertyChangedExtendedEventArgs<T>
{
public virtual T OldValue { get; private set; }
public virtual T NewValue { get; private set; }
public PropertyChangedExtendedEventArgs(string propertyName, T oldValue, T newValue)
: base(propertyName)
{
OldValue = oldValue;
NewValue = newValue;
}
}
这现在更好用了:
if (e is IPropertyChangedExtendedEventArgs<object> anyProperty)
Console.WriteLine($"'{anyProperty.PropertyName}' has changed, " +
$"from '{anyProperty.OldValue}' to '{anyProperty.NewValue}'.");
我希望一切都解决了!
关于c# - NotifyPropertyChanged 事件,其中事件参数包含旧值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7677854/
这个问题在这里已经有了答案: 9年前关闭。 Possible Duplicate: typesafe NotifyPropertyChanged using linq expressions 我正在开
我刚刚根据 Rachel Lim 的 blog 实现了我的业务逻辑验证。 . 一切都运行良好,直到我决定在绑定(bind)到 的 View 中放置一个触发器。有效像这样的属性(property):
测试此属性的最佳方法是什么: public string ThreadId { get { return _threadId; } set {
我有以下 View 模型 [NotifyPropertyChanged] public class ActivateViewModel { public string Password { g
我正在尝试为 ListBox 捕获 SelectedItem,然后为 Button 触发数据模板单击事件。我在 notifypropertychanged 事件处理程序中放置了一个断点,但它从未触发。
我正在查看 INotifyPropertyChanged 中的 NotifyPropertyChanged() 并注意到在 Microsoft 的示例中,例如此处: http://msdn.micro
如果我更新的属性在绑定(bind)控件的调度程序以外的线程上抛出 NotifyPropertyChanged,更新是否会被强制编码到此调度程序? BackgrounWorker.Run() => {
您好,我有一个 DataGridCheckBoxColumn,我希望它在用户选中或取消选中 DataGridCheckBoxColumn 时立即在基础绑定(bind)对象上通知 propertycha
似乎有些人在 Silverlight 中更新文本 AutoCompleteBox 时遇到问题,遗憾的是我已经加入了这个行列。 我有一个像这样的名为 EditableCombo 的派生类; publ
我的应用程序具有定期数据库同步功能。每当发生同步时,所有输入控件的值都会重置为数据库中的当前值。 但是,当在 TextBox 中键入长文本时发生同步事件时,这非常不方便。 期望的行为是输入控件的值不设
我有一个 UserControl,它包含 bool 属性 A。在包含该 UserControl 的主窗口中,我必须根据 A 的值启用/禁用按钮。我试图像这样将 A 设置为公开和绑定(bind)按钮:
我现在已经为我的问题苦苦挣扎了一个星期,但我无法解决它。我正在编写一个只有一个窗口 (MainView) 的 MVVM WPF 应用程序。在此 Mainview 中,我想在需要时加载不同的 UserC
我正在使用 Android 的数据绑定(bind)库。我的数据对象扩展了 BaseObservable。 public static class SimpleData extends BaseObse
在我的新 WPF 应用程序中,我重用了一个模型类。在该模型类中,所有属性都在其 setter 中触发 NotifyPropertyChanged。在我的应用程序中,我并没有真正为单个属性触发 INPC
是否有类似 INotifyPropertyChanged 的接口(interface),其中事件参数包含正在更改的属性的旧值,或者我是否必须扩展该接口(interface)来创建一个接口(inte
我有一个组件,其中包含一个子组件列表(在父组件中使用 yield 绘制): parent-component for item in items child-component item=
表格 Build your own MVVM我有以下代码可以让我们进行类型安全的 NotifyOfPropertyChange 调用: public void NotifyOfPropertyChan
这是一个简化的示例,但很好地说明了我的问题。我有一个 PIN 码输入,带有数字按钮(1、2、3、4)。我的按钮上的操作应该设置一个属性 pinValue ,该属性将传递到包装的组件 pin-input
我对 INotifyPropertyChanged 的 PostSharp 实现没有什么问题。 PostSharp 在编译时添加了 PropertyChangedEventHandler Proper
我对 WPF 非常熟悉,但有一件事困扰着我。我正在使用 ReactiveUI 引发 INotifyPropertyChanged 事件。我有两个地方与此类似: public UiModel UiMo
我是一名优秀的程序员,十分优秀!