English 中文(简体)
How to make all text upper case / capital?
原标题:

I want all texts in TextBlock, Label, MenuItem.Header to be displayed in upper case. The strings are taken from a ResourceDictionary e.g.:

<TextBlock Text="{StaticResource String1}"/>
<MenuItem Header="{StaticResource MenuItemDoThisAndThat}"/>

etc. (also for Label and other controls)

I cannot use a value converter because there is no binding. I don t want to make the strings upper case in the dictionary itself.

最佳回答

You still can use a converter, just set the textvalue in the source of the binding :

<TextBlock Text="{Binding Source={StaticResource String1},  Converter ={StaticResource myConverter}}"/>
问题回答

I think this will work for you

<TextBlock Text= {StaticResource String1}  Typography.Capitals="AllPetiteCaps"/>

For font capitals enumerations https://msdn.microsoft.com/en-us/library/system.windows.fontcapitals(v=vs.110).aspx

Rather than using a converter, you can use the tag CharacterCasing in a TextBox but in your case, it doesn t work on a TextBlock.

<TextBox CharacterCasing="Upper" Text="{StaticResource String1}" />

To complete Peter s answer (my edit has been rejected), you can use a converter like this:

C#:

public class CaseConverter : IValueConverter
{    
    public CharacterCasing Case { get; set; }

    public CaseConverter()
    {
        Case = CharacterCasing.Upper;
    }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var str = value as string;
        if (str != null)
        {
            switch (Case)
            {
                case CharacterCasing.Lower:
                    return str.ToLower();
                case CharacterCasing.Normal:
                    return str;
                case CharacterCasing.Upper:
                    return str.ToUpper();
                default:
                    return str;
            }
        }
        return string.Empty;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML:

<TextBlock Text="{Binding Source={StaticResource String1}, Converter ={StaticResource myCaseConverter}}"/>

I created an attached property and converter for this. You probably already have the converter, so replace my reference to CaseConverter to whatever implementation you have.

The attached property is just a boolean that you set if you want it to be uppercase (you could obviously extend this to instead be an enumerable for a selection of styles). When the property changes, it rebinds the TextBlock s Text property as needed, adding in the converter.

A little more work might need to be done when the property is already bound - my solution assumes it s a simple Path binding. But it may need to also duplicate the source, etc. However I felt this example is enough to get my point across.

Here s the attached property:

public static bool GetUppercase(DependencyObject obj)
    {
        return (bool)obj.GetValue(UppercaseProperty);
    }

    public static void SetUppercase(DependencyObject obj, bool value)
    {
        obj.SetValue(UppercaseProperty, value);
    }

    // Using a DependencyProperty as the backing store for Uppercase.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty UppercaseProperty =
        DependencyProperty.RegisterAttached("Uppercase", typeof(bool), typeof(TextHelper), new PropertyMetadata(false, OnUppercaseChanged));

    private static void OnUppercaseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TextBlock txt = d as TextBlock;

        if (txt == null) return;

        var val = (bool)e.NewValue;

        if (val)
        {
            // rebind the text using converter
            // if already bound, use it as source

            var original = txt.GetBindingExpression(TextBlock.TextProperty);

            var b = new Binding();

            if (original != null)
            {
                b.Path = original.ParentBinding.Path;
            }
            else
            {
                b.Source = txt.Text;
            }

            b.Converter = new CaseConverter() { Case = CharacterCasing.Upper };


            txt.SetBinding(TextBlock.TextProperty, b);
        }
    }

This does not strictly answer the question but does provide a trick to cause the same effect.

I believe many finding their way here are looking how to do this with a style. TextBlock is a bit tricky here because it is not a Control but a FrameworkElement and therefore you can not define a Template to do the trick.

The need to use all uppercase text is most likely for headings or something like that where use of Label is justified. My solution was:

<!-- Examples of CaseConverter can be found in other answers -->

<ControlTemplate x:Key="UppercaseLabelTemplate" TargetType="{x:Type Label}">
    <TextBlock Text="{TemplateBinding Content, Converter={StaticResource CaseConverter}}" />
</ControlTemplate>

<Style x:Key="UppercaseHeadingStyle"
       TargetType="{x:Type Label}">
    <Setter Property="FontSize" Value="20" />
    <Setter Property="FontWeight" Value="Bold" />
    <Setter Property="Template" Value="{StaticResource UppercaseLabelTemplate}" />
</Style>

<!-- Usage: -->
<Label Content="Header" Style="{StaticResource UppercaseHeadingStyle}" />

Note that this does disable some of the default behavior of Label, and works only for text, so I would not define this as default (no one probably wants all labels uppercase anyway). And of course you must use Label instead of TextBlock when you need this style. Also I would not use this inside of other templates, but only strictly as a topic style.

    public class StaticResourceToUpperExtension : StaticResourceExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var resource = base.ProvideValue(serviceProvider);
            if (resource is string str)
                return str.ToUpper();
            return resource;
        }

        public StaticResourceToUpperExtension() : base() { }
        public StaticResourceToUpperExtension(object resourceKey) : base(resourceKey) { }

    }
    <Grid>
        <FrameworkElement.Resources>
            <sys:String x:Key="String1">any text</sys:String>
        </FrameworkElement.Resources>
        <TextBlock Text="{local:StaticResourceToUpper String1}"/>
    </Grid>




相关问题
WPF convert 2d mouse click into 3d space

I have several geometry meshes in my Viewport3D, these have bounds of (w:1800, h:500, d:25). When a user clicks in the middle of the mesh, I want the Point3D of (900, 500, 25)... How can I achieve ...

Editing a xaml icons or images

Is it possible to edit a xaml icons or images in the expression design or using other tools? Is it possible to import a xaml images (that e.g you have exported) in the expression designer for editing?...

WPF: writing smoke tests using ViewModels

I am considering to write smoke tests for our WPF application. The question that I am faced is: should we use UI automation( or some other technology that creates a UI script), or is it good enough to ...

WPF - MVVM - NHibernate Validation

Im facing a bit of an issue when trying to validate a decimal property on domain object which is bound to a textbox on the view through the viewmodel. I am using NHibernate to decorate my property on ...

How do WPF Markup Extensions raise compile errors?

Certain markup extensions raise compile errors. For example StaticExtension (x:Static) raises a compile error if the referenced class cannot be found. Anyone know the mechanism for this? Is it baked ...

WPF design-time context menu

I am trying to create a custom wpf control, I m wondering how I can add some design-time features. I ve googled and can t seem to get to my goal. So here s my simple question, how can I add an entry ...

How to combine DataTrigger and EventTrigger?

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger? I think I need to combine an EventTrigger and a DataTrigger to achieve what I m after: when ...

热门标签