我有两个相同的视图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}" />
这很糟糕,因为我必须为两个ViewModels编写相同的代码。我试图创建一个从RelayCommand继承的类ButtonCommand
,但是因为并非每个视图都具有此功能,所以无法使用此方法来实现它。
答案 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
因此,首先,我们需要一个用于子视图模型的接口
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;
}
}
最后是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
我强烈推荐。