我创建了一个虚拟窗口
- 一个复选框
- a 按钮
- 自定义用户控件内的按钮
两个按钮都以蓝色开头,选中复选框后,它们都应变为橙色。但是,用户控件中的那个似乎忽略了该复选框。为什么它会失败,我该如何解决这个问题?
我要插入的用户控件:
<UserControl x:Class="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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
<Grid>
<!--MyContent is a dependency property in UserControl1's code behind-->
<ContentControl Content="{Binding MyContent}">
</Grid>
</UserControl>
主窗口:
<Window x:Class="WpfApplication11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="Background" Value="Cyan"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=myCheckbox, Path=isChecked}" Value="True">
<Setter Property="Background" Value="Orange/>
</DataTrigger>
</Style.Triggers>
</Style>
<Button x:Key="Button1" Content="Button1"/>
<Button x:Key="Button2" Content="Button2"/>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<CheckBox x:Name = "myCheckBox" Content="Turn Orange" Grid.Row="0"/>
<!--This updates when I check myCheckBox-->
<ContentControl Content = "{StaticResource Button1}" Grid.Row="2"/>
<!--This does NOT update when I check myCheckBox-->
<test:UserControl1 MyContent="{StaticResource Button2}" Grid.Row="2"/>
</Grid>
</Window>
为什么会失败
因为用户控件中没有名为"myCheckBox"的复选框。父窗口中的复选框驻留在另一个命名范围内,因此绑定到 ElementName 在此处不起作用。
我该如何解决这个问题?
学习并实现 MVVM 设计模式:https://msdn.microsoft.com/en-us/library/hh848246.aspx。这是开发基于 XAML 的 UI 应用程序时建议使用的设计模式。
创建保存复选框当前状态的视图模型类:
public class ViewModel : INotifyPropertyChanged
{
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set { _isChecked = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
并将窗口的 DataContext 设置为 this 的实例,并绑定到其 IsChecked 属性,而不是直接绑定到 CheckBox:
<Window ...>
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Cyan"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked}" Value="True">
<Setter Property="Background" Value="Orange"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Button x:Key="Button1" Content="Button1"/>
<Button x:Key="Button2" Content="Button2"/>
</Window.Resources>
<Window.DataContext>
<test:ViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<CheckBox x:Name ="myCheckBox" Content="Turn Orange" Grid.Row="0" IsChecked="{Binding IsChecked}"/>
<ContentControl Content = "{StaticResource Button1}" Grid.Row="1"/>
<test:UserControl2 MyContent="{StaticResource Button2}" Grid.Row="2"/>
</Grid>
</Window>
UserControl 应继承父窗口的 DataContext,因此不要在 UserControl1.xaml 中显式设置 DataContext 属性:
<UserControl x:Class="WpfApplication11.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:WpfApplication2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<ContentControl Content="{Binding MyContent, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</Grid>
</UserControl>
您不能从样式中引用 myCheckBox,这是两个不同的范围。此外,样式以按钮为目标,但控件是窗口。您必须将所有控件放在控件模板的样式中。