C# 窗口中的ViewModel和UserControl中的ViewModel之间的WPF数据绑定
我在这个窗口中使用了一个窗口和一个usercontrol 我已经做了以下工作:C# 窗口中的ViewModel和UserControl中的ViewModel之间的WPF数据绑定,c#,wpf,xaml,mvvm,data-binding,C#,Wpf,Xaml,Mvvm,Data Binding,我在这个窗口中使用了一个窗口和一个usercontrol 我已经做了以下工作: 将窗口属性绑定到窗口的viewmodel属性 将usercontrol属性绑定到usercontrol的viewmodel属性 将usercontrol属性绑定到窗口的viewmodel属性 在我看来,我认为如果按特定值设置window属性,usercontrol的viewmodel属性将设置为相同的值 但是usercontrol的viewmodel属性没有设置为相同的值 这是完整的代码 MainWindow.xam
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Window1 w = new Window1();
w.Mode = RegisterMode.Update;
w.Show();
}
}
Window1.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMTest2" x:Name="window" x:Class="MVVMTest2.Window1"
Title="Window1" Height="300" Width="300">
<Window.DataContext>
<local:WindowViewModel></local:WindowViewModel>
</Window.DataContext>
<Grid>
<local:UserControl1 x:Name="uc1" HorizontalAlignment="Left" Height="100" Margin="77,116,0,0" VerticalAlignment="Top" Width="100" Mode="{Binding DataContext.Mode, ElementName=window, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="156,43,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMTest2" x:Name="window" x:Class="MVVMTest2.Window1"
Title="Window1" Height="300" Width="300"
Mode={Binding UcViewModel.Mode}> <!-- Added this binding -->
<!-- MOVED THIS TO THE CODE-BEHIND
<Window.DataContext>
<local:WindowViewModel></local:WindowViewModel>
</Window.DataContext>
-->
<Grid>
<local:UserControl1 x:Name="uc1" HorizontalAlignment="Left" Height="100" Margin="77,116,0,0" VerticalAlignment="Top" Width="100"
Mode="{Binding UcViewModel.Mode}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="156,43,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
WindowViewModel.cs
public class WindowViewModel : INotifyPropertyChanged
{
RegisterMode mode = RegisterMode.None;
public event PropertyChangedEventHandler PropertyChanged;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class UCViewModel : INotifyPropertyChanged
{
RegisterMode mode = RegisterMode.None;
public event PropertyChangedEventHandler PropertyChanged;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class WindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/* Remove this:
RegisterMode mode = RegisterMode.None;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
*/
// Use composition instead
UCViewModel _ucViewModel = null;
public UCViewModel UcViewModel
{
get
{
if (_ucViewModel == null)
{
_ucViewModel = new UCViewModel();
}
return _ucViewModel;
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
UserControl1.xaml
<UserControl x:Class="MVVMTest2.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MVVMTest2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<local:UCViewModel></local:UCViewModel>
</UserControl.DataContext>
<Grid>
</Grid>
</UserControl>
<UserControl x:Class="MVVMTest2.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MVVMTest2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<!-- THIS PART IS NOT NEEDED
<UserControl.DataContext>
<local:UCViewModel></local:UCViewModel>
</UserControl.DataContext>
-->
<Grid>
</Grid>
</UserControl>
UCViewModel.cs
public class WindowViewModel : INotifyPropertyChanged
{
RegisterMode mode = RegisterMode.None;
public event PropertyChangedEventHandler PropertyChanged;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class UCViewModel : INotifyPropertyChanged
{
RegisterMode mode = RegisterMode.None;
public event PropertyChangedEventHandler PropertyChanged;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class WindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/* Remove this:
RegisterMode mode = RegisterMode.None;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
*/
// Use composition instead
UCViewModel _ucViewModel = null;
public UCViewModel UcViewModel
{
get
{
if (_ucViewModel == null)
{
_ucViewModel = new UCViewModel();
}
return _ucViewModel;
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
我做错了什么?
请让我知道。使用您的
视图模型之间的组合尝试此解决方案
Window1.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMTest2" x:Name="window" x:Class="MVVMTest2.Window1"
Title="Window1" Height="300" Width="300">
<Window.DataContext>
<local:WindowViewModel></local:WindowViewModel>
</Window.DataContext>
<Grid>
<local:UserControl1 x:Name="uc1" HorizontalAlignment="Left" Height="100" Margin="77,116,0,0" VerticalAlignment="Top" Width="100" Mode="{Binding DataContext.Mode, ElementName=window, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="156,43,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMTest2" x:Name="window" x:Class="MVVMTest2.Window1"
Title="Window1" Height="300" Width="300"
Mode={Binding UcViewModel.Mode}> <!-- Added this binding -->
<!-- MOVED THIS TO THE CODE-BEHIND
<Window.DataContext>
<local:WindowViewModel></local:WindowViewModel>
</Window.DataContext>
-->
<Grid>
<local:UserControl1 x:Name="uc1" HorizontalAlignment="Left" Height="100" Margin="77,116,0,0" VerticalAlignment="Top" Width="100"
Mode="{Binding UcViewModel.Mode}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="156,43,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
UserControl1.xaml
<UserControl x:Class="MVVMTest2.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MVVMTest2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<local:UCViewModel></local:UCViewModel>
</UserControl.DataContext>
<Grid>
</Grid>
</UserControl>
<UserControl x:Class="MVVMTest2.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MVVMTest2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<!-- THIS PART IS NOT NEEDED
<UserControl.DataContext>
<local:UCViewModel></local:UCViewModel>
</UserControl.DataContext>
-->
<Grid>
</Grid>
</UserControl>
WindowViewModel.cs
public class WindowViewModel : INotifyPropertyChanged
{
RegisterMode mode = RegisterMode.None;
public event PropertyChangedEventHandler PropertyChanged;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class UCViewModel : INotifyPropertyChanged
{
RegisterMode mode = RegisterMode.None;
public event PropertyChangedEventHandler PropertyChanged;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class WindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/* Remove this:
RegisterMode mode = RegisterMode.None;
public RegisterMode Mode
{
get { return this.mode; }
set
{
this.mode = value;
RaisePropertyChanged("Mode");
}
}
*/
// Use composition instead
UCViewModel _ucViewModel = null;
public UCViewModel UcViewModel
{
get
{
if (_ucViewModel == null)
{
_ucViewModel = new UCViewModel();
}
return _ucViewModel;
}
}
void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
还有一件事,您可能希望将ViewModel属性Mode
重命名为另一个名称,如RegMode
。原因是绑定过程中XAML代码会让人困惑
由此:
{绑定模式,模式=双向}
或者,这是:
{绑定路径=模式,模式=双向}
对于这个不那么令人困惑的问题:
{Binding RegMode,Mode=TwoWay}
您不应该显式设置UserControl的DataContext,因为这样做可以有效地防止DataContext从UserControl的父项继承。请参见此处示例:@Clemens那么如何更改构造函数中的绑定代码?请给我看一些东西。UserControl和Window1的构造函数中不应该有任何绑定代码。相反,当声明它们的实例时,它们的属性应该在XAML中绑定,例如
。绑定源将是从窗口继承的DataContext。@YHKim我只是想澄清一下您希望发生什么,您希望UCViewModel.Mode获得WindowViewModel.Mode中设置的值?@janonimus我想将模式值从Window1发送到UCViewModel。So MessageBox.Show((uc1.DataContext作为UCViewModel.Mode.ToString());应显示“更新”。感谢您的回答。这接近我想要的。