C# 绑定到模型或视图模型
我使用MVVM模式创建了一个项目(或者我认为;))。为了简化我的情况: 型号:C# 绑定到模型或视图模型,c#,wpf,mvvm,C#,Wpf,Mvvm,我使用MVVM模式创建了一个项目(或者我认为;))。为了简化我的情况: 型号: public class Model { public string Name { get; set; } public bool IsDefective { get; set; } } ViewModel-扩展MvvmLightViewModelBase: public class ViewModel : ViewModelBase { private ObservableCollecti
public class Model {
public string Name { get; set; }
public bool IsDefective { get; set; }
}
ViewModel-扩展MvvmLightViewModelBase
:
public class ViewModel : ViewModelBase {
private ObservableCollection<Model> models;
public ObservableCollection<Model> Models {
get {
if (_models== null) {
_models= new ObservableCollection<Models>();
}
return _models;
}
set {
RaisePropertyChanged("Models");
_models= value;
}
}
}
public类ViewModel:ViewModelBase{
私有可观测收集模型;
公共可观测收集模型{
得到{
如果(_models==null){
_模型=新的ObservableCollection();
}
回归模型;
}
设置{
RaisePropertyChanged(“模型”);
_模型=价值;
}
}
}
查看-我正在显示一个文本框列表:
<TextBlock Text="{Binding Name}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=.IsDefective}" Value="True">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
我的场景是这样的:
Model
类中的某些方法可能会更改IsDefective属性,但由于我的模型没有实现INotifyPropertyChanged
接口,因此我的视图不知道这些更改。“mvvm方式”应该如何解决这个问题?我在这里偶然发现了这个问题,但老实说,在阅读了投票率最高的答案和评论中的讨论之后,我更困惑了:。我愿意同意Jonathan Allen的观点,因为这样绑定对我来说更自然,但作为mvvm模式的初学者,我可能遗漏了一些东西。那么,我是吗?您没有遗漏任何东西,Mvvm及其对应部分是帮助您创建可维护、可测试和解耦的代码片段的建议
当你遇到一种情况,你复制代码只是为了满足Mvvm,你可以“作弊”
您的模型实现INotifyPropertyChanged是完全合法的。
它在“CRUD”应用程序中非常流行。通常,您希望您的模型是一个哑数据传输对象。当您执行数据库查询时,您会得到一个哑模型,该模型不会进行任何转换,因为否则您就无法遵循实体主体中的关注点分离。然而,稍微作弊并不会让你丧命,但它可能会让调试变得有点令人沮丧,因为大多数人不会期望他们的POCO(普通的旧CLR对象)启动任何业务逻辑 下面是一些代码: 一些设置类: ViewModelBase.cs galasoft的ViewModelBase的“更智能”版本,这个坏男孩自动连接设计时视图模型(您会喜欢这个) 使用模型优先法: ProductModel.cs POCO DTO
namespace WPFPlayground.Model
{
public class ProductModel
{
public string Name { get; set; }
public bool IsDefective { get; set; }
}
}
ProductViewModel.cs
请注意,使用setvalue自动连接notifypropertychanged事件
namespace WPFPlayground.ViewModel
{
public class ProductViewModel : ViewModelBase
{
private string _name;
private bool _isDefective;
public bool IsDefective
{
get { return _isDefective; }
set { SetValue(ref _isDefective, value); }
}
public string Name
{
get { return _name; }
set { SetValue(ref _name, value); }
}
}
}
我们有一个productmodel和一个productviewmodel。一个在与数据库交互时完成所有工作,另一个在绑定到视图时完成所有工作
因此,我们需要一个仅表示单个productviewmodel的视图:
ProductView.xaml
注意使用背景颜色转换器来处理触发器
<UserControl x:Class="WPFPlayground.View.ProductView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wpfPlayground="clr-namespace:WPFPlayground"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance wpfPlayground:DesignProductViewModel, IsDesignTimeCreatable=True}">
<UserControl.Resources>
<wpfPlayground:DefectiveToBackgroundColorConverter x:Key="DefectiveToBackgroundColorConverter" />
</UserControl.Resources>
<Viewbox>
<Border Width="500" Background="{Binding IsDefective, Converter={StaticResource DefectiveToBackgroundColorConverter}}">
<TextBlock Text="{Binding Name}" FontSize="40" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
</Viewbox>
</UserControl>
现在,我们需要显示这些viewmodels的列表:
MainWindow.xaml
Items全天控制错误日期
<Window x:Class="WPFPlayground.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModel="clr-namespace:WPFPlayground.ViewModel"
xmlns:view="clr-namespace:WPFPlayground.View"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" d:DataContext="{d:DesignInstance viewModel:DesignProductsViewModel, IsDesignTimeCreatable=True}">
<Window.Resources>
<DataTemplate DataType="{x:Type viewModel:ProductViewModel}">
<view:ProductView />
</DataTemplate>
</Window.Resources>
<StackPanel>
<ItemsControl ItemsSource="{Binding Products}">
<view:ProductView />
</ItemsControl>
</StackPanel>
</Window>
DesignProductsViewModel.cs
设计时视图模型,以便您可以看到它在设计时工作。它生成一组简单的随机产品
using System;
using System.Collections.ObjectModel;
using System.Linq;
namespace WPFPlayground.ViewModel
{
public class DesignProductsViewModel : ProductsViewModel
{
public DesignProductsViewModel()
{
var random = new Random();
Products = new ObservableCollection<ProductViewModel>(Enumerable.Range(1, 5).Select(i => new ProductViewModel
{
Name = String.Format(@"Product {0}", i),
IsDefective = (random.Next(1, 100) < 50)
}));
}
}
}
使用系统;
使用System.Collections.ObjectModel;
使用System.Linq;
命名空间WPFPlayground.ViewModel
{
公共类设计ProductsViewModel:ProductsViewModel
{
公共设计产品视图模型()
{
var random=新的random();
Products=新的ObservableCollection(可枚举。范围(1,5)。选择(i=>new ProductViewModel
{
Name=String.Format(@“Product{0}”,i),
IsDefective=(随机。下一步(1100)<50)
}));
}
}
}
Mvvm及其对应部分是一个建议,它可以帮助您创建可维护、可测试和解耦的代码片段。您的模型实现INotifyPropertyChanged是完全合法的。它在“CRUD”应用程序中非常流行。“…Model类中的某些方法可能会更改IsDefective属性…”您能否澄清哪个类调用Model方法(可能更改IsDefective
属性的方法)?我同意您的DTO可以保持“哑巴”您可以为DTO的UI端创建一个包装器,在那里它实现了InotifyProperty更改,但大多数时候它只是冗余和不方便..像冗余和不方便这样的词是人们用来忽略TDD、可靠原则和其他受益实践的东西。仅仅因为它不方便,并不意味着它应该被丢弃。所以在你看来——在这个特定的场景中——我应该为我的视图创建一个额外的层来建模绑定,还是应该作弊?我已经编写了一些测试用例,这很容易-我对这段代码没有任何问题,但可能附加层会使编写测试变得更加容易(再一次,在这个特殊的情况下)?换句话说,如果我不直接向视图公开模型,在这种情况下我会得到什么好处?这是一个简单的例子,但我的应用程序将增长。这完全取决于你,我的朋友。在我的应用程序中,会有一个“模型”ViewModel,我会在那里完成notifypropertychanged属性。这就是MVVM的目的。如果您将这一点业务逻辑添加到您的模型中,如果出现新的业务需求,会发生什么?我想你也把它加在那里了。最终,该模型期望成为一个DTO,当它仅仅被认为是一个DTO时,它正在执行一系列业务逻辑。在小项目中,它可能不会烧死你。
using WPFPlayground.ViewModel;
namespace WPFPlayground
{
public class DesignProductViewModel : ProductViewModel
{
public DesignProductViewModel()
{
Name = "This is my product";
IsDefective = true;
}
}
}
<Window x:Class="WPFPlayground.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModel="clr-namespace:WPFPlayground.ViewModel"
xmlns:view="clr-namespace:WPFPlayground.View"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" d:DataContext="{d:DesignInstance viewModel:DesignProductsViewModel, IsDesignTimeCreatable=True}">
<Window.Resources>
<DataTemplate DataType="{x:Type viewModel:ProductViewModel}">
<view:ProductView />
</DataTemplate>
</Window.Resources>
<StackPanel>
<ItemsControl ItemsSource="{Binding Products}">
<view:ProductView />
</ItemsControl>
</StackPanel>
</Window>
using System;
using System.Collections.ObjectModel;
using System.Linq;
namespace WPFPlayground.ViewModel
{
public class DesignProductsViewModel : ProductsViewModel
{
public DesignProductsViewModel()
{
var random = new Random();
Products = new ObservableCollection<ProductViewModel>(Enumerable.Range(1, 5).Select(i => new ProductViewModel
{
Name = String.Format(@"Product {0}", i),
IsDefective = (random.Next(1, 100) < 50)
}));
}
}
}