关于WPF mvvm的一些问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于WPF mvvm的一些问题相关的知识,希望对你有一定的参考价值。

1、MVVM中的model是不是就是业务逻辑层(需按领域建模吗?);
2、看过网上很多的例子,有的是在Viewmodel层实现INotifyPropertyChanged;有的是在Model层实现这个接口,我知道Viewmodel层肯定要实现这个接口,不然没法驱动view层,如果说我Model层有一个Person类,它有很多属性,比如姓名,年龄,生日,性别等等,
一、如过我在Model层实现这个接口,那么我Viewmodel中可能这样写
public Person Person

get;
private set;

在和View绑定时,直接通过这个Person属性绑定,有说这样违背MVVM的初衷,View会和Model紧 耦合;
二、如果Model不实现INotifyPropertyChanged,那我需要在ViewModel中重新封装一个Model或者多个 Model的属性,这样是不是有些麻烦;
关于这两种方法,哪一种更好一点,或者说是两种结合起来用?????

    model应该是数据的表示,viewmodel才是业务逻辑

    一般是在viewmodel层,大多数都使用了实现了此接口的viewmodelbase基类

    如果你的程序很简单,那通常只需要viewmodel,不需要model层了。

    如果model不实现(因为有时候model不在你的控制范围之内),只有在ViewModel中封装,而且需要使用哪些属性就要重新让其实现inpc接口,确实比较麻烦。

    最后,MVVM只是指导原则,不是规定(MVVM is a set of guidelines, not rules.),并没有标准说一定要怎么写的

追问

model只是单纯的数据吗,那它不包含业务规则吗?

追答

可以这么说吧。

追问

我就是搞不明白,一般分层中不都有业务逻辑层吗,而且很多要按领域建模,它除了包含业务数据,自身还有业务逻辑。我不明白业务逻辑层和他这个Model层之间是什么关系,我知道ViewModel充当了View和model之间的桥梁,他肯定也要按照业务来设计。

追答

你可以理解成model就是和显示无关的东西,要呈现到界面的话就需要用viewmodel。

参考技术A

可以以管理系统为例理解下。假如:

数据库中有一张表:Person 列:ID Name;

Model为

public class Person

    public string IDget;set;
    public string Nameget;set;   

ViewModel则负责数据的读取和更新,实现INotifyPropertyChanged

public class ViewModel:INotifyPropertyChanged

   //实现省略
    private string _id;
    public string ID
    
        getreturn _id;
        set_id=value;OnPropertyChanged("ID");
    
    //Name属性同上 

    public void Query()//假如界面点击的查询按钮
           
         Person p=GetPersonFromDb(); 
         p.ID=this.ID;
         p.Name=this.Name;   
     
    public void Save()
 

这样从数据库中获得Person,然后将值赋给ViewModel中属性,就可以实现更新界面。

Model中没有任何函数,只有属性。

-----------------------------

但是现在要将表Person中的所有列显示在DataGrid中,并且编辑后保存到数据中。

这时Model和ViewModel都必须实现实现INotifyPropertyChanged。这样在DataGrid中编辑的内容才能更新到对应Person的属性中。

WPF + MVVM + RadioButton:使用单个属性处理绑定

【中文标题】WPF + MVVM + RadioButton:使用单个属性处理绑定【英文标题】:WPF + MVVM + RadioButton : Handle binding with single property 【发布时间】:2016-10-13 21:18:15 【问题描述】:

从this 和this(和其他)关于 SO 的问题以及互联网上的许多其他材料中,我了解了如何将单选按钮与 VM 绑定。

但它们都为单选按钮的每个可能值创建单独的属性。一个问题 (this) 与我的要求类似,但接受的答案建议使用 ListBox 而不是单选按钮。

要表示人的性别(数据类型 CHAR,可能的值 'M'、'F'),需要在 VM 中创建三个属性:PersonGender、IsPersonMale、IsPersonFemale。 我只想在一个属性 PersonGender 上控制它。 我可以这样做吗?如果是,怎么做?

【问题讨论】:

在每个 RadioButton 上放置一个命令(相同)并将它们的值作为参数传递 @nkoniishvt:看起来很有趣;会试试这个。但仍不能完全接受。单选按钮代表用户输入和显示,如文本框或组合框;不像命令按钮那样的动作。使用命令处理输入/显示看起来不正确。 命令是为 MVVM 制作的,如果你想拥有一个兼容 MVVM 的应用程序,你应该从 UI 绑定到命令。看看这样的教程:codeproject.com/Articles/238657/How-to-use-Commands-in-WPF 【参考方案1】:

你需要一个转换器。

//define this in the Window's Resources section or something similiarly suitable
<local:GenderConverter x:Key="genderConverterKey" />


<RadioButton Content="M" IsChecked="Binding Gender, Converter=StaticResource ResourceKey=genderConverterKey, ConverterParameter=M" />
<RadioButton Content="F" IsChecked="Binding Gender, Converter=StaticResource ResourceKey=genderConverterKey, ConverterParameter=F" />

转换器

public class GenderConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        return ((string)parameter == (string)value);
    

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        return (bool)value ? parameter : null;        
    

如果在这种情况下不应应用绑定,请将null(在ConvertBack)替换为Binding.DoNothing

return (bool)value ? parameter : Binding.DoNothing;

【讨论】:

如果在这种情况下不应应用绑定,请将 null(在 ConvertBack 中)替换为 Binding.DoNothing返回(布尔)值?参数:Binding.DoNothing; 转换器中没有任何东西将其与 Gender 数据类型联系起来。因此,您可以重命名它以使其成为通用转换器。 就我的口味而言,这个解决方案比命令解决方案更纯粹的 MVVM。【参考方案2】:

使用命令(这里使用DelegateCommands)

虚拟机:

public enum Genders 
    Female,
    Male

public YourVMClass 
    public Genders SelectedGender get; set;

    private DelegateCommand _cmdSelectGender;

    public DelegateCommand CmdSelectGender 
        get  return _cmdSelectGender ?? (_cmdSelectGender = new DelegateCommand(SelectGender)); 
    

    private void SelectGender(Object parameter) 
        SelectedGender = (Genders)parameter;
    

XAML:

<Window.Resources>
    <ObjectDataProvider x:Key="listOfGenders" MethodName="GetValues"
                        ObjectType="x:Type System:Enum">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="loca:Genders"/>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

<ItemsControl ItemsSource="Binding Source=StaticResources listOfGenders">
    <ItemsControl.ItemTemplate>
        <RadioButton GroupName="Genders" Command="Binding RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type MainWindow, Path=DataContext.CmdSelectGender" CommandParameter="Binding"/>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

(没有测试代码,但这是思路)

【讨论】:

【参考方案3】:

您的要求是可能的,但您需要一些额外的努力才能使其发挥作用。其主要原因是 RadioButton 的属性 IsCheckedBoolean 并且多个单选按钮是独立的控件,不能像一个一样。例如一个列表框。

为了满足您的要求,您可以使用转换器。 将两个 Radiobuttons 的 IsChecked 绑定到 ViewModel 中的 PersonGender 属性,并使用通用转换器并为男性单选按钮传递参数“MALE”,为女性单选按钮传递参数“FEMALE” .

在 Converter 中检查 parameterPersonGender 是否相同并为此返回 TRUE

即。如果 checkbox 命令参数是 MALE 并且 PersonGender 也是 MALE,那么复选框被启用 否则,如果复选框命令参数为 FEMALE 且 PersonGender 为 MALE,则不会启用复选框,因为返回 false。

【讨论】:

【参考方案4】:

您需要做的是使用IValueConverter,将 Bool 转换为 Char,反之亦然。 示例 True => 'M';假 => 'F'

在您的视图中有两个单选按钮。确保将它们设置在相同的组名中。 然后您需要将您的 PersonGender 绑定到仅 IsMale 单选按钮。 因为然后 IsFemale 单选按钮被选中。由于组名相同,IsMale 单选按钮将自动取消选中。

【讨论】:

【参考方案5】:

我将 solution 转换器稍微更改为 MarkupExtension 以使其更易于使用(此处为 int-converter):

public class RadioValueExtension : MarkupExtension, IValueConverter

    [ConstructorArgument("value")]
    public int Value  get; set; 

    public RadioValueExtension(int value)
    
        Value = value;    
    

    public override object ProvideValue(IServiceProvider serviceProvider)
    
        return this;
    

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        return Value == (int)value;
    

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    
        return (bool)value ? Value : Binding.DoNothing;
    

所以我可以这样使用它

<RadioButton IsChecked="Binding Gender, Converter=converters:RadioValue 0" Content="M" />
<RadioButton IsChecked="Binding Gender, Converter=converters:RadioValue 1" Content="F" />

【讨论】:

以上是关于关于WPF mvvm的一些问题的主要内容,如果未能解决你的问题,请参考以下文章

在 WPF MVVM 中的视图之间导航

wpf的棱镜vs mvvm灯

WPF - MVVM 视图模型设置

Android MVVM 设计模式示例

MVVM 架构 WPF

如何在 MVVM WPF 中刷新 UI