是否可以在WPF中设置我们绑定TextBox值的属性?

6g8kf2rb  于 2023-05-01  发布在  其他
关注(0)|答案(2)|浏览(209)

我有一个复选框和一个文本框。当复选框取消勾选时,我希望文本框被禁用和清除,因此当用户点击保存时,一个空字符串应保存到文本框绑定的属性。然而,目前只有内容本身被删除。有没有一种方法可以改变我的代码绑定属性也会改变?我想同样的效果upon取消选中复选框,就好像用户删除了文本框内容的手。

<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
    <Setter Property="Text" Value="{Binding Path=Data.SomeValue, Mode=TwoWay}" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding ElementName=SomeCheckBox, Path=IsChecked}" Value="False">
            <Setter Property="IsEnabled" Value="False" />
            <Setter Property="Text" Value="{Binding x:Null}" />
        </DataTrigger>
    </Style.Triggers>
</Style>
</TextBox.Style>
gudnpqoy

gudnpqoy1#

我认为最干净的方法是在数据级别而不是在UI中处理。显然,CheckBox状态影响数据,而不仅仅是视觉表示。
根据您的上下文,您可以使用数据绑定或ICommand来触发数据源相应地更新其属性:

方案一

使用数据绑定并将CheckBox.IsChecked绑定到数据源。
另外,直接绑定TextBox.IsEnabled消除了DataTrigger,以进一步简化代码:

主窗口。xaml

<Window>
  <Window.DataContext>
    <DataSource /> 
  </Window.DataContext>

  <Stackpanel>
    <CheckBox IsChecked="{Binding IsSaveNameEnabled}" />
    <TextBox Text="{Binding Name}"
             IsEnabled="{Binding IsSaveNameEnabled}" />
  </StackPanel>
</Window>

DataSource。cs

// For simplicity the properties don't raise the INotifyPropertyChanged.PropertyChanged event
class DataSource : INotifyPropertyChanged
{
  private bool isSaveNameEnabled;
  public bool IsSaveNameEnabled 
  { 
    get => this.isSaveNameEnabled; 
    set
    {
      this.isSaveNameEnabled = value;
      OnPropertyChanged();
      OnIsSaveNameEnabledChanged();
    }
  }

  public string Name { get; set; }

  private void OnIsSaveNameEnabledChanged()
  {
    if (!this.IsSaveNameEnabled)
    {
      // Alternatively, instead of clearing the value
      // use the flag to explicitly ignore the related 
      // data value when persisting the data.
      // In this case the TextBox would show a greyed-out value.
      this.Name = string.Empty;
    }
  }
}

方案二

使用命令执行数据源中的数据相关逻辑。
同样,绑定TextBox.IsEnabled直接消除了DataTrigger,以进一步简化代码。
该示例使用ICommandRelayCommand实现。
您可以在Microsoft Docs中找到此类的源代码:继电器命令逻辑:

主窗口。xaml

<Window>
  <Window.DataContext>
    <DataSource /> 
  </Window.DataContext>

  <Stackpanel>
    <CheckBox x:Name="DisableTextInputButton" 
              Command="{Binding IgnoreNameValueCommand}" 
              CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" />
    <TextBox Text="{Binding Name}"
             IsEnabled="{Binding ElementName=DisableTextInputButton, Path=IsChecked}" />
  </StackPanel>
</Window>

DataSource。cs

// For simplicity the properties don't raise the INotifyPropertyChanged.PropertyChanged event
class DataSource : INotifyPropertyChanged
{
  public RelayCommand IgnoreNameValueCommand { get; }
    = new RelayCommand(ExecuteIgnoreNameValueCommand, CanExecuteIgnoreNameValueCommand);

  public string Name { get; set; }

  private bool CanExecuteIgnoreNameValueCommand(object commandParameter)
    => commandParameter is bool;

  private void ExecuteIgnoreNameValueCommand(object commandParameter)
  {
    bool isSaveNameEnabled = (bool)commandParameter;
    if (!isSaveNameEnabled)
    {
      // Alternatively, instead of clearing the value save the isSaveNameEnabled value
      // in a property and use it later to explicitly ignore the related 
      // data value when persisting the data.
      // In this case the TextBox would show a greyed-out value.
      this.Name = string.Empty;
    }
  }
}
j1dl9f46

j1dl9f462#

您遇到的问题是,使用<Setter Property="Text" Value="{x:Null}" />时,您会从ViewModel中删除与属性的绑定。
再次启用TextBox后,另一个样式Setter将再次将绑定设置为VM中未修改的值。财产。
你能做的就是在e中设置值。一种行为:

<TextBox x:Name="tb1" Margin="5" Text="{Binding Path=SomeStr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
    <i:Interaction.Behaviors>
        <yourBehaviorsXmlns:EmptyOnDisabled/>
    </i:Interaction.Behaviors>
    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=SomeCheckBox, Path=IsChecked}" Value="False">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

public class EmptyOnDisabled : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.IsEnabledChanged += AssociatedObject_IsEnabledChanged;
    }

    private void AssociatedObject_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (!AssociatedObject.IsEnabled)
        {
            AssociatedObject.Text = null;
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.IsEnabledChanged -= AssociatedObject_IsEnabledChanged;
    }
}

另一种方法是使用附加属性,如果它应该在其他条件下完成。更好的方法是在viewmodel中进行,在那里你应该存储复选框的状态。

<TextBox Margin="5" x:Name="tb1" attachedProps:ClearTextAttached.DontClearText="{Binding ElementName=SomeCheckBox, Path=IsChecked}">
    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Text" Value="{Binding Path=SomeStr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=SomeCheckBox, Path=IsChecked}" Value="False">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

public class ClearTextAttached
{
    public static bool GetDontClearText(DependencyObject obj)
    {
        return (bool)obj.GetValue(DontClearTextProperty);
    }

    public static void SetDontClearText(DependencyObject obj, bool value)
    {
        obj.SetValue(DontClearTextProperty, value);
    }
        
    public static readonly DependencyProperty DontClearTextProperty =
        DependencyProperty.RegisterAttached("DontClearText", typeof(bool), typeof(ClearTextAttached), new PropertyMetadata(false, ClearTextChanged));

    private static void ClearTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is TextBox tbx && !(bool)tbx.GetValue(ClearTextAttached.DontClearTextProperty))
        {
            tbx.Text = null;
        }
    }
}

相关问题