开发者

WPF - Apply a converter to all textboxes

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={StaticReso开发者_如何转开发urce 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!


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;

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜