【发布时间】:2022-01-07 14:54:46
【问题描述】:
我的 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”的设置器中设置。
这是更改后的代码隐藏(更改后的代码在上一行用 cmets "Change here" 注释):
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”的设置器中没有命中断点。
然后我尝试了 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"/>
但是,再一次,什么也没发生。 :(
我在尝试任何建议之前撤消了所有更改,因此没有两个建议都有效的情况。
【问题讨论】:
-
问题是文本框不知道
TextBoxEnabled何时更改,因此解决方案是使其成为依赖属性(只读)并在CheckBoxChecked的设置器中设置其值,或者只是绑定到CheckBoxChecked并使用转换器来否定它的值。 -
@Khiro,谢谢,听起来不错,但我一定做错了什么。根据我对您的建议所做的更新答案。
-
请注意,
SetValue(TextBoxEnabledProperty, !value);方法将不起作用,因为依赖属性X的 CLR 包装器不得包含除SetValue(XProperty, value)之外的任何其他代码。 setter 可能会被框架绕过。 -
在所有情况下,是的。见XAML Loading and Dependency Properties。
-
在这种情况下,我想将
TextBoxEnabledProperty的设置移动到CheckBoxChecked的属性更改处理程序将解决该问题。 @K-RUSHer 请注意,您没有以正确的方式使用只读依赖属性,因为它仍然可以在课堂外的任何地方使用SetValue进行写入,请检查此answer 以了解正确的方式;)跨度>
标签: c# wpf user-controls