Formatting issues trying to create a WPF Label template that allows text selection
I have a requirement to allow selecting the text displayed in read only screens.
A simple solution one of our developers came up with is using a TextBox
instead of a Label or TextBlock, with the following style:
<Style x:Key="ControlData" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="TextWrapping" Value="Wrap" />
<!-- unrelated properties ommitted -->
</Style>
I don't like the idea of usin开发者_运维技巧g a TextBox there, among other things because it forces me to use Binding Mode=OneWay
for read-only properties, so I was trying to define a Style that I can apply to a label to get the same result:
<Style x:Key="SelectableLabel" TargetType="Label">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<TextBox Style="{StaticResource ControlData}"
Text="{Binding Path=Content, Mode=OneWay,
RelativeSource={RelativeSource FindAncestor,
AncestorType=Label}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem is, some of my bindings have StringFormat
set, and that is lost.
- Is there a way to keep the formatting of the outer binding?
- Should I create my template/binding differently?
- Is there a whole different approach that's better than this?
- Should I stop with the nitpicking and go with the TextBox?
I think it's a good idea to use a Label and override the control template. At the end this is what the separation of Control logic and layout in WPF is for and you should make use of it to have a cleaner, more understandable xaml code.
Did you try using a TemplateBinding instad of normal Binding? I'm not sure if this will preserve the outer binding, but it's the recommended Binding to use in DataTemplates.
You should also take a look at the ContentPresenter class, although I'm not sure if it's applicable here, since your inner text box only has a Text property of type string...
Edit: I solved the problem, although it was more complicated then I thought...
Create the style as following:
<Application.Resources>
<LabelTest:ContentToTextConverter x:Key="contentConverter" />
<Style TargetType="Label">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<TextBox DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor,AncestorType=Label}}">
<TextBox.Text>
<MultiBinding Converter="{StaticResource contentConverter}" >
<Binding Mode="OneWay" Path="ContentStringFormat" />
<Binding Mode="OneWay" Path="Content" />
</MultiBinding>
</TextBox.Text>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
The ContentToTextConverter is defined as following:
public class ContentToTextConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var format = values[0] as string;
if (string.IsNullOrEmpty(format)) format = "{0}";
else if(format.IndexOf('{') < 0) format = "{0:" + format + "}";
return string.Format(culture, format, values[1]);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Example of how to use:
<Label ContentStringFormat="{}{0}$">
<System:Int64>15</System:Int64>
</Label>
It would be nice to find a nicer solution than this, but for the moment it should work as expected.
Should I stop with the nitpicking and go with the TextBox?
Definitely.
精彩评论