【问题标题】:WPF Custom control reset textbox text to a default valueWPF 自定义控件将文本框文本重置为默认值
【发布时间】: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 索引的面板中没有变化,我认为查看焦点是我设法提高可用性的正确方法。设置这个。 这让我可以立即单击按钮,但是一旦我切换选项卡控件,就会触发丢失焦点事件,我仍然需要再次单击按钮两次。

标签: c# wpf mvvm user-controls


【解决方案1】:

部分回答

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

【讨论】:

  • 刚刚测试了您的示例并且正在运行,现在绑定是 2 方式。 (真实)。
猜你喜欢
  • 1970-01-01
  • 2019-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多