WPF - 将转换器应用于所有文本框

发布于 2024-09-04 08:19:14 字数 978 浏览 3 评论 0原文

使用 WPF,我想在所有 TextBox 内的 Text 属性的绑定中应用转换器。
以下内容适用于单个文本框:

<TextBox Style="{StaticResource TextBoxStyleBase2}" 
                             Text="{Binding Text, Converter={StaticResource MyConverter}}">
                    </TextBox>

但是,我们的文本框使用带有控件模板的样式,如下所示:

<Grid>
            <Border x:Name="Border"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    CornerRadius="{StaticResource DefaultCornerRadius}">
                <Grid>
                    <Border BorderThickness="1">
                        <ScrollViewer x:Name="PART_ContentHost" Margin="0"/>
                    </Border>
                </Grid>
            </Border>
        </Grid>

如何使用此模板应用我的转换器? 谢谢!

Using WPF, I want to apply a converter within the binding of the Text property within all my TextBoxes.
The following works for a single TextBox:

<TextBox Style="{StaticResource TextBoxStyleBase2}" 
                             Text="{Binding Text, Converter={StaticResource MyConverter}}">
                    </TextBox>

However, our TextBoxes uses a style with a Control Template that looks like this:

<Grid>
            <Border x:Name="Border"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    CornerRadius="{StaticResource DefaultCornerRadius}">
                <Grid>
                    <Border BorderThickness="1">
                        <ScrollViewer x:Name="PART_ContentHost" Margin="0"/>
                    </Border>
                </Grid>
            </Border>
        </Grid>

How can I apply my converter using this Template?
Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

廻憶裏菂餘溫 2024-09-11 08:19:14

任何从 ControlTemplate 内部修改 TextBox 属性的尝试都会很混乱,因此我建议您在 Style 而不是 中进行操作。 ControlTemplate 如果可能的话。我将首先解释如何使用 Style 执行此操作,然后解释如何在必要时调整该技术以在 ControlTemplate 中使用。

您需要做的是创建一个可以像这样使用的附加属性:

<Style x:Name="TextBoxStyleBase2" TargetType="TextBox">
  <Setter Property="local:ConverterInstaller.TextPropetyConverter"
          Value="{StaticResource MyConverter}" />
  ...
</Style>

ConverterInstaller 类有一个简单的附加属性,它将转换器安装到最初在TextBox

public class ConverterInstaller : DependencyObject
{
  public static IValueConverter GetTextPropertyConverter(DependencyObject obj) { return (IValueConverter)obj.GetValue(TextPropertyConverterProperty); }
  public static void SetTextPropertyConverter(DependencyObject obj, IValueConverter value) { obj.SetValue(TextPropertyConverterProperty, value); }
  public static readonly DependencyProperty TextPropertyConverterProperty = DependencyProperty.RegisterAttached("TextPropertyConverter", typeof(IValueConverter), typeof(Converter), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
      {
        var box = (TextBox)obj;
        box.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
          {
            var binding = BindingOperations.GetBinding(box, TextBox.TextProperty);
            if(binding==null) return;

            var newBinding = new Binding
            {
              Converter = GetTextPropertyConverter(box),

              Path = binding.Path,
              Mode = binding.Mode,
              StringFormat = binding.StringFormat,
            }
            if(binding.Source!=null) newBinding.Source = binding.Source;
            if(binding.RelativeSource!=null) newBinding.RelativeSource = binding.RelativeSource;
            if(binding.ElementName!=null) newBinding.ElementName = binding.ElementName;

            BindingOperations.SetBinding(box, TextBox.TextProperty, newBinding);
          }));
      }
  });
}

这里唯一的复杂性是:

  • 使用 Dispatcher.BeginInvoke 来确保在 XAML 完成加载并应用所有样式后进行绑定更新,并且
  • 需要将 Binding 属性复制到新的 Binding 中更改转换器,因为原始 Binding 已密封

要将此属性附加到 ControlTemplate 内的元素而不是在样式中执行此操作,请使用相同的代码,除了传递到 PropertyChangedCallback 的原始对象被强制转换 var element = ( FrameworkElement)obj; 并在 Dispatcher.BeginInvoke 操作中使用 var box = (TextBox)element.TemplatedParent; 找到实际的 TextBox

Any attempt to modify TextBox properties from inside the ControlTemplate will be messy, so I recommend you do it in the Style instead of the ControlTemplate if at all possible. I'll start by explaining how to do it with a Style then explain how to adapt the technique for use in a ControlTemplate if necessary.

What you need to do is create an attached property that can be used like this:

<Style x:Name="TextBoxStyleBase2" TargetType="TextBox">
  <Setter Property="local:ConverterInstaller.TextPropetyConverter"
          Value="{StaticResource MyConverter}" />
  ...
</Style>

The ConverterInstaller class has a simple attached property that installs the converter into any Binding initially set on the TextBox:

public class ConverterInstaller : DependencyObject
{
  public static IValueConverter GetTextPropertyConverter(DependencyObject obj) { return (IValueConverter)obj.GetValue(TextPropertyConverterProperty); }
  public static void SetTextPropertyConverter(DependencyObject obj, IValueConverter value) { obj.SetValue(TextPropertyConverterProperty, value); }
  public static readonly DependencyProperty TextPropertyConverterProperty = DependencyProperty.RegisterAttached("TextPropertyConverter", typeof(IValueConverter), typeof(Converter), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
      {
        var box = (TextBox)obj;
        box.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
          {
            var binding = BindingOperations.GetBinding(box, TextBox.TextProperty);
            if(binding==null) return;

            var newBinding = new Binding
            {
              Converter = GetTextPropertyConverter(box),

              Path = binding.Path,
              Mode = binding.Mode,
              StringFormat = binding.StringFormat,
            }
            if(binding.Source!=null) newBinding.Source = binding.Source;
            if(binding.RelativeSource!=null) newBinding.RelativeSource = binding.RelativeSource;
            if(binding.ElementName!=null) newBinding.ElementName = binding.ElementName;

            BindingOperations.SetBinding(box, TextBox.TextProperty, newBinding);
          }));
      }
  });
}

The only complexity here is:

  • The use of Dispatcher.BeginInvoke to ensure the binding update happens after the XAML finishes loading and all styles are applied, and
  • The need to copy Binding properties into a new Binding to change the Converter, since the original Binding is sealed

To attach this property to an element inside the ControlTemplate instead of doing it in the style, the same code is used except the original object passed into the PropertyChangedCallback is cast var element = (FrameworkElement)obj; and inside the Dispatcher.BeginInvoke action the actual TextBox is found with var box = (TextBox)element.TemplatedParent;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文