Почему я не могу сбросить фон TextBox в моем UserControl? - PullRequest
3 голосов
/ 12 февраля 2010

Я создал UserControl, который расширяет функциональность ComboBox интересными и полезными способами. Когда это выпало, это выглядит так:

My user control

Я встроил целую кучу функций в элемент управления, и все они работают гладко. Это заставляет меня поверить, что я что-то понимаю в том, что я делаю. Вы могли бы подумать, что было бы тривиально, чтобы стиль UserControl устанавливал кисть фона редактируемого TextBox. На самом деле, это кажется невероятным. И я сбит с толку.

XAML UserControl, чрезвычайно сокращенно (вы мне за это поблагодарите), выглядит следующим образом:

<UserControl x:Class="MyApp.CodeLookupBox" x:Name="MainControl">
    <UserControl.Resources>
       <!-- tons of DataTemplates and Styles, most notably the style that
            contains the control template for the ComboBox -->
    <UserControl.Resources>
    <ComboBox x:Name="ComboBox" 
                   Margin="0" 
                   Style="{DynamicResource ComboBoxStyle1}" 
                   VerticalAlignment="Top"
                   ItemTemplate="{StaticResource GridViewStyleTemplate}"/>
</UserControl>

В этом элементе управления много кода, в основном это свойства зависимостей, которые я использую для таких вещей, как выбор шаблона, который используется в раскрывающемся списке.

Что сводит меня с ума, так это редактируемое текстовое поле. Я хочу иметь возможность установить его кисть фона из стиля пользовательского элемента управления - например, когда я объявляю один из этих пользовательских элементов управления в моем XAML, он использует такой стиль:

<Style TargetType="{x:Type local:CodeLookupBox}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsRequired}" Value="True">
            <Setter Property="EditableTextBoxBackground" Value="{StaticResource RequiredFieldBrush}"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

Я начал свою жизнь просто с установки фона UserControl, но это установило фон позади редактируемого TextBox. Сам TextBox остался белым.

Внутри шаблона для ComboBox есть стиль, который управляет этим TextBox:

<Style x:Key="ComboBoxEditableTextBox" TargetType="{x:Type TextBox}">
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="AllowDrop" Value="true"/>
    <Setter Property="MinWidth" Value="0"/>
    <Setter Property="MinHeight" Value="0"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <ScrollViewer 
                            x:Name="PART_ContentHost" 
                            Focusable="false" 
                            HorizontalScrollBarVisibility="Hidden" 
                            VerticalScrollBarVisibility="Hidden"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

И есть TextBox (внутри шаблона элемента управления ComboBox), его плохое «я»:

<TextBox 
    x:Name="PART_EditableTextBox" 
    Margin="{TemplateBinding Padding}" 
    Style="{StaticResource ComboBoxEditableTextBox}" 
    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
    VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
    IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource TemplatedParent}}"/>

Теперь есть определенный элемент вещей, которые человеку не нужно было знать о том стиле ComboBoxEditableTextBox. Что этот ScrollViewer делает там? Я понятия не имею. Я могу сказать вам, что если я закомментирую часть стиля, который устанавливает ControlTemplate TextBox, произойдут очень плохие вещи.

И я также знаю это: если я явно установлю фоновую кисть TextBox в качестве одного из установщиков стиля, ничего не произойдет. Если я явно установлю фон для PART_EditableTextBox, ничего не произойдет. (Я могу установить его передний план или его FontFamily, и они отлично работают.)

Если я явно установлю для фона этого ScrollViewer значение Green, хотя, вуаля, TextBox станет зеленым.

Хорошо, тогда TextBox игнорирует свой собственный фон и использует его из своего шаблона управления. На самом деле, строго говоря, он не использует тот же шаблон управления. Когда я устанавливаю фон ScrollViewer, вокруг краев цвета появляется определенное поле, а не цвет, полностью заполняющий TextBox. Но это поле белого цвета, а не фона.

Если я не могу понять, почему TextBox игнорирует свой Фон, мне придется смириться с настройкой ScrollViewer. Так как же получить его, чтобы получить кисть из свойства EditableTextBoxBackground пользовательского элемента управления? Я сделал это свойство зависимости, которое правильно вызывает событие PropertyChanged при его изменении. Я связываюсь с этим в таинственном XAML ScrollViewer, как это:

Background="{Binding ElementName=MainControl, 
    Path=EditableTextBoxBackground, 
    Converter={StaticResource DebuggingConverter}}"

Я установил точку останова в моем отладочном конвертере. Когда элемент управления впервые рисуется, он получает удар дважды. В первый раз значение кисти равно нулю. Во второй раз это правильное значение. И если я установлю свойство в конструкторе моего UserControl , оно будет работать.

Итак, вот что я знаю: свойство My UserControl устанавливается правильно. Привязка к стилю TextBox правильно связана со свойством UserControl. Привязка к ScrollViewer в шаблоне элемента управления TextBox привязана к правому свойству. Свойство вызывает PropertyChanged с правильным именем свойства при его изменении, и привязка передает значение в свойство фона ScrollViewer.

И ничего не происходит.

Итак, я думаю, у меня есть вопрос из трех частей: 1) Почему? 2) Какого черта ScrollViewer делает там в первую очередь? У меня есть подозрения, но сейчас час ночи, и мне становится трудно их сформулировать. 3) Почему Blend дал мне другой шаблон управления для работы, чем гораздо более понятный здесь ?

Действительно, любая помощь будет принята.

1 Ответ

6 голосов
/ 12 февраля 2010

У вас есть вопросы. У меня есть ответы.

1- Почему привязка фона ScrollViewer ведет себя так странно?

Когда TextBox измеряется впервые, он создает свой шаблон. Это создает ScrollViewer. После применения шаблона TextBox проверяет, имеет ли свойство ScrollViewer Background в настоящее время нулевое значение. Если так, это перезаписывает это с Background.Transparent. Это отключит вашу привязку.

Вот почему он работает, когда вы устанавливаете его в конструкторе, но не позже: TextBox увидел нулевое значение и переписал его с помощью Background.Transparent, нарушив привязку.

2- Что вообще там делает ScrollViewer?

TextBox - это Control, который на самом деле не обрабатывает никаких кровавых подробностей самого текстового представления - если вы просматриваете визуальное дерево, вы увидите, что это обрабатывается другим Visual с именем что-то как "TextView". * * Основная задача TextBox - представить границу вокруг текстового поля и / или позволить вам придать ему совершенно новый вид.

TextBox требуется шаблон с элементом с именем PART_ContentHost, который является либо ContentPresenter, либо ScrollViewer. Если это простой ContentPresenter, внутренний объект «TextView» просто добавляется к нему. Если это ScrollViewer, TextBox также подключает некоторые дополнительные функции, такие как прокрутка текста в поле зрения, когда он находится в фокусе.

Цель ScrollViewer в жизни - позволить тексту в TextBox горизонтально прокручиваться, а также вертикально прокручиваться для многострочных текстовых полей.

3- Почему Blend дал мне другой шаблон управления

Blend загружает фактический ControlTemplate XAML из ссылочных сборок, в данном случае PresentationFramework.dll и связанной dll темы для текущей системной темы. Таким образом, он загрузит то, что на самом деле используется в установленной вами версии NET Framework. XAML на сайте, на который вы ссылаетесь, является просто примером кода, а не фактическим XAML NET Framework.

Я добавил еще два соответствующих вопроса:

4- Почему не работает настройка свойства TextBox's Background?

Ни один из подклассов Control WPF фактически не реализует свои свойства Background. Background DependencyProperty - это просто именованная кисть, которую шаблон элемента управления может привязать к , если ему нравится . Это так же верно для TextBox, как и для любого другого Control. Шаблон TextBox по умолчанию включает в себя объект «хром», который содержит код для отображения фона, аналогично тому, для которого вы можете использовать границу. Поскольку ComboBox уже отображает свой собственный «хром», он использует собственный шаблон TextBox, который включает ScrollViewer, но не окружающий хром. Вот почему установка свойства Background для TextBox внутри ComboBox не имеет никакого эффекта.

5- Как мне решить мою проблему и связать цвет фона TextBox внутри ComboBox

Если вы в порядке с белым полем, вы можете просто обернуть ScrollViewer внутри <Border> и установить фон на <Border>. Если нет, вам придется переместить нужный фон в хром, поставляемый в основном ControlTemplate для ComboBox.

...