在 MVVM 中单击按钮时清除 TextBox 的文本

Clear TextBox's text on button click in MVVM

我正在研究一个没有绑定文本的搜索框解决方案,因为我使用 Text 属性 作为搜索命令的参数。 那部分工作得很好。

现在我想使用 TextBox 末尾设置的“清除按钮”清除 TextBox 中的文本。

我尝试使用 EventTrigger,但是 StoryBoard 阻止了 Command 并且没有将文本设置为 nil。

下面是我的代码。 有什么想法吗?

<!--Search Box-->
<Grid Grid.Column="0">
    <TextBox x:Name="FilterText">
        <TextBox.InputBindings>
            <KeyBinding  Key="Enter" Command="{Binding FilterDataCommand}" CommandParameter="{Binding ElementName=FilterText, Path=Text}"/>
        </TextBox.InputBindings>
    </TextBox>
    <Button HorizontalAlignment="Right" Width="20" Height="20" Margin="5,0" Style="{StaticResource ButtonTransparentStyle}" Command="{Binding ClearSearchCommand}">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard>
                    <Storyboard>
                        <StringAnimationUsingKeyFrames Storyboard.TargetName="FilterText" Storyboard.TargetProperty="Text">
                            <DiscreteStringKeyFrame KeyTime="0:0:1" Value=""/>
                        </StringAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Button.Triggers>
        <Image Source="/VisionRanger;component/Images/Icons/icon.clear.dark.png" Stretch="UniformToFill" Margin="4,3,2,4" Opacity="0.5"/>
    </Button>
</Grid>
<!--Search Button-->
<Button Grid.Column="1"  Style="{StaticResource ButtonTransparentStyle}" Margin="5,0,0,0" Width="25" HorizontalAlignment="Left"
    Command="{Binding FilterDataCommand}" CommandParameter="{Binding ElementName=FilterText, Path=Text}">
    <Image Source="/VisionRanger;component/Images/Icons/icon.search.dark.png" Stretch="UniformToFill"/>
</Button>

Text 属性 不可设置动画,参见 Remarks in the documentation. In the reference source, the FrameworkPropertyMetadata is initialized with isAnimationProhibited 设置为 true

一个解决方案是将 MyFilterTextProperty 属性 绑定到 TwoWay 模式下 TextBoxText 属性(这是默认值)。

<TextBox Text="{Binding MyFilterTextProperty}"/>

然后在您的命令 ClearSearchCommand 中您可以清除 MyFilterTextProperty

public void ExecuteClearSearchCommand(/*...parameter.*/)
{
   MyFilterTextProperty = string.Empty;
   
   // ...other code.
}

另一种方法是使用自定义 TriggerAction 清除 TextBox。安装 Microsoft.Xaml.Behaviors.Wpf NuGet 包。像这样创建一个自定义触发器操作。它公开了 TextBox 可以绑定到的依赖项 属性 Target。如果发生事件,它将清除它。

public class ClearTextTriggerAction : TriggerAction<Button>
{
   public static TextBox GetTarget(DependencyObject obj)
   {
      return (TextBox)obj.GetValue(TargetProperty);
   }

   public static void SetTarget(DependencyObject obj, int value)
   {
      obj.SetValue(TargetProperty, value);
   }

   public static readonly DependencyProperty TargetProperty = DependencyProperty.RegisterAttached(
      "Target", typeof(TextBox), typeof(ClearTextTriggerAction), new PropertyMetadata(null));

   protected override void Invoke(object parameter)
   {
      GetTarget(this)?.Clear();
   }
}

在 XAML 中,您只需附加行为并绑定 FilterText

<Button HorizontalAlignment="Right" Width="20" Height="20" Margin="5,0" Style="{StaticResource ButtonTransparentStyle}" Command="{Binding ClearSearchCommand}">
    <b:Interaction.Triggers>
       <b:EventTrigger EventName="Click">
          <local:ClearTextTriggerAction Target="{Binding ElementName=FilterText}"/>
       </b:EventTrigger>
    </b:Interaction.Triggers>
    <Image Source="/VisionRanger;component/Images/Icons/icon.clear.dark.png" Stretch="UniformToFill" Margin="4,3,2,4" Opacity="0.5"/>
</Button>

必须包含 XAML 行为的 b XML 命名空间。

xmlns:b="http://schemas.microsoft.com/xaml/behaviors"

对我来说最明显的方法是创建自定义控件。但是我需要一些可以快速用于客户项目的东西,所以我创建了一种样式,利用按钮的属性来创建搜索“按钮”(当然还涉及其他样式),但它们不会改变基本原理使用过。

并且当有文本时,点击关闭按钮将清除它。

<!--#region Search Button-->
<Style
    x:Key="SearchButton"
    BasedOn="{StaticResource BaseStyle}"
    TargetType="{x:Type Button}">
    <Setter Property="Tag" Value="{StaticResource SearchIcon}" />
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ButtonBase}">
                <Border
                    x:Name="border"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    CornerRadius="5"
                    SnapsToDevicePixels="True">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>

                        <!--#region Search Icon-->
                        <Border
                            Grid.Column="0"
                            Margin="{TemplateBinding Padding}"
                            HorizontalAlignment="Center"
                            VerticalAlignment="Center">
                            <Button
                                Name="icon"
                                Background="{TemplateBinding Background}"
                                Command="{TemplateBinding Command}"
                                CommandParameter="{Binding Text, ElementName=text}"
                                Content="{TemplateBinding Tag}"
                                FontSize="{TemplateBinding FontSize}"
                                Foreground="{TemplateBinding Foreground}"
                                IsDefault="True"
                                Style="{StaticResource IconButton}" />
                        </Border>
                        <!--#endregion-->

                        <!--#region Text Box-->
                        <Border Grid.Column="1" Margin="5">
                            <TextBox
                                Name="text"
                                VerticalAlignment="Center"
                                HorizontalContentAlignment="Left"
                                VerticalContentAlignment="Center"                                  
                                ClipToBounds="True"
                                FontSize="{TemplateBinding FontSize}"
                                Foreground="{TemplateBinding Foreground}"
                                Style="{StaticResource TextBoxWithPlaceHolder}"
                                Tag="{TemplateBinding Content}"
                                TextWrapping="NoWrap">
                                <TextBox.InputBindings>
                                    <KeyBinding
                                        Key="Enter"
                                        Command="{TemplateBinding Command}"
                                        CommandParameter="{Binding Text, ElementName=text}" />
                                </TextBox.InputBindings>
                            </TextBox>
                        </Border>
                        <!--#endregion-->

                        <!--#region Close Icon-->
                        <Button
                            Name="close"
                            Grid.Column="2"
                            Margin="5"
                            FontSize="{TemplateBinding FontSize}"
                            Foreground="{TemplateBinding Foreground}"
                            IsCancel="True"
                            Style="{StaticResource CloseButtonStyle}">
                            <TextBlock FontFamily="{StaticResource IconSolid}" Text="{StaticResource CloseIcon}" />
                        </Button>
                        <!--#endregion-->

                    </Grid>
                </Border>

                <!--#region Triggers-->
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding Text, ElementName=text}" Value="">
                        <Setter TargetName="icon" Property="IsEnabled" Value="False" />
                        <Setter TargetName="close" Property="Visibility" Value="Collapsed" />
                    </DataTrigger>
                    <Trigger SourceName="close" Property="IsPressed" Value="True">
                        <Setter TargetName="text" Property="Text" Value="" />                           
                    </Trigger>
                </ControlTemplate.Triggers>
                <!--#endregion-->

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<!--#endregion-->

在代码中的任何一点,我定义一个按钮并在其上调用此样式,并绑定其命令。

<Button
       Width="400"
       Height="50"
       Margin="10"
       HorizontalAlignment="Left"
       Background="Transparent"
       Command="{Binding SearchCommand}"
       Style="{StaticResource SearchButton}" />

我相信有更好的方法可以做到这一点,但到目前为止这对我有用。