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 convert开发者_如何转开发er because there is no binding. I don't want to make the strings upper case in the dictionary itself.
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
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}}"/>
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>
You can case all input into TextBox controls with the following property:
<TextBox CharacterCasing="Upper"
To apply to all TextBox controls in the entire application create a style for all TextBox controls:
<Style TargetType="{x:Type TextBox}">
<Setter Property="CharacterCasing" Value="Upper"/>
</Style>
精彩评论