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

时间:2010-05-31 17:03:44

标签: wpf converter controltemplate

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

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

但是,我们的TextBoxes使用带有控制模板的样式,如下所示:

<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>

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

1 个答案:

答案 0 :(得分:2)

任何从TextBox内部修改ControlTemplate属性的尝试都会很混乱,因此我建议您尽可能在Style而不是ControlTemplate进行修改。我将首先解释如何使用Style解释如何根据需要调整技术以便在ControlTemplate中使用。

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

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

ConverterInstaller类有一个简单的附加属性,可将转换器安装到Binding上最初设置的任何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中以更改Converter,因为原始Binding已被密封

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

找到TextBox