WPF 自定义控件将文本框文本重置为默认值

Posted

技术标签:

【中文标题】WPF 自定义控件将文本框文本重置为默认值【英文标题】:WPF Custom control reset textbox text to a default value 【发布时间】:2021-11-08 17:36:50 【问题描述】:

我需要一个带有按钮的文本框,它必须显示默认值,但仍应允许用户输入我需要存储在 ViewModel 属性中的文本。 该按钮应将值重置为默认值。

我在这个实现中遇到了一些问题:

当用户在文本框中键入时,我希望我的 viewModel 中的绑定属性会相应更新,但似乎不再有绑定。 (绑定设置两种方式) (绑定和 DataContext 是正确的,因为加载时显示的是从 ViewModel 设置的值)

一旦我在框中键入并点击恢复按钮,文本将按预期分配给属性,但文本框仍由用户显示相同的值类型。

每次我在选项卡上移动或单击另一个控件时,负责将文本还原回来的按钮需要单击两次(看起来像焦点问题),因为一旦焦点位于文本框中,一切正常。

如果我定义了控制模板,我已经创建了一个 Generic.xaml。

 <Style x:Key="x:Type local:RememberValue" TargetType="x:Type local:RememberValue">
        <Setter Property="Background" Value="StaticResource RemeberValue_Background" />
        <Setter Property="BorderBrush" Value="StaticResource RemeberValue_Border" />
        <Setter Property="Foreground" Value="StaticResource RemeberValue_Foreground" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="Focusable" Value="True" />
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="FocusVisualStyle" Value="x:Null"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type local:RememberValue">
                    <Grid x:Name="LayoutGrid">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <baseControlUi:IconButton
                            Grid.Column="0"
                            Height="22"
                            Grid.ZIndex="1"
                            Margin="0"
                            EllipseDiameter="19"
                            Focusable="True"
                            Visibility="Binding ElementName=RememberValueControl, Path=IsDifferentValue, Converter=StaticResource BooleanToVisibilityConverter"
                            ButtonCommand="TemplateBinding RevertCommand"
                            ButtonIcon="StaticResource RevertIcon" />
                        <TextBox
                            Grid.ZIndex="0"
                            Foreground="StaticResource RemeberValue_Foreground"
                            Text="TemplateBinding DisplayText"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Center" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

这是视图中的用法。

<StackPanel Width="400">
  <remebervalue:RememberValue
    DisplayText="Binding DisplayText, UpdateSourceTrigger=PropertyChanged"
    DefaultValue="Binding DefaultText, UpdateSourceTrigger=PropertyChanged"
    HorizontalAlignment="Left" Width="400" />
</StackPanel>

RemeberValue.cs 后面的代码为 DisplayText 和 DefaultText 注册了 DP

public static readonly DependencyProperty DisplayTextProperty =
            DependencyProperty.Register(nameof(DisplayText), typeof(string), typeof(RememberValue), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDisplayText_Changed));

public RememberValue()

    RevertCommand = new SimpleCommand(Revert);


private void Revert()

    DisplayText = DefaultValue;

    
public string DisplayText

 get => (string)GetValue(DisplayTextProperty);
 set => SetValue(DisplayTextProperty, value);
 

private static void OnDisplayText_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)

    RememberValue RememberValue = d as RememberValue;


【问题讨论】:

感谢重播我已编辑问题。 ontext changed 方法目前是“空的”。 我认为DisplayText 属性和OnDisplayText_Changed() 方法没有问题。如果你没有在里面放任何东西,你可以删除这个方法,创建FrameworkPropertyMetadata不是强制性的。不过,您可能想添加OnPropertyChanged(nameof(IsDifferentValue))。您是否有一个 ViewModel,其中有 DisplayTextDefaultText 属性?名称 DefaultTextDefaultValue 之间的差异是故意的吗?在调试中运行项目时,输出窗口中是否没有错误? 我知道现在不使用了,我会删除它。你是对的,是复制和粘贴错误。我将其更改为 DisplayText = DefaultText;目前剩下的问题只是在需要单击两次才能触发命令的控件上。而且我仍然认为问题出在焦点上,这可能是我使用 z 索引的事实吗? 我很少用z-index,所以不知道。您可以尝试删除它,并在 XAML 中将 IconButton 移动到 TextBox 之后吗?如果这不能解决您的问题,那么在网格中添加一列并将按钮移动到该列,或者将 Grid 更改为 StackPanel 怎么样? 如果在 agrid 中有或没有 z 索引的面板中没有变化,我认为查看焦点是我设法提高可用性的正确方法。设置这个。 这让我可以立即单击按钮,但是一旦我切换选项卡控件,就会触发丢失焦点事件,我仍然需要再次单击按钮两次。 【参考方案1】:

部分回答

第一点:我相信你写错了“Binding is set two way”,因为你使用的是TemplateBinding,即always one-way。您应该将其替换为
Binding DisplayText, RelativeSource=RelativeSource TemplatedParent, Mode=TwoWay
第二点:由上述固定 第三点:不同的问题,需要在不同的问题中解决。

【讨论】:

刚刚测试了您的示例并且正在运行,现在绑定是 2 方式。 (真实)。

以上是关于WPF 自定义控件将文本框文本重置为默认值的主要内容,如果未能解决你的问题,请参考以下文章

将 WPFToolkit DatePickerTextBox 控件重写为自定义组合框控件

在 wpf 中的自定义样式上,文本框的文本始终为空

WPF自定义控件与样式-TextBox & RichTextBox & PasswordBox样式水印Label标签功能扩展

form

C#WPF - 创建自定义控件。不确定如何正确对齐文本

vs2008时间控件设置默认值