简体   繁体   中英

How do I make a usercontrol update its own property?

I have a usercontrol in my WPF app that is basically a checkbox and textbox. I want the textbox to be disabled or enabled based on the checkbox state and the state be data bindable.

This is my usercontrol:

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="Enabled"
              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>

Codebehind

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);
    }
}

I have no idea how to tell the TextCheckBox to update its "IsEnabled" property when the checkbox is checked.

This is the XAML where I'm using TextCheckBox and the bindings are working correctly:

<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>

It seems odd that the TextBox is supposed to be enabled when a CheckBox with Content "Enabled" is not checked.

You probably just wanted to do it the other way round. Give the CheckBox a name and bind the TextBox's IsEnabled property to the IsChecked property of the CheckBox:

<CheckBox x:Name="checkBox" .../>
<TextBox IsEnabled="{Binding IsChecked, ElementName=checkBox}" .../>

If you really need to invert the logic, use an appropriate Binding Converter, or use a 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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM