C# 如何在WPF中使用多个ViewModel并通过一个MainViewModel绑定它们?
我在通过MainViewModel将2个ViewModels绑定到一个视图时遇到了麻烦 My MainWindow.xaml如下所示:C# 如何在WPF中使用多个ViewModel并通过一个MainViewModel绑定它们?,c#,wpf,xaml,data-binding,C#,Wpf,Xaml,Data Binding,我在通过MainViewModel将2个ViewModels绑定到一个视图时遇到了麻烦 My MainWindow.xaml如下所示: <Window x:Class="Dojo4.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ViewM
<Window x:Class="Dojo4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:Dojo4.ViewModels"
Title="Dojo4" Height="346" Width="706">
<Window.DataContext>
<ViewModels:MainViewModel/>
</Window.DataContext>
<Grid>
<Button Content="Register" DataContext="{Binding RegisterViewModel}" Command="{Binding Register}" HorizontalAlignment="Left" Margin="19,63,0,0" VerticalAlignment="Top" Width="75"/>
<Label Content="Registration Name
" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="25"/>
<Label Content="Field Size" HorizontalAlignment="Left" Margin="161,10,0,0" VerticalAlignment="Top" Height="25"/>
<Label Content="X" HorizontalAlignment="Left" Margin="161,35,0,0" VerticalAlignment="Top" Height="25"/>
<Label Content="Y" HorizontalAlignment="Left" Margin="203,35,0,0" VerticalAlignment="Top" Height="25"/>
<TextBox DataContext="{Binding RegisterViewModel}" Text="{Binding Name}" MaxLength="8" HorizontalAlignment="Left" Height="23" Margin="19,35,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox DataContext="{Binding RegisterViewModel}" HorizontalAlignment="Left" Height="23" Margin="161,62,0,0" TextWrapping="Wrap" Text="{Binding X}" VerticalAlignment="Top" Width="23"/>
<TextBox DataContext="{Binding RegisterViewModel}" HorizontalAlignment="Left" Height="23" Margin="203,62,0,0" TextWrapping="Wrap" Text="{Binding Y}" VerticalAlignment="Top" Width="23"/>
<Button Content="Up" DataContext="{Binding PlayerControlViewModel}" Command="{Binding MovePlayer}" CommandParameter="up" HorizontalAlignment="Left" Margin="79,118,0,0" VerticalAlignment="Top" Width="75" IsEnabled="False"/>
<Button Content="Down" DataContext="{Binding PlayerControlViewModel}" Command="{Binding MovePlayer}" CommandParameter="down" HorizontalAlignment="Left" Margin="79,226,0,0" VerticalAlignment="Top" Width="75" IsEnabled="False"/>
<Button Content="Left" DataContext="{Binding PlayerControlViewModel}" Command="{Binding MovePlayer}" CommandParameter="left" HorizontalAlignment="Left" Margin="10,173,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="0.707,0.409" IsEnabled="False"/>
<Button Content="Right" DataContext="{Binding PlayerControlViewModel}" Command="{Binding MovePlayer}" CommandParameter="right" HorizontalAlignment="Left" Margin="145,173,0,0" VerticalAlignment="Top" Width="75" IsEnabled="False"/>
</Grid>
namespace Dojo4.ViewModels
{
class MainViewModel : BaseViewModel
{
private RegistrationViewModel _RegistrationViewModel;
public RegistrationViewModel RegistrationViewModel
{
get { return _RegistrationViewModel; }
}
private PlayerControlViewModel _PlayerControlViewModel;
public PlayerControlViewModel PlayerControlViewModel
{
get { return _PlayerControlViewModel; }
}
private GameModel _game;
public MainViewModel()
{
_game = new GameModel();
_PlayerControlViewModel = new PlayerControlViewModel(_game);
_RegistrationViewModel = new RegistrationViewModel(_game);
}
}
}
运行程序后,绑定将失败,并出现以下错误:
System.Windows.Data错误:40:BindingExpression路径错误:“在对象”“MainViewModel'(HashCode=51295333)”上找不到“Register”属性。BindingExpression:Path=Register;DataItem='MainViewModel'(HashCode=51295333);目标元素是“按钮”(名称=“”);目标属性为“Command”(类型为“ICommand”)
System.Windows.Data错误:40:BindingExpression路径错误:在“对象”“MainViewModel”(HashCode=51295333)“上找不到RegisterViewModel”属性。BindingExpression:Path=RegisterViewModel;DataItem='MainViewModel'(HashCode=51295333);目标元素是“按钮”(名称=“”);目标属性为“DataContext”(类型为“Object”)
System.Windows.Data错误:40:BindingExpression路径错误:在“对象”“MainViewModel”(HashCode=51295333)“上找不到RegisterViewModel”属性。BindingExpression:Path=RegisterViewModel;DataItem='MainViewModel'(HashCode=51295333);目标元素是“TextBox”(名称=“”);目标属性为“DataContext”(类型为“Object”)
System.Windows.Data错误:40:BindingExpression路径错误:在“对象”“MainViewModel”(HashCode=51295333)“上找不到RegisterViewModel”属性。BindingExpression:Path=RegisterViewModel;DataItem='MainViewModel'(HashCode=51295333);目标元素是“TextBox”(名称=“”);目标属性为“DataContext”(类型为“Object”)
System.Windows.Data错误:40:BindingExpression路径错误:在“对象”“MainViewModel”(HashCode=51295333)“上找不到RegisterViewModel”属性。BindingExpression:Path=RegisterViewModel;DataItem='MainViewModel'(HashCode=51295333);目标元素是“TextBox”(名称=“”);目标属性为“DataContext”(类型为“Object”)
System.Windows.Data错误:40:BindingExpression路径错误:“在”“对象”“PlayerControlViewModel'(HashCode=65331996)”上找不到MovePlayer属性。BindingExpression:Path=MovePlayer;DataItem='PlayerControlViewModel'(HashCode=65331996);目标元素是“按钮”(名称=“”);目标属性为“Command”(类型为“ICommand”)
System.Windows.Data错误:40:BindingExpression路径错误:“在”“对象”“PlayerControlViewModel'(HashCode=65331996)”上找不到MovePlayer属性。BindingExpression:Path=MovePlayer;DataItem='PlayerControlViewModel'(HashCode=65331996);目标元素是“按钮”(名称=“”);目标属性为“Command”(类型为“ICommand”)
System.Windows.Data错误:40:BindingExpression路径错误:“在”“对象”“PlayerControlViewModel'(HashCode=65331996)”上找不到MovePlayer属性。BindingExpression:Path=MovePlayer;DataItem='PlayerControlViewModel'(HashCode=65331996);目标元素是“按钮”(名称=“”);目标属性为“Command”(类型为“ICommand”)
System.Windows.Data错误:40:BindingExpression路径错误:“在”“对象”“PlayerControlViewModel'(HashCode=65331996)”上找不到MovePlayer属性。BindingExpression:Path=MovePlayer;DataItem='PlayerControlViewModel'(HashCode=65331996);目标元素是“按钮”(名称=“”);目标属性为“Command”(类型为“ICommand”)
看起来,DataContext
无法通过MainViewModel
绑定到ViewModels
,我会尝试以下几件事:
首先我会尝试将一些xaml提取到它自己的视图(usercontrols/pages)中。这里的问题是,您有单独的视图模型,但没有单独的视图。大多数时候,我尝试将我的主窗口用作容纳其他视图的容器,我尝试使用单一责任原则,这基本上意味着类/方法只做一件事,只做一件事。我可以为每个视图模型创建一个视图。我想我会尝试将您的观点设置为:
因此,创建两个用户控件:(RegisterControl和PlayerControl)
您可能需要实现INotifyPropertyChange,以便在更改这些值时通知视图进行更新。为什么要更改这些值?假设您想在不同的时间显示不同的视图,那么您可以创建一个名为IView的界面,并将属性更改为:
public IView RegisterView { get; set; }
public IView PlayerControlView { get; set; }
如果这些都不起作用或对您来说没有意义,我唯一能想到的是您现在的设置方式可能是因为您没有通知viewmodels上的属性更改(INotifyPropertyChanged)。同样,尽管我不喜欢按您的方式设置数据上下文。希望这至少能帮上一点忙。你可以试试下面的方法 不要将DataContext设置为每个控件,而是在绑定过程中按如下方式自绑定实例中的属性
<Button Content="Register" Command="{Binding RegisterViewModel.Register}" HorizontalAlignment="Left" Margin="19,63,0,0" VerticalAlignment="Top" Width="75"/>
因为UI中有很多控件,所以首先从一个控件开始,注释掉所有其他控件,如果一个控件有效,那么您将清楚如何为其他控件执行此操作。其他明智的编译器将显示许多难以通过错误检查的错误您的代码中有输入错误:RegisterViewModel vs RegistrationViewModel。但还有其他问题: 这个代码有问题吗
DataContext=“{Binding RegisterViewModel}”Command=“{Binding Register}”
是指,可以在DataContext绑定之前计算Command属性上的绑定
只需将IsAsync=True添加到命令绑定:
<Button DataContext="{Binding RegisterViewModel}"
Command="{Binding Register, IsAsync=True}" />
当您绑定datacontext并同时绑定同一元素的另一个属性(例如Command属性)时,应将IsAsync=True设置为除datacontext之外的所有绑定,以便更早地对datacontext进行计算
但是,您应该避免在元素上设置datacontext,因为其他属性也绑定在元素上:
<Button Command="{Binding RegisterViewModel.Register}" />
由于将多个元素数据绑定到同一个viewmodel,因此应该按viewmodel将它们分组到根元素,这样代码更具可读性和maintanab
<Button DataContext="{Binding RegisterViewModel}"
Command="{Binding Register, IsAsync=True}" />
<Button Command="{Binding RegisterViewModel.Register}" />
<Grid DataContext="{Binding RegisterViewModel}" >
<Button Command="{Binding Register}" />
<Label Content="Registration Name
"/>
<Label Content="Field Size" />
<Label Content="X" />
<Label Content="Y" />
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding X}" />
<TextBox Text="{Binding Y}" />
</Grid>
<Grid DataContext="{Binding PlayerControlViewModel}">
<Button Command="{Binding MovePlayer}" CommandParameter="up" />
<Button Command="{Binding MovePlayer}" CommandParameter="down"/>
<Button Command="{Binding MovePlayer}" CommandParameter="left" />
<Button Command="{Binding MovePlayer}" CommandParameter="right" />
</Grid>