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 - Fatal编程技术网

C# 对多个视图使用相同的命令

C# 对多个视图使用相同的命令,c#,wpf,mvvm,C#,Wpf,Mvvm,我有两个相同的视图View1.xaml和View2.xaml,它们都有一个按钮button1和一个文本字段textfield1。这个想法是,当您按下按钮时,相应的文本字段将填充一些信息。两个视图都使用相同的方法填充文本字段(从这个意义上说,两个视图完全相同) 我的问题是:如何使用OOP原则编写通用代码而不破坏MVVM模式?我当前使用RelayCommand执行此操作的方式: ViewModel1和ViewModel2的代码相同: public RelayCommand ButtonCommand

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

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

ViewModel1
ViewModel2
的代码相同:

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.xaml
View2.xaml
中的按钮绑定:

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


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

这可能是一种方法:

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-从基础viewmodel继承:

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

public class ViewModel2:YourBaseViewModel
{    
  // .... 
}
编辑: 如果您有另一个基类,则可以执行以下操作:

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

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

public class ViewModel2:YourBaseViewModel
{    
      // .... 
}
与其有一个“基本”视图模型和两个派生视图模型,不如让您的两个视图模型都使用在别处定义的相同代码(理想情况下,都调用相同的接口,并注入依赖项注入)

这是组合优先于继承的原则

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


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

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

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

我想补充一点,你也说过你并不是只有两个相同的视图,还有更多

解决此问题的最佳方法是使用可以构造子视图模型的父视图模型

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

IMyViewModel 其次是实施

MyViewModel 最后是负责创建视图模型的
ParentViewModel
。请注意,我没有告诉它什么时候创建ViewModels,我将留给您

父视图模型 公共类ParentViewModel:ViewModelBase { 私人Func_myVmCreator; 公共ParentViewModel(Func myVmCreator) { _friendEditVmCreator=friendEditVmCreator; } 公共ObservableCollection MyViewModels{get;private set;} 私有IMyViewModel CreateAndLoadMyViewModel() { var myVm=_myVmCreator(); 添加(myVm); myVm.Load(); 返回myVm; } }
这将允许您创建任意数量的
MyViewModels
,或任何其他类型的ViewModel,只要它实现了
IMyViewModel

上述示例源自本课程:


我强烈推荐。

将文本框的Text属性绑定到同一个ViewModel(您可以为具有此属性的ViewModels创建基类)属性。为什么不能对两个视图使用完全相同的视图模型类?不能对两个不同的视图使用相同的
ViewModel
,因为您破坏了模式,而且它具有“可读性”。如果你有
MyView
,按照惯例,它的虚拟机是
MyViewModel
而不是
MyOtherViewModel
@Babbillumpa我已经有了
ViewModelBase
,问题是不是每个
ViewModel
都有这个功能,因此,我只能执行另一个基类,该基类将继承自
ViewModelBase
,然后由这些
ViewModels
@karolyz进行扩展,是什么阻止了您这样做?不幸的是,这不会起作用,因为如果我有
view3.xaml
,那么,它具有与新的
命令关联的
按钮
文本字段
,并在现有的
视图2中添加相同的
按钮
文本字段
,然后
视图2.xaml必须扩展两个基类,依此类推。换句话说,如果
view2
具有
view1
view3
的功能,它将不起作用,但是
view1
view3
将完全不同。@karolyz和“new command”您的意思是相同的命令但不同的执行操作?Exmaple:
view1
的按钮负责生成一个随机数,
view3
的按钮负责生成一个随机字符串。现在,如果
view2
有两个按钮,一个用于生成字符串,一个用于数字,这将不再起作用,因为view2现在必须有另一个类来扩展这两个功能。如果我理解正确,你是说有一个包含该方法的命令及其注入的接口?然后viewmodels会简单地调用接口?实际的命令是视图模型的属性,因此它们可以绑定到。为命令执行的代码只能调用另一个类上的方法。两个视图模型都可以使用该类而不共享基类。是的,这可能是在这种情况下的方法。回到这个答案,这可能是我读过的堆栈溢出中最重要的一个答案。谢谢,它改变了我看待软件开发的方式,让我学到了各种新概念。这无疑也是这个问题的最佳答案,这是我当时一直在寻找的。谢谢你这么广泛的回答,我很高兴
public interface IMyViewModel
{
    void Load(); 
}
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;
    }
}
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;
    }
}