C# 如何测试需要协调用户控件的创建和宿主的ViewModel?
我正在进行一个演示MVVM项目,其中我有一个WPF主窗口和一个ViewModel,需要协调不同用户控件的创建和托管。如果ViewModel不应该包含WPF元素的任何部分,那么我不知道该怎么做。我知道这是一个相当广泛的设计问题,但我是WPF/TDD新手,我很难看到一条清晰的路径,即如何创建用户控件并将其绑定到ViewModel,而不必在ViewModel中使用一些创建和绑定代码 从我所读到的内容来看,在MainViewModel中公开绑定到ContentControl的UserControl属性不是一个好办法。如何在MainView模型中抽象出UserControls的创建和绑定,以便对其进行测试 工作但不可测试:C# 如何测试需要协调用户控件的创建和宿主的ViewModel?,c#,wpf,mvvm,C#,Wpf,Mvvm,我正在进行一个演示MVVM项目,其中我有一个WPF主窗口和一个ViewModel,需要协调不同用户控件的创建和托管。如果ViewModel不应该包含WPF元素的任何部分,那么我不知道该怎么做。我知道这是一个相当广泛的设计问题,但我是WPF/TDD新手,我很难看到一条清晰的路径,即如何创建用户控件并将其绑定到ViewModel,而不必在ViewModel中使用一些创建和绑定代码 从我所读到的内容来看,在MainViewModel中公开绑定到ContentControl的UserControl属性不
<ContentControl Grid.Row="2" Content="{Binding UserControl}" />
public class MainWindowViewModel
{
public void ShowHome()
{
SomeUserControl uc = new SomeUserControl();
uc.DataContext = new SomeUserControlViewModel();
UserControl = uc;
}
public void ShowKeypad()
{
SomeOtherUserControl uc = new SomeOtherUserControl();
uc.DataContext = new SomeOtherUserControlViewModel();
UserControl = uc;
}
public UserControl UserControl {get; private set;}
}
视图模型中不应包含任何具有MVVM模式的控件。视图模型只是要显示的数据的状态
例如:
要显示的记录
标题
形象
可以删除
可以编辑
在WPF中,控件可以绑定到这些属性以进行显示
视图模型是视图不可知的,它们不关心哪个视图在使用它。因此,它们中不会有对UI控件的实际引用
要测试实际的UI,可以编写编码的UI测试。在web应用程序中,有一个Selenium框架,允许您编写与浏览器中的UI组件交互的单元测试
我敢肯定,WPF UI测试也有类似的框架
编辑:有一个名为Appium的框架,允许您编写UI和底层MVVM设置之间的集成测试
视图模型中不应包含任何具有MVVM模式的控件。视图模型只是要显示的数据的状态
例如:
要显示的记录
标题
形象
可以删除
可以编辑
在WPF中,控件可以绑定到这些属性以进行显示
视图模型是视图不可知的,它们不关心哪个视图在使用它。因此,它们中不会有对UI控件的实际引用
要测试实际的UI,可以编写编码的UI测试。在web应用程序中,有一个Selenium框架,允许您编写与浏览器中的UI组件交互的单元测试
我敢肯定,WPF UI测试也有类似的框架
编辑:有一个名为Appium的框架,允许您编写UI和底层MVVM设置之间的集成测试
你可以做几件事 我创建了许多项目,其中启动时的视图创建了可见性设置为隐藏的控件。然后VM创建/拥有一个状态属性,该属性定义应用程序的不同状态。当该属性通过INotifyPropertyChanged更改时,屏幕上的控件会显示或隐藏自己 使用1或不使用1,可以创建视图可以处理但由VM或其他地方启动的命令。因此,保持关注点的分离 一, 定义枚举 关于VM定义状态
private OperationState _State;
public OperationState State
{
get => _State;
set { _State = value; OnPropertyChanged(nameof(State)); }
}
根据需要设置状态,例如state=Select
具有基于状态的控件可视性
<Control:AlignmentProcessing
ProjectContainer="{Binding CurrentContainer, Mode=TwoWay}"
Visibility="{Binding State, Converter={StaticResource VisibilityStateConverter},
ConverterParameter=Alignment}"/>
2否则,在VM上执行命令操作,例如:
public ICommand ShowControl1 { get; set; }
然后在视图上订阅命令,假设VM持有当前VM:
VM.ShowControl1 = new Commanding((o) =>
{
SomeUserControl uc = new SomeUserControl();
uc.DataContext = new SomeUserControlViewModel();
UserControl = uc;
}
然后,当从VM执行命令时,视图执行其工作
ShowControl1.Execute(null);
我在我的博客上提供了一个很好的例子,你可以做一些事情 我创建了许多项目,其中启动时的视图创建了可见性设置为隐藏的控件。然后VM创建/拥有一个状态属性,该属性定义应用程序的不同状态。当该属性通过INotifyPropertyChanged更改时,屏幕上的控件会显示或隐藏自己 使用1或不使用1,可以创建视图可以处理但由VM或其他地方启动的命令。因此,保持关注点的分离 一, 定义枚举 关于VM定义状态
private OperationState _State;
public OperationState State
{
get => _State;
set { _State = value; OnPropertyChanged(nameof(State)); }
}
根据需要设置状态,例如state=Select
具有基于状态的控件可视性
<Control:AlignmentProcessing
ProjectContainer="{Binding CurrentContainer, Mode=TwoWay}"
Visibility="{Binding State, Converter={StaticResource VisibilityStateConverter},
ConverterParameter=Alignment}"/>
2否则,在VM上执行命令操作,例如:
public ICommand ShowControl1 { get; set; }
然后在视图上订阅命令,假设VM持有当前VM:
VM.ShowControl1 = new Commanding((o) =>
{
SomeUserControl uc = new SomeUserControl();
uc.DataContext = new SomeUserControlViewModel();
UserControl = uc;
}
然后,当从VM执行命令时,视图执行其工作
ShowControl1.Execute(null);
我在我的博客上提供了一个命令式的例子,只需使用数据模板即可。让Wpf为您选择视图
<ContentControl Grid.Row="2" Content="{Binding UserControl}" />
public class MainWindowViewModel
{
public void ShowHome()
{
MyViewmodelChoosedInMain = new SomeViewModel();
}
public void ShowKeypad()
{
MyViewmodelChoosedInMain = new SomeOtherViewModel();
}
//better use an Interface instead of object type ;)
//you also need to implement and call INotifyPropertyChanged of course
public object MyViewmodelChoosedInMain {get; private set;}
}
//in your ResourceDictionary create the DataTemplates
<DataTemplate DataType="{x:Type SomeViewModel}">
<MySomeViewmodelView />
</DataTemplate>
<DataTemplate DataType="{x:Type SomeOtherViewModel}">
<MySomeOtherViewmodelView />
</DataTemplate>
只需使用数据模板。让Wpf为您选择视图
<ContentControl Grid.Row="2" Content="{Binding UserControl}" />
public class MainWindowViewModel
{
public void ShowHome()
{
MyViewmodelChoosedInMain = new SomeViewModel();
}
public void ShowKeypad()
{
MyViewmodelChoosedInMain = new SomeOtherViewModel();
}
//better use an Interface instead of object type ;)
//you also need to implement and call INotifyPropertyChanged of course
public object MyViewmodelChoosedInMain {get; private set;}
}
//in your ResourceDictionary create the DataTemplates
<DataTemplate DataType="{x:Type SomeViewModel}">
<MySomeViewmodelView />
</DataTemplate>
<DataTemplate DataType="{x:Type SomeOtherViewModel}">
<MySomeOtherViewmodelView />
</DataTemplate>
人们将MVVM视为一种宗教,而不是教条。它只是将GUI、业务处理和数据库之间的关注点分离开来。它过去被称为三层方法。因此,您希望您需要做什么才能使其工作,但要将主要组件保持在其层内;仅此而已。这是我的观点,我可能错了
人们把MVVM当作一种宗教,而不是教条。它只是将GUI、业务处理和数据库之间的关注点分离开来。它过去被称为三层方法。因此,您希望您需要做什么才能使其工作,但要将主要组件保持在其层内;仅此而已。这是我的观点,我可能错了。我已经能够按照您的指导原则测试所有的UserControl视图模型。我遇到的一个问题是MainView模型,我不知道该方法,因为它非常清楚需要创建和协调的视图。我以前使用过Selenium,但在本例中,我没有进行集成测试。我已经能够按照您的指导原则测试所有UserControl视图模型。我遇到的一个问题是MainView模型,我不知道该方法,因为它非常清楚需要创建和协调的视图。我以前使用过Selenium,但在本例中我没有进行集成测试。对于初学者来说,提及模板也可以位于页面资源或父控件的资源部分可能会有所帮助。最好的位置是app.xaml ResourceDictionary。我更喜欢这样:-对于初学者,提及模板也可以位于页面资源或父控件的资源部分可能会有所帮助。最好的位置是app.xaml ResourceDictionary。我更喜欢这样:-