Проблемы с форматированием при попытке создать шаблон метки WPF, позволяющий выделять текст - PullRequest
3 голосов
/ 09 мая 2011

У меня есть требование разрешить выделение текста, отображаемого на экранах только для чтения.

Простое решение, которое придумал один из наших разработчиков, - это использование TextBox вместо Label или TextBlock со следующим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>

Мне не нравится идея использовать там TextBox, помимо прочего, потому что это заставляет меня использовать Binding Mode=OneWay для свойств только для чтения, поэтому я пытался определить стильчто я могу применить к метке, чтобы получить тот же результат:

<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>

Проблема в том, что для некоторых моих привязок установлено StringFormat, и оно потеряно.

  • Есть ли способ сохранить форматирование внешней привязки?
  • Должен ли я создать свой шаблон / привязку по-другому?
  • Есть ли совсем другой подход, который лучше этого?
  • Должен ли я остановиться на придирках и перейти к TextBox?

Ответы [ 2 ]

2 голосов
/ 10 мая 2011

Я думаю, что это хорошая идея использовать Label и переопределить шаблон управления.В конце концов это то, для чего нужно разделение логики управления и макета в WPF, и вы должны использовать его, чтобы получить более чистый и понятный код xaml.

Вы пытались использовать TemplateBinding вместо обычного Binding?Я не уверен, сохранит ли это внешнее связывание, но это рекомендуемое связывание для использования в DataTemplates.

Вам также следует взглянуть на класс ContentPresenter, хотя я не уверен, применимо ли оно здесь, поскольку ваше внутреннее текстовое поле имеет только свойство Text типа string ...

Edit: Я решил проблему, хотя она была более сложной, чем я думал ...

Создайте стиль следующим образом:

<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>

ContentToTextConverter определен следующим образом:

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();
    }
}

Пример использования:

<Label ContentStringFormat="{}{0}$">
     <System:Int64>15</System:Int64>
</Label>

Itбыло бы неплохо найти более приятное решение, чем это, но на данный момент оно должно работать как положено.

2 голосов
/ 09 мая 2011

Должен ли я остановиться на придирках и перейти к TextBox?

Определенно.

...