WPF 自定义控件将文本框文本重置为默认值
WPF Custom control reset textbox text to a default value
我需要一个带有按钮的文本框,它必须显示默认值,但仍应允许用户键入我需要存储在我的 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>
这是View中的用法
<StackPanel Width="400">
<remebervalue:RememberValue
DisplayText="{Binding DisplayText, UpdateSourceTrigger=PropertyChanged}"
DefaultValue="{Binding DefaultText, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left" Width="400" />
</StackPanel>
RemeberValue.cs ha DP 注册了 DisplayText 和 DefaultText
的代码
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;
}
部分回答
- 第一点:我相信你写错了“Binding is set two way”,因为你使用的是
TemplateBinding
,也就是always one-way。您应该将其替换为
Binding DisplayText, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay
- 第二点:由上面修正
- 第三点:不同的问题,需要在不同的问题中解决。
我需要一个带有按钮的文本框,它必须显示默认值,但仍应允许用户键入我需要存储在我的 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>
这是View中的用法
<StackPanel Width="400">
<remebervalue:RememberValue
DisplayText="{Binding DisplayText, UpdateSourceTrigger=PropertyChanged}"
DefaultValue="{Binding DefaultText, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left" Width="400" />
</StackPanel>
RemeberValue.cs ha DP 注册了 DisplayText 和 DefaultText
的代码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;
}
部分回答
- 第一点:我相信你写错了“Binding is set two way”,因为你使用的是
TemplateBinding
,也就是always one-way。您应该将其替换为
Binding DisplayText, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay
- 第二点:由上面修正
- 第三点:不同的问题,需要在不同的问题中解决。