Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 绑定到模型或视图模型_C#_Wpf_Mvvm_Binding - Fatal编程技术网

C# 绑定到模型或视图模型

C# 绑定到模型或视图模型,c#,wpf,mvvm,binding,C#,Wpf,Mvvm,Binding,我知道已经有关于这个主题的问题了,但这些问题在某种程度上是针对其他问题的,并没有提供结论性的答案 特别是这里的:,当然所以请不要太快结束这个问题。他们回答说“做这个,做那个”,而不是为什么 有人否认需要一个视图模型,并这样说 “标准”方式是直接绑定到模型。这是我所否认的,并试图用技术论证来证明 从我在MVC,MVP,演示模型的背景来看,这很自然 让我使用视图模型也许我错过了一个重要的要点? 因此,对于我来说,默认情况是绑定到ViewModel,而不管模型是什么(也不管它是否实现了INotifyP

我知道已经有关于这个主题的问题了,但这些问题在某种程度上是针对其他问题的,并没有提供结论性的答案

特别是这里的:,当然所以请不要太快结束这个问题。他们回答说“做这个,做那个”,而不是为什么

有人否认需要一个
视图模型
,并这样说 “标准”方式是直接绑定到模型。这是我所否认的,并试图用技术论证来证明

从我在
MVC
MVP
演示模型
的背景来看,这很自然 让我使用
视图模型
也许我错过了一个重要的要点?

因此,对于我来说,默认情况是绑定到
ViewModel
,而不管
模型是什么(也不管它是否实现了
INotifyPropertyChanged

我认为绑定到
ViewModel
s有几个原因,包括 (如此处和此处所述)

1。从视图中删除逻辑

  • 使逻辑单元可测试
  • 减少代码冗余(必要时重复)
2。安全性

  • 模型包含用户不应更改的属性
  • 如果绑定到模型,则可能会发生自动但不需要的更新
3。松耦合

  • 如果直接绑定到模型,则较低层和视图之间将存在耦合
  • 更改模型会导致所有视图中的更改
  • 视图不依赖于任何给定的模型
  • 模型可以通过EF、一些DSL、批处理文件等轻松生成
4。发展速度

  • 您可以从
    原型ViewModel
    层次结构开始并绑定到该层次结构
  • 如果模型仍在开发中,您可以从原型模型开始
  • Model
    ViewModel
    可以通过测试驱动开发,无论视图如何
  • 视图
    完全可以由具有强大设计背景的设计师或开发人员构建
5。解决了“棘手的同步问题”

  • 对于任何给定的“棘手的同步”问题,都有很多解决方案,例如
  • 汽车制造商
  • 模型中的事件系统(模型激发事件,视图模型订阅)
6。整个项目的平等结构

  • 有些地方必须创建ViewModel,如SelectedItem
  • 混合绑定到Model和ViewModel很容易出错
  • 新开发人员很难弄清楚项目的结构
  • 在没有办法解决的情况下,以后再开始使用ViewModel会很混乱
7。可扩展性

  • 让我们定义:如果不使用ViewModel,则它不是MVVM
  • MVVM可以很容易地应用于许多数据源、许多视图
  • 如果发现任何性能问题:延迟加载和缓存将进入ViewModel
8。关注点分离

  • 掌握复杂性是软件的主要问题
  • ViewModels的唯一责任是推动更改
  • 向视图发送通知与将其推送到不同的进程或机器一样容易
  • ViewModel,而不是模型/数据源上更改通知的视图注册表
  • 数据源可以忽略向ViewModel发送导致更改的事件
相反的,这个家伙在比赛中丢了一些分数,包括

  • 如果直接更新模型,视图模型将不知道触发属性更改事件。这会导致UI不同步。 这严重限制了在父视图模型和子视图模型之间发送消息的选项

  • 如果模型有自己的属性更改通知,#1和2不是问题。相反,如果包装器VM超出范围,但模型没有超出范围,则必须担心内存泄漏

  • 如果您的模型很复杂,有很多子对象,那么您必须遍历整个树,并创建第二个对象图来遮挡第一个对象图。这可能非常乏味,而且容易出错

  • 包装的集合尤其难以处理。任何时候(UI或后端)从集合中插入或删除项时,都需要更新卷影集合以匹配。这种代码很难正确编写

  • 那么,问题是:默认的绑定方式是什么?为什么?

    我是否遗漏了需要使用ViewModel的要点

    是否有任何想绑定到模型的真正原因

    最重要的是为什么,而不是如何

    所以,问题是:绑定的默认方式是什么?为什么

    一般来说,我认为拥有一个ViewModel并绑定到它是默认的。“ViewModel”的存在是有原因的,它是MVVM模式的一部分

    除了纯粹的数据之外,还存在需要ViewModel的其他原因。您还通常实现特定于应用程序的逻辑(即:不是模型的一部分,但在应用程序中是必需的)。例如,任何
    ICommand
    实现都应该在ViewModel上,因为它与模型完全无关

    有没有什么真正的理由想绑定到一个模型


    在某些情况下,它可能更简单,特别是如果您的模型已经实现了
    INotifyPropertyChanged
    。降低代码复杂性是一个有价值的目标,有其自身的优点。

    视图模型通常包含用于视图的成员(例如,
    IsSomethingSelected
    IsSomethingExpandedpublic class ModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    
            OnErrorChanged(propertyName);
        }
    
        protected void OnErrorChanged(string propertyName)
        {
            if (ErrorsChanged != null)
                ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }
    
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    
        public virtual IEnumerable GetErrors(string propertyName)
        {
            return Enumerable.Empty<string>();
        }
    
        public virtual bool HasErrors
        {
            get { return false; }
        }
    }
    
    public class Customer : ModelBase
    {
        public Customer()
        {
            Orders.CollectionChanged += Orders_CollectionChanged;
        }
    
        void Orders_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.OldItems.Count > 0)
                foreach (INotifyPropertyChanged item in e.OldItems)
                    item.PropertyChanged -= Customer_PropertyChanged;
    
            if (e.NewItems.Count > 0)
                foreach (INotifyPropertyChanged item in e.NewItems)
                    item.PropertyChanged += Customer_PropertyChanged;
    
            OnPropertyChanged("TotalSales");
        }
    
        void Customer_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Total")
                OnPropertyChanged("TotalSales");
        }
    
        public decimal TotalSales
        {
            get { return Orders.Sum(o => o.Total); }
        }
    
        private string _FirstName;
        public string FirstName
        {
            get { return _FirstName; }
            set
            {
    
                if (_FirstName == value)
                    return;
                _FirstName = value;
                OnPropertyChanged();
            }
        }
    
        private string _LastName;
        public string LastName
        {
            get { return _LastName; }
            set
            {
    
                if (_LastName == value)
                    return;
                _LastName = value;
                OnPropertyChanged();
            }
        }
    
    
    
        private readonly ObservableCollection<Order> _Orders = new ObservableCollection<Order>();
        public ObservableCollection<Order> Orders
        {
            get { return _Orders; }
        }
    
    }
    
    public class Order : ModelBase
    {
        public Order()
        {
            OrderLines.CollectionChanged += OrderLines_CollectionChanged;
        }
    
        void OrderLines_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.OldItems.Count > 0)
                foreach (INotifyPropertyChanged item in e.OldItems)
                    item.PropertyChanged -= OrderLine_PropertyChanged;
    
            if (e.NewItems.Count > 0)
                foreach (INotifyPropertyChanged item in e.NewItems)
                    item.PropertyChanged += OrderLine_PropertyChanged;
    
            OnPropertyChanged("Total");
            OnErrorChanged("");
        }
    
        public override bool HasErrors
        {
            get { return GetErrors("").OfType<string>().Any() || OrderLines.Any(ol => ol.HasErrors); }
        }
    
        void OrderLine_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Extension")
                OnPropertyChanged("Total");
        }
    
        public decimal Total
        {
            get { return OrderLines.Sum(o => o.Extension); }
        }
    
        private int _OrderNumber;
        private DateTime _OrderDate;
    
        public DateTime OrderDate
        {
            get { return _OrderDate; }
            set
            {
                if (_OrderDate == value)
                    return;
                _OrderDate = value;
                OnPropertyChanged();
            }
        }
        public int OrderNumber
        {
            get { return _OrderNumber; }
            set
            {
                if (_OrderNumber == value)
                    return;
                _OrderNumber = value;
                OnPropertyChanged();
            }
        }
    
        private readonly ObservableCollection<OrderLine> _OrderLines = new ObservableCollection<OrderLine>();
        public ObservableCollection<OrderLine> OrderLines
        {
            get { return _OrderLines; }
        }
    
    }
    
    public class OrderLine : ModelBase
    {
        private string _ProductName;
        private decimal _Quantity;
        private decimal _Price;
        public decimal Price
        {
            get { return _Price; }
            set
            {
                if (_Price == value)
                    return;
                _Price = value;
                OnPropertyChanged();
            }
        }
        public string ProductName
        {
            get { return _ProductName; }
            set
            {
                if (_ProductName == value)
                    return;
                _ProductName = value;
                OnPropertyChanged();
                OnPropertyChanged("Extension");
            }
        }
        public decimal Quantity
        {
            get { return _Quantity; }
            set
            {
                if (_Quantity == value)
                    return;
                _Quantity = value;
                OnPropertyChanged();
                OnPropertyChanged("Extension");
            }
        }
        public decimal Extension
        {
            get { return Quantity * Price; }
        }
    
        public override IEnumerable GetErrors(string propertyName)
        {
            var result = new List<string>();
    
            if ((propertyName == "" || propertyName == "Price") && Price < 0)
                result.Add("Price is less than 0.");
            if ((propertyName == "" || propertyName == "Quantity") && Quantity < 0)
                result.Add("Quantity is less than 0.");
    
            return result;
        }
    
        public override bool HasErrors
        {
            get { return GetErrors("").OfType<string>().Any(); }
        }
    }
    
    public class CustomerViewModel : ModelBase
    {
        public CustomerViewMode()
        {
            LoadCustomer = null; //load customer from service, database, repositry, etc.
            SaveCustomer = null; //save customer to service, database, repositry, etc.
        }
    
        private Customer _CurrentCustomer;
    
        public Customer CurrentCustomer
        {
            get { return _CurrentCustomer; }
            set
            {
                if (_CurrentCustomer == value)
                    return;
                _CurrentCustomer = value;
                OnPropertyChanged();
            }
        }
        public ICommand LoadCustomer { get; private set; }
        public ICommand SaveCustomer { get; private set; }
    
    }