WPF:如何强制Combobox输入大写字母?

4

我不确定为什么,但是从类似的问题中,没有一个解决方案适用于我的情况。

我知道TextBox有一个属性(CharacterCasing),可以设置为Upper,将任何小写字母转换为大写字母。它非常有效,因为用户在输入时不会受到干扰,大写锁定和Shift键也不会对其产生负面影响,其他非字母字符也不会受到负面影响。

问题是ComboBox没有使用此属性的选项。那个类似的帖子中的解决方案似乎对我无效。我想复制CharacterCasing属性,但是应用于ComboBox。我不介意它成为一个附加属性,实际上这很好。我尝试了一些直接在xaml对象上使用的不同事件,但没有成功。

1个回答

15
ComboBox 模板在 IsEditable 为 true 时使用了一个 TextBox。因此,您可以替换模板以在 TextBox 上设置 CharacterCasing,或者创建一个附加属性,通过其名称 ("PART_EditableTextBox") 查找 TextBox 并在其中设置 CharacterCasing 属性。

这是一个简单的附加属性解决方案实现:

public static class ComboBoxBehavior
{

    [AttachedPropertyBrowsableForType(typeof(ComboBox))]
    public static CharacterCasing GetCharacterCasing(ComboBox comboBox)
    {
        return (CharacterCasing)comboBox.GetValue(CharacterCasingProperty);
    }

    public static void SetCharacterCasing(ComboBox comboBox, CharacterCasing value)
    {
        comboBox.SetValue(CharacterCasingProperty, value);
    }

    // Using a DependencyProperty as the backing store for CharacterCasing.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CharacterCasingProperty =
        DependencyProperty.RegisterAttached(
            "CharacterCasing",
            typeof(CharacterCasing),
            typeof(ComboBoxBehavior),
            new UIPropertyMetadata(
                CharacterCasing.Normal,
                OnCharacterCasingChanged));

    private static void OnCharacterCasingChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var comboBox = o as ComboBox;
        if (comboBox == null)
            return;

        if (comboBox.IsLoaded)
        {
            ApplyCharacterCasing(comboBox);
        }
        else
        {
            // To avoid multiple event subscription
            comboBox.Loaded -= new RoutedEventHandler(comboBox_Loaded);
            comboBox.Loaded += new RoutedEventHandler(comboBox_Loaded);
        }
    }

    private static void comboBox_Loaded(object sender, RoutedEventArgs e)
    {
        var comboBox = sender as ComboBox;
        if (comboBox == null)
            return;

        ApplyCharacterCasing(comboBox);
        comboBox.Loaded -= comboBox_Loaded;
    }

    private static void ApplyCharacterCasing(ComboBox comboBox)
    {
        var textBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox;
        if (textBox != null)
        {
            textBox.CharacterCasing = GetCharacterCasing(comboBox);
        }
    }

}

以下是如何使用它的方法:

    <ComboBox ItemsSource="{Binding Items}"
              IsEditable="True"
              local:ComboBoxBehavior.CharacterCasing="Upper">
        ...

这似乎对我不起作用...它在用户控件中不可用吗?特别是这一行 var textBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox; 将textBox设置为null,这就是为什么 CharacterCasing 从未应用的原因。 - myermian
很奇怪...我测试过了,对我来说运行得很好。你是否将IsEditable设置为true?如果它为false,ComboBox使用不同的模板,其中不包含TextBox。 - Thomas Levesque
我也不确定为什么它不起作用。我在那一行上设置了一个调试停止点,并检查了comboBox的属性。IsEditable被设置为true。 - myermian
1
你是否在使用自定义的ComboBox控件模板?如果是,检查一下它是否包含了一个名为PART_EditableTextBox的元素。虽然有可能使用不包含该元素的控件模板,但这种实现方式当然是无法工作的。 - Simon D.
感谢您提供的好解决方案...在添加处理程序之前(在else块中),我会添加comboBox.Loaded -= comboBox_Loaded;。这只是一个小优化,以防在控件加载之前多次调用PropertyChanged(据我所知,这应该是可能的,并且会导致对ApplyCharacterCasing的重复调用,即使它仍然可以正常工作)。 - TCC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接