同一命令可用于多个视图

时间:2018-07-11 12:24:24

标签: c# wpf mvvm

我有两个相同的视图View1.xamlView2.xaml,它们都有一个按钮button1和一个文本字段textfield1。这个想法是,当您按下按钮时,相应的文本字段将填充一些信息。两种视图都使用相同的方法填充文本字段(在这种意义上,这些视图在字面上完全相同)。

我的问题是:如何使用OOP原理编写通用代码而又不破坏MVVM模式?我目前使用RelayCommand执行此操作的方式:

ViewModel1ViewModel2的相同代码:

public RelayCommand ButtonCommand { get; private set; }

#Constructor
ButtonCommand = new RelayCommand(ExecuteButtonCommand, CanExecuteButtonCommand);
#EndConstructor

private void ExecuteButtonCommand(object message)
{
    //Some method to fill the corresponding textfield
}

private bool CanExecuteButtonCommand(object message)
{
    return true;
}

绑定View1.xamlView2.xaml中的按钮:

<Button Command="{Binding Path=ButtonCommand, Mode=OneWay}" />

这很糟糕,因为我必须为两个ViewModels编写相同的代码。我试图创建一个从RelayCommand继承的类ButtonCommand,但是因为并非每个视图都具有此功能,所以无法使用此方法来实现它。

3 个答案:

答案 0 :(得分:2)

这可能是一种方法:

1-创建一个基本的viewmodel类:

public class YourBaseViewModel
{   
    public Object YourBaseProperty{get; set;}

    public RelayCommand ButtonCommand { get; private set; }

    private void ExecuteButtonCommand(object message)
    {
        //Some method to fill the corresponding textfield
    }

    private bool CanExecuteButtonCommand(object message)
    {
        return true;
    }
}

2-从基本视图模型继承:

public class ViewModel1:YourBaseViewModel
{    
  // .... 
}

public class ViewModel2:YourBaseViewModel
{    
  // .... 
}

编辑: 如果您还有其他基类,则可以:

public class YourBaseViewModel:YourReallyBaseViewModel
{ 
    // ....
}

public class ViewModel1:YourBaseViewModel
{    
      // .... 
}

public class ViewModel2:YourBaseViewModel
{    
      // .... 
}

答案 1 :(得分:2)

让您的两个视图模型都使用在别处定义的相同代码(理想情况下,都调用相同的接口,并注入依赖项注入),而不是拥有“基本”视图模型和两个派生的视图模型。

这是“继承之上的构成”原则。

在编写测试时,请测试两个视图模型都调用了该接口,并测试该接口的实现是否应该执行一次。

这样,您不仅可以避免编写两次代码,还可以避免对其进行两次测试,还可以遵循其他原则,例如单一责任原则。

答案 2 :(得分:2)

这是一个XY问题。您正在寻求一种解决Y的方法(实际上不是重复相同的ButtonCommand,但您的问题是X(您的代码中已经存在重复的代码)

  

我有两个相同的视图View1.xaml和View2.xaml

我想补充一点,您还说过您不仅有两个相同的视图,还有更多。

解决此问题的最佳方法是拥有可以构造子ViewModel的父ParentViewModel

因此,首先,我们需要一个用于子视图模型的接口

IMyViewModel

public interface IMyViewModel
{
    void Load(); 
}

接下来,实现

MyViewModel

public class MyViewModel : ViewModelBase, IMyViewModel
{
    public MainViewModel() 
    {
        ButtonCommand = new RelayCommand(ExecuteButtonCommand, CanExecuteButtonCommand);
    }

    public RelayCommand ButtonCommand { get; private set; }

    public void Load()
    {
        //Example load logic
        InvalidateCommands();
    }

    private void InvalidateCommands()
    {
        ButtonCommand.RaiseCanExecuteChanged();
    }

    private void ExecuteButtonCommand(object message)
    {
        //Some method to fill the corresponding textfield
    }

    private bool CanExecuteButtonCommand(object message)
    {
        return true;
    }
}

最后是ParentViewModel,它负责创建视图模型。请注意,当创建ViewModel时,我没有告诉过我,我将由您自己决定。

父视图模型

public class ParentViewModel : ViewModelBase 
{
    private Func<IMyViewModel> _myVmCreator;

    public ParentViewModel(Func<IMyViewModel> myVmCreator) 
    {
        _friendEditVmCreator = friendEditVmCreator;
    }

    public ObservableCollection<IMyViewModel> MyViewModels { get; private set; }

    private IMyViewModel CreateAndLoadMyViewModel()
    {
        var myVm = _myVmCreator();
        MyViewModels.Add(myVm);
        myVm.Load();
        return myVm;
    }
}

这将允许您创建任意数量的MyViewModels或任何其他类型的ViewModel,只要它实现IMyViewModel

以上示例是从本课程中获得的:https://www.pluralsight.com/courses/wpf-mvvm-test-driven-development-viewmodels

我强烈推荐。