передача TextBlock или коллекции встроенных строк дочернему элементу управления UserControl в WPF

Я создал UserControl под названием InfoBox, который действует как причудливый текстовый блок (дополнительные кнопки и т. д.). Это работает нормально. Я могу использовать его в Blend так:

<myNS:InfoBox Text="Some Text"/>

где «Текст» — это свойство зависимости:

 public static readonly DependencyProperty TextProperty =
     DependencyProperty.Register("Text", typeof(string), typeof(InfoBox),
     new UIPropertyMetadata(null,ValueChanged));

и обрабатывается так:

    private static void ValueChanged(DependencyObject dpo,
                                     DependencyPropertyChangedEventArgs args)
    {
        ((InfoBox)dpo).TextBlock.Text = (string)args.NewValue;
    }

Когда я добавляю элемент управления в Blend, он отображается с образцом текста времени разработки, пока я не укажу Text="Something", и в этом случае "Something" волшебным образом появляется в дизайнере. Идеально!

Но теперь я хочу передать больше, чем просто текст, я хочу иметь возможность использовать всю причудливую функциональность, которую вы получаете встроенным текстовым блоком. Выполнить, курсив и т.д.

Почему следующее не работает?

<myNS:InfoBox>
        <myNS:InfoBox.ReferenceBlock>
             <TextBlock>
                <Run Language="en-gb" Text="SampleSample"/><LineBreak/>
                <Run Language="en-gb"/><LineBreak/>
                <Run Language="en-gb" Text="MoreMoreMore"/>
             </TextBlock>   
        <myNS:InfoBox.ReferenceBlock>           
</myNS:InfoBox>

.

     public static readonly DependencyProperty ReferenceBlockProperty =
        DependencyProperty.Register("ReferenceBlock", typeof(TextBlock), 
        typeof(InfoBox), new UIPropertyMetadata(null, ReferenceBlockReceived));

[...]


     private static void ReferenceBlockReceived(DependencyObject dpo,
            DependencyPropertyChangedEventArgs args)
    {
        var textblock = (TextBlock)args.NewValue;
        if (textblock != null)
        {
            ((InfoBox)dpo).TextBlock.Inlines.Clear();
            ((InfoBox)dpo).TextBlock.Inlines.AddRange(textblock.Inlines);
        }
    }

TextBlock, полученный обработчиком, по какой-то причине полностью пуст. Я ценю любую помощь. Этот материал WPF жесткий!


person Harry Mexican    schedule 24.02.2012    source источник


Ответы (2)


К сожалению, это не так просто. TextBlock поддерживает элементы типа Run через свойство зависимости, называемое Inlines, а также пару интерфейсов. Было бы возможно, но трудно воспроизвести это поведение в вашем причудливом текстовом поле.

Я рекомендую вам загрузить бесплатный декомпилятор Jetbrain DotPeek, который позволит вам изучить реализацию TextBlock для получения представления о что требуется.

person Phil    schedule 24.02.2012
comment
На самом деле я не пытаюсь воспроизвести поведение, а скорее передаю экземпляр или копию экземпляра текстового блока под свой контроль. Не уверен, почему это было бы невозможно? В любом случае посмотрю на dotpeek, спасибо - person Harry Mexican; 27.02.2012

В дополнение к ответу Фила я бы предложил изменить тип вашего свойства зависимости ReferenceBlock на object, затем в вашем пользовательском элементе управления используйте ContentControl со свойством Content, привязанным к ReferenceBlock - это позволит вам передавать произвольный контент, включая несколько строк текста :

<ControlTemplate TargetType="myNS:InfoBox">
    <ContentControl Content="{TemplateBinding ReferenceBlock}" />
</ControlTemplate>

Это также позволит вам передавать изображения/элементы управления/другой контент по мере необходимости.

person Steve Greatrex    schedule 24.02.2012