【问题标题】:Access ObservableCollection items from property set从属性集中访问 ObservableCollection 项
【发布时间】:2015-08-20 00:04:37
【问题描述】:

给定以下用作 WPF DataContext 的类:

class ViewModel
{
    public ObservableCollection<Task> Tasks { get; set; }
}

还有这个任务类:

public class Task
{
    private string startTime;

    public Task ID { get; set; }
    public string StartTime
    {
        get { return startTime; }
        set
        {
            // Access ObservableCollection items
            startTime = value;
            OnPropertyChanged("StartTime");
        }
    }
}

如何在代码中您看到“// 访问 ObservableCollection 项”的位置访问 Tasks ObservableCollection 中的其他项,以便将设置的实例的 StartTime 与其他任务的 StartTime 进行比较Tasks ObservableCollection 中的项目?

【问题讨论】:

  • 我完全不确定我会 - 听起来您可能正在尝试将 ViewModel 级别的功能放入您的模型中。是否有充分的理由不将该比较合并到 ViewModel 中?
  • @goobering:鉴于我想在设置属性时进行比较,你能给我一些指导吗?
  • 为什么需要比较?你的方案是什么?
  • @Liero:因为 StartTimes 绑定到 DataGrid 中的 TextBoxes,所以用户可以更改 StartTime。 StartTimes 需要按时间顺序排列,因此如果用户在一行中更改 StartTime,则该时间必须在上一行的 StartTime 之后,并且在下一行的 StartTime 之前。
  • @Liero:更多信息:如果输入的时间不可接受,那么我不想设置该属性。这就是为什么我最初的尝试是尝试在属性的设置逻辑中执行此操作。我可以通过在 TextBox 的 XAML 中指定 LostFocus 属性来做到这一点,并且该属性的值是窗口代码隐藏中的一个方法。如果 TextBox 的值不可接受,我可以将其恢复为原始值。由于 LostFocus 事件发生在属性设置之前,因此不会为属性分配错误值。我的新方法是尝试消除代码隐藏。

标签: c# wpf


【解决方案1】:

你有两个选择:

  1. 您可以将 ViewModel 注入到任务中

    public class Task
    {
        private ViewModel viewModel;
        public class Task(ViewModel viewModel)
        {
            this.viewModel = viewModel;
        }
        ...
    }
    

    但是,这使得 Task 类只能与 ViewModel 类一起使用,因为它们是松散耦合的。

  2. 您可以在 ViewModel 中执行 StartTime 验证。为此,您需要捕获所有任务的 PropertyChanged 事件。

    我创建了ExtendedObservableCollection,它会在任何项目的属性发生更改时触发一个事件:

    public class ExtendedObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler ItemPropertyChanged;
        protected override void ClearItems()
        {
            foreach (var item in Items) item.PropertyChanged -= OnItemPropertyChanged;
            base.ClearItems();
        }
    
        protected override void InsertItem(int index, T item)
        {
            item.PropertyChanged += OnItemPropertyChanged;
            base.InsertItem(index, item);
        }
    
        protected override void RemoveItem(int index)
        {
            this[index].PropertyChanged -= OnItemPropertyChanged;
            base.RemoveItem(index);
        }
    
        protected override void SetItem(int index, T item)
        {
            this[index].PropertyChanged -= OnItemPropertyChanged;
            item.PropertyChanged += OnItemPropertyChanged;
            base.SetItem(index, item);
        }
    
        protected virtual void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
       {
           var handler = ItemPropertyChanged;
           if (handler != null) handler(sender, e);
       }
    }
    

    最后完成验证或您需要的任何东西

    public class ViewModel
    {
       public ExtendedObservableCollection<Task> Tasks { get; set; }
       public ViewModel()
       {
           Tasks=new ExtendedObservableCollection<Task>();
           Tasks.ItemPropertyChanged += TaskPropertyChanged;
       }
    
       private void TaskPropertyChanged(object sender, PropertyChangedEventArgs e)
       {
           var changedTask = (Task)sender;
           if (e.PropertyName == "StartTime")
           {
              if (!IsStartTimeGreatedThenPrevious(changedTask )) 
                  changedTask.SetError("StartTime", "Start time has to be greated than in previous task)
           }
       }        
    }
    

您可以在任务集合中添加或删除项目,ExtendedObservableCollection 负责附加/分离到 PropertyChanged 事件。

【讨论】:

  • 将视图模型与模型混合,我不喜欢我的实体或 DTO 中的视图模型内容
  • 我假设,你在谈论第一种方法。好吧,这取决于 Task 类是什么。没有人说它是模型实体或 DTO。我提到了松散耦合这两个类的缺点。第二种方法不混合 Task 和 ViewModel。
  • 所以不推荐在 Task 类本身上实现 INotifyPropertyChanged(这是我实际拥有它的方式,即使我在最初的问题中省略了它),因为该类不是 ViewModel 的一部分?跨度>
  • 似乎使用这种方法,验证将在属性设置后发生。我希望在设置属性之前进行验证,以便在验证失败时可以中止属性的设置。
  • 1.回复:INotifyPropertyChanged 上的任务:不,这不是重点。将视图模型注入模型不是一个好习惯。
猜你喜欢
  • 2017-12-01
  • 1970-01-01
  • 2011-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-18
  • 1970-01-01
  • 2018-09-03
相关资源
最近更新 更多