2010-09-07 49 views
1

我一直在使用表达式 - 而且我可能已经超出了我的能力 - 但是在这里......我实现了'类型安全的'INotifyPropertyChanged实现(例子是here),但是走得更远了,附带的changetracking:更改跟踪和并发 - 可以失败吗?

public abstract BaseViewModel<TEntity>:INotifyPropertyChanged 
{ 
    private readonly IBaseChangeTracker<TEntity> _changeTracker; 
    protected void OnPropertyChanged<T>(Expression<Func<T>> property, T value) 
    { 
     _changeTracker.AddChange(property, value); 
     OnPropertyChanged(property); 
    } 
    protected virtual void OnPropertyChanged<TProperty>(Expression<Func<TProperty>> property) 
    { 
     if (PropertyChanged == null) return; 
     PropertyChanged(this, new PropertyChangedEventArgs(property.GetMemberInfo().Name)); 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
} 

public abstract class BaseChangeTracker<TEntity>:IBaseChangeTracker<TEntity> 
{ 
    private readonly IDictionary<Expression, object> _changes = new Dictionary<Expression, object>(); 
    public void AddChange<T>(Expression<Func<T>> expression, T newValue) 
    { 
     _changes.Add(expression, newValue); 
    } 

    public void ApplyChanges(TEntity entity) 
    { 
     foreach (var change in _changes) 
     { 
      var property = typeof(TEntity).GetProperty(change.Key.GetMemberInfo().Name); 
      property.SetValue(entity, change.Value, null); 
     } 
    } 

    public virtual void CopyCurrentState(TEntity entity) 
    { 
     _changes.Clear(); 

    } 
    public virtual void ResetEntity(TEntity entity) 
    { 
     _changes.Clear(); 
    } 

    public bool HasUnsavedChanges 
    { 
     get { return _changes.Any(); } 
    } 
} 

这似乎有点过分 - 每一个实体将拥有它,它自己的ChangeTracker保持实体的原始状态加载时,可以重置回这些,但这个想法是如果存在当它试图保存更新的实体时发生并发冲突,我从数据库重新加载实体,并通过.ApplyChanges运行它,并尝试再次保存它。这将消除我的约95%的并发问题...如果它有效。我的测试表明,对于有限的实体来说,它的工作原理就是简单的属性更改。

已知问题:

  1. 我还没有找到应对的集合一种优雅的方式。

我还错过了什么 - 或者我的设计中是否有明显的缺陷?

回答

1

我意识到这不是对你的问题的直接回答,但你可以考虑使用命令模式来实现撤销/重做堆栈。 (1)为应用程序增加价值的一个很好的功能,(2)您可以将许多操作包含在任何其他操作中给定的命令,如提高事件更改通知的数据绑定支持在do和undo方向。

此外,管理集合更改不会比简单的属性更新具有更多或更少的挑战性。

具体到你贴了,因为你的if()语句后裸支架再打电话return,然后(这些不对应if状态)OnPropertyChanged实施,将永远不会提高PropertyChanged事件的代码。

if (PropertyChanged == null) return; // this returns based on if 
    { 
     return; // this returns no matter what 
    } 

此外,似乎用户永远不会看到UI中的任何更改。在调用ApplyChanges之前不会更新这些值,并且此时不存在PropertyChanged事件。 (我可能没有正确地跟踪你的代码,但只是查看它,这似乎是这种情况)。

+0

双倍回报是一个错字:-)。要首先回答你的最后一个问题 - 这些是基类 - 派生的将在setters中调用OnPropertyChanged。我同意这是一个穷人的命令堆栈实现。命令的问题在于WPF有很多内置的Ctrl-Z功能(文本框中的多级撤消等),这会混淆命令。另外,我需要能够将更改应用于除原始实体之外的其他内容(即重新加载的实体)。但是,感谢您的意见! – Goblin 2010-09-08 07:07:57

+0

我现在将它关闭 - 感谢您的输入! :-) – Goblin 2010-09-09 20:40:36