自定义控件动态更新文本属性

Custom control dynamically update text properties

我有一个基于按钮的自定义控件,可以包含如下文本:

public class TextButtonControl : Button
{
    public bool AllCaps
    {
        get => (bool)GetValue(AllCapsProperty);
        set => SetValue(AllCapsProperty, value);
    }
    public static readonly DependencyProperty AllCapsProperty =
        DependencyProperty.Register("AllCaps", typeof(bool), typeof(TextButtonControl), new PropertyMetadata(false));

    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(TextButtonControl), new PropertyMetadata(""));

    static TextButtonControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(TextButtonControl), new FrameworkPropertyMetadata(typeof(TextButtonControl)));
    }
}
<ControlTemplate TargetType="{x:Type local:TextButtonControl}">
    <Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" BorderBrush="Red" BorderThickness="2">
        <TextBlock Text="{TemplateBinding Text}"
                   FontFamily="{TemplateBinding FontFamily}"
                   FontSize="{TemplateBinding FontSize}"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   TextAlignment="Center"/>
    </Border>
</ControlTemplate>

当依赖项 属性 AllCaps 更新时,如何使我的控件的文本从大写实时更改为小写(反之亦然)?

用法示例:

<!-- inside some window or user control -->
<ToggleButton x:Name="tbCaseToggle" />
<custom:TextButtonControl Text="some text" Capitalised="{Binding ElementName=tbCaseToggle, Path=IsChecked}" />

在选中或取消选中切换按钮时更改按钮内容的大小写。

Multi-value转换器

您可以为此创建一个 multi-converter,它需要一个布尔值来指示大写和文本。

public class CapitalizationConverter : IMultiValueConverter
{
   public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
   {
      var capitalize = (bool)values[0];
      var text = (string)values[1];

      // Change the capitalization here as you need
      return capitalize ? text.ToUpper() : text.ToLower();
   }

   public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
   {
      throw new InvalidOperationException();
   }
}

在您的控件模板可以访问的资源字典中创建一个转换器实例。

<local:CapitalizationConverter x:Key="CapitalizationConverter"/>

然后在绑定 AllCapsText 属性 的控件模板中使用 multi-binding 并使用转换器根据值将文本大写AllCaps.

<ControlTemplate x:Key="TextButtonControlTemplate" TargetType="{x:Type local:TextButtonControl}">
   <Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" BorderBrush="Red" BorderThickness="2">
      <TextBlock FontFamily="{TemplateBinding FontFamily}"
                 FontSize="{TemplateBinding FontSize}"
                 VerticalAlignment="Center"
                 HorizontalAlignment="Center"
                 TextAlignment="Center">
         <TextBlock.Text>
            <MultiBinding Converter="{StaticResource CapitalizationConverter}">
               <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="AllCaps"/>
               <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Text"/>
            </MultiBinding>
         </TextBlock.Text>
      </TextBlock>
   </Border>
</ControlTemplate>

暴露另一个属性

另一种方法是公开一个 read-only 依赖项 属性 DisplayText.

private static readonly DependencyPropertyKey DisplayTextPropertyKey = DependencyProperty.RegisterReadOnly(
   nameof(DisplayText), typeof(string), typeof(TextButtonControl),
   new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.None));

public static readonly DependencyProperty DisplayTextProperty = DisplayTextPropertyKey.DependencyProperty;

public string DisplayText
{
   get => (string)GetValue(DisplayTextProperty);
   private set => SetValue(DisplayTextPropertyKey, value);
}

AllCapsText 属性更改时重新格式化 DisplayText 属性。这仅是 AllCaps 的示例,但它对 Text 的工作方式也相同。

public static readonly DependencyProperty AllCapsProperty = DependencyProperty.Register(
   "AllCaps", typeof(bool), typeof(TextButtonControl), new PropertyMetadata(false, OnAllCapsChanged));

private static void OnAllCapsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
   var textButtonControl = (TextButtonControl)d;
   textButtonControl.DisplayText = textButtonControl.FormatText();
}

private string FormatText()
{
   return AllCaps ? Text.ToUpper() : Text.ToLower();
}

在您的控件模板中,您只需绑定到 DisplayText

<TextBlock Text="{Binding DisplayText, RelativeSource={RelativeSource TemplatedParent}}"
           FontFamily="{TemplateBinding FontFamily}"
           FontSize="{TemplateBinding FontSize}"
           VerticalAlignment="Center"
           HorizontalAlignment="Center"
           TextAlignment="Center"/>