Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.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 - Fatal编程技术网

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

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

我使用MVVM模式创建了一个项目(或者我认为;))。为了简化我的情况:

型号

public class Model {
    public string Name { get; set; }
    public bool IsDefective { get; set; }
}
ViewModel-扩展MvvmLight
ViewModelBase

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)
            }));
        }
    }
}