如何让用户控件更新自己的 属性?
How do I make a usercontrol update its own property?
我的 WPF 应用程序中有一个用户控件,它基本上是一个复选框和文本框。我希望根据复选框状态禁用或启用文本框,并且该状态是数据可绑定的。
这是我的用户控件:
XAML
<UserControl x:Class="WpfApp.Views.Elements.TextCheckBox"
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="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox Content="Disabled"
IsChecked="{Binding CheckBoxChecked,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Row="1"
Grid.Column="1"
Margin="5,5,8,5"/>
<TextBox Text="{Binding TextBoxText,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
IsEnabled="{Binding TextBoxEnabled,
Mode=OneWay,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
Grid.Row="1"
Grid.Column="0"
Height="20"/>
</Grid>
</UserControl>
代码隐藏
using System.Windows;
using System.Windows.Controls;
namespace WpfApp.Views.Elements
{
/// <summary>
/// Interaction logic for TextCheckBox.xaml
/// </summary>
public partial class TextCheckBox : UserControl
{
public bool TextBoxEnabled => !CheckBoxChecked;
public string TextBoxText
{
get => (string)GetValue(TextBoxTextProperty);
set => SetValue(TextBoxTextProperty, value);
}
public bool CheckBoxChecked
{
get => (bool)GetValue(CheckBoxCheckedProperty);
set => SetValue(CheckBoxCheckedProperty, value);
}
public event DependencyPropertyChangedEventHandler TextPropertyChanged;
public static readonly DependencyProperty TextBoxTextProperty =
DependencyProperty.Register(nameof(TextBoxText), typeof(string), typeof(TextCheckBox), new PropertyMetadata(OnAnyPropertyChanged));
public static readonly DependencyProperty CheckBoxCheckedProperty =
DependencyProperty.Register(nameof(CheckBoxChecked), typeof(bool), typeof(CheckBoxInput), new PropertyMetadata(OnAnyPropertyChanged));
public TextCheckBox()
=> InitializeComponent();
static void OnAnyPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
=> (obj as TextCheckBox).OnAnyPropertyChanged(args);
void OnAnyPropertyChanged(DependencyPropertyChangedEventArgs args)
=> TextPropertyChanged?.Invoke(this, args);
}
}
我不知道如何告诉 TextCheckBox 在选中复选框时更新其“IsEnabled”属性。
这是我使用 TextCheckBox 并且绑定正常工作的 XAML:
<UserControl x:Class="WpfApp.Views.MyView"
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:other="clr-namespace:WpfApp.Other" xmlns:elements="clr-namespace:WpfApp.Views.Elements"
mc:Ignorable="d"
other:ViewModelLocator.AutoWireViewModel="True"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<elements:TextCheckBox
CheckBoxChecked="{Binding IsChecked,
Mode=OneWayToSource}"
TextBoxText="{Binding TextContent,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</UserControl>
编辑:
正如 Khiro 所建议的,我尝试使用依赖项 属性,其值在“CheckBoxChecked”的 setter 中设置。
这是更改后的代码隐藏(更改后的代码在上一行注释为“更改此处”):
using System.Windows;
using System.Windows.Controls;
namespace WpfApp.Views.Elements
{
/// <summary>
/// Interaction logic for TextCheckBox.xaml
/// </summary>
public partial class TextCheckBox : UserControl
{
// Change here.
public bool TextBoxEnabled => (bool)GetValue(TextBoxEnabledProperty);
public string TextBoxText
{
get => (string)GetValue(TextBoxTextProperty);
set => SetValue(TextBoxTextProperty, value);
}
public bool CheckBoxChecked
{
get => (bool)GetValue(CheckBoxCheckedProperty);
set
{
SetValue(CheckBoxCheckedProperty, value);
// Change here.
SetValue(TextBoxEnabledProperty, !value);
}
}
public event DependencyPropertyChangedEventHandler TextPropertyChanged;
// Change here.
public static readonly DependencyProperty TextBoxEnabledProperty =
DependencyProperty.Register(nameof(TextBoxEnabled), typeof(bool), typeof(CheckBoxInput), new PropertyMetadata(OnAnyPropertyChanged));
public static readonly DependencyProperty TextBoxTextProperty =
DependencyProperty.Register(nameof(TextBoxText), typeof(string), typeof(TextCheckBox), new PropertyMetadata(OnAnyPropertyChanged));
public static readonly DependencyProperty CheckBoxCheckedProperty =
DependencyProperty.Register(nameof(CheckBoxChecked), typeof(bool), typeof(CheckBoxInput), new PropertyMetadata(OnAnyPropertyChanged));
public TextCheckBox()
=> InitializeComponent();
static void OnAnyPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
=> (obj as TextCheckBox).OnAnyPropertyChanged(args);
void OnAnyPropertyChanged(DependencyPropertyChangedEventArgs args)
=> TextPropertyChanged?.Invoke(this, args);
}
}
但没有任何改变。单击复选框不会禁用文本框。此外,在“CheckBoxChecked”的 setter 中未命中断点。
然后我尝试了由 Clemens 提供的答案,我的用户控件的 XAML 变成了(这里只更改了部分):
<TextBox Text="{Binding TextBoxText,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
IsEnabled="{Binding TextBoxEnabled,
Mode=OneWay,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
Grid.Row="1"
Grid.Column="0"
Height="20">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=checkBox}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<CheckBox x:Name="checkBox"
Content="Newline"
IsChecked="{Binding CheckBoxChecked,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Row="1"
Grid.Column="1"
Margin="5,5,8,5"/>
但是,同样,没有任何反应。 :(
我在尝试任何建议之前撤消了所有更改,因此没有出现两个建议都有效的情况。
当 未 选中内容为“已启用”的复选框时,应该启用文本框似乎很奇怪。
您可能只是想反过来做。给 CheckBox 起个名字,然后把 TextBox 的 IsEnabled
属性 绑定到 CheckBox 的 IsChecked
属性:
<CheckBox x:Name="checkBox" .../>
<TextBox IsEnabled="{Binding IsChecked, ElementName=checkBox}" .../>
如果您确实需要反转逻辑,请使用适当的绑定转换器,或使用 DataTrigger:
<TextBox ...>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger
Binding="{Binding IsChecked, ElementName=checkBox}"
Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
我的 WPF 应用程序中有一个用户控件,它基本上是一个复选框和文本框。我希望根据复选框状态禁用或启用文本框,并且该状态是数据可绑定的。
这是我的用户控件:
XAML
<UserControl x:Class="WpfApp.Views.Elements.TextCheckBox"
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="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox Content="Disabled"
IsChecked="{Binding CheckBoxChecked,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Row="1"
Grid.Column="1"
Margin="5,5,8,5"/>
<TextBox Text="{Binding TextBoxText,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
IsEnabled="{Binding TextBoxEnabled,
Mode=OneWay,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
Grid.Row="1"
Grid.Column="0"
Height="20"/>
</Grid>
</UserControl>
代码隐藏
using System.Windows;
using System.Windows.Controls;
namespace WpfApp.Views.Elements
{
/// <summary>
/// Interaction logic for TextCheckBox.xaml
/// </summary>
public partial class TextCheckBox : UserControl
{
public bool TextBoxEnabled => !CheckBoxChecked;
public string TextBoxText
{
get => (string)GetValue(TextBoxTextProperty);
set => SetValue(TextBoxTextProperty, value);
}
public bool CheckBoxChecked
{
get => (bool)GetValue(CheckBoxCheckedProperty);
set => SetValue(CheckBoxCheckedProperty, value);
}
public event DependencyPropertyChangedEventHandler TextPropertyChanged;
public static readonly DependencyProperty TextBoxTextProperty =
DependencyProperty.Register(nameof(TextBoxText), typeof(string), typeof(TextCheckBox), new PropertyMetadata(OnAnyPropertyChanged));
public static readonly DependencyProperty CheckBoxCheckedProperty =
DependencyProperty.Register(nameof(CheckBoxChecked), typeof(bool), typeof(CheckBoxInput), new PropertyMetadata(OnAnyPropertyChanged));
public TextCheckBox()
=> InitializeComponent();
static void OnAnyPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
=> (obj as TextCheckBox).OnAnyPropertyChanged(args);
void OnAnyPropertyChanged(DependencyPropertyChangedEventArgs args)
=> TextPropertyChanged?.Invoke(this, args);
}
}
我不知道如何告诉 TextCheckBox 在选中复选框时更新其“IsEnabled”属性。
这是我使用 TextCheckBox 并且绑定正常工作的 XAML:
<UserControl x:Class="WpfApp.Views.MyView"
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:other="clr-namespace:WpfApp.Other" xmlns:elements="clr-namespace:WpfApp.Views.Elements"
mc:Ignorable="d"
other:ViewModelLocator.AutoWireViewModel="True"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<elements:TextCheckBox
CheckBoxChecked="{Binding IsChecked,
Mode=OneWayToSource}"
TextBoxText="{Binding TextContent,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</UserControl>
编辑:
正如 Khiro 所建议的,我尝试使用依赖项 属性,其值在“CheckBoxChecked”的 setter 中设置。
这是更改后的代码隐藏(更改后的代码在上一行注释为“更改此处”):
using System.Windows;
using System.Windows.Controls;
namespace WpfApp.Views.Elements
{
/// <summary>
/// Interaction logic for TextCheckBox.xaml
/// </summary>
public partial class TextCheckBox : UserControl
{
// Change here.
public bool TextBoxEnabled => (bool)GetValue(TextBoxEnabledProperty);
public string TextBoxText
{
get => (string)GetValue(TextBoxTextProperty);
set => SetValue(TextBoxTextProperty, value);
}
public bool CheckBoxChecked
{
get => (bool)GetValue(CheckBoxCheckedProperty);
set
{
SetValue(CheckBoxCheckedProperty, value);
// Change here.
SetValue(TextBoxEnabledProperty, !value);
}
}
public event DependencyPropertyChangedEventHandler TextPropertyChanged;
// Change here.
public static readonly DependencyProperty TextBoxEnabledProperty =
DependencyProperty.Register(nameof(TextBoxEnabled), typeof(bool), typeof(CheckBoxInput), new PropertyMetadata(OnAnyPropertyChanged));
public static readonly DependencyProperty TextBoxTextProperty =
DependencyProperty.Register(nameof(TextBoxText), typeof(string), typeof(TextCheckBox), new PropertyMetadata(OnAnyPropertyChanged));
public static readonly DependencyProperty CheckBoxCheckedProperty =
DependencyProperty.Register(nameof(CheckBoxChecked), typeof(bool), typeof(CheckBoxInput), new PropertyMetadata(OnAnyPropertyChanged));
public TextCheckBox()
=> InitializeComponent();
static void OnAnyPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
=> (obj as TextCheckBox).OnAnyPropertyChanged(args);
void OnAnyPropertyChanged(DependencyPropertyChangedEventArgs args)
=> TextPropertyChanged?.Invoke(this, args);
}
}
但没有任何改变。单击复选框不会禁用文本框。此外,在“CheckBoxChecked”的 setter 中未命中断点。
然后我尝试了由 Clemens 提供的答案,我的用户控件的 XAML 变成了(这里只更改了部分):
<TextBox Text="{Binding TextBoxText,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
IsEnabled="{Binding TextBoxEnabled,
Mode=OneWay,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
Grid.Row="1"
Grid.Column="0"
Height="20">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=checkBox}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<CheckBox x:Name="checkBox"
Content="Newline"
IsChecked="{Binding CheckBoxChecked,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Row="1"
Grid.Column="1"
Margin="5,5,8,5"/>
但是,同样,没有任何反应。 :(
我在尝试任何建议之前撤消了所有更改,因此没有出现两个建议都有效的情况。
当 未 选中内容为“已启用”的复选框时,应该启用文本框似乎很奇怪。
您可能只是想反过来做。给 CheckBox 起个名字,然后把 TextBox 的 IsEnabled
属性 绑定到 CheckBox 的 IsChecked
属性:
<CheckBox x:Name="checkBox" .../>
<TextBox IsEnabled="{Binding IsChecked, ElementName=checkBox}" .../>
如果您确实需要反转逻辑,请使用适当的绑定转换器,或使用 DataTrigger:
<TextBox ...>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger
Binding="{Binding IsChecked, ElementName=checkBox}"
Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>