Можно ли задать в XAML стиль, который выборочно влияет на элементы управления?

В <Window.Resources> я определил следующий стиль:

    <Style x:Key="textBlockStyle" TargetType="TextBlock">
        <Setter Property="Margin" Value="5,0,5,0"/>
    </Style>

Я определил некоторую сетку, в которой у меня есть четыре TextBlocks:

    <WrapPanel>
        <TextBlock Style="{StaticResource textBlockStyle}">Server</TextBlock>
        <TextBlock Style="{StaticResource textBlockStyle}">IP</TextBlock>
        <TextBlock Style="{StaticResource textBlockStyle}">Port</TextBlock>
        <TextBlock Style="{StaticResource textBlockStyle}">Status</TextBlock>
    </WrapPanel>

Проблема: мне нужно сослаться на textBlockStyle четыре раза.

Вопрос: можно ли установить этот стиль только один раз в WrapPanel или где-то еще, не повторяя ссылку на стиль?

Может быть, что-то вроде:

    <WrapPanel Style="{StaticResource textBlockStyle}">
        <TextBlock>Server</TextBlock>
        <TextBlock>IP</TextBlock>
        <TextBlock>Port</TextBlock>
        <TextBlock>Status</TextBlock>
    </WrapPanel>

Я не ищу глобального решения! Я могу удалить это свойство x:Key="textBlockStyle", но это повлияет на все TextBlocks в окне. Мне нужен более избирательный механизм, но без этого уродливого дублирования кода.


person Theo Lenndorff    schedule 29.03.2009    source источник


Ответы (2)


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

Вариант 1. Определите стиль без ключа на более низком уровне

Вы можете закрепить ресурс на уровне WrapPanel, чтобы он влиял только на элементы управления внутри этого уровня WrapPanel:

<WrapPanel>
    <WrapPanel.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="Margin" Value="5,0,5,0"/>
        </Style>
    </WrapPanel.Resources>

    <!-- TextBlocks here -->
</WrapPanel>

Обратите внимание на отсутствие ключа. Это Style будет применяться ко всем TextBlock в пределах WrapPanel.

Вариант 2. Определите стиль с ключом и снова без него на более низком уровне

Если вы определяете Style на более высоком уровне с помощью ключа, вы можете затем определить другой Style на более низком уровне без ключа и основывать этот Style на более высоком уровне:

<Window>
    <Window.Resources>
        <Style TargetType="TextBlock" x:Key="textBlockStyle">
            <Setter Property="Margin" Value="5,0,5,0"/>
        </Style>
    </Window.Resources>

    <WrapPanel>
        <WrapPanel.Resources>
            <Style TargetType="TextBlock" BasedOn="{StaticResource textBlockStyle"/>
        </WrapPanel.Resources>

        <!-- TextBlocks here -->
    </WrapPanel>
</Window>

Это приводит к тому, что Style автоматически применяется к TextBlock внутри WrapPanel, но не за его пределами. Кроме того, вы не дублируете детали Style — они хранятся на более высоком уровне.

Вариант 3. Поместите стили в ResourceDictionary и выборочно объедините их

Наконец, вы можете поместить свои Style в отдельный ResourceDictionary и выборочно объединить этот словарь с коллекцией Resources элемента управления:

<!-- TextBlockStyles.xaml -->
<ResourceDictionary>
    <Style TargetType="TextBlock">
        <Setter Property="Margin" Value="5,0,5,0"/>
    </Style>
</ResourceDictionary>

<!-- Window.xaml -->
<Window>
    <WrapPanel>
        <WrapPanel.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="TextBlockStyles.xaml"/>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </WrapPanel.Resources>
    </WrapPanel>
</Window>

<!-- Alternative Window.xaml if you have only one RD to merge in -->
<Window>
    <WrapPanel>
        <WrapPanel.Resources>
            <ResourceDictionary Source="TextBlockStyles.xaml"/>
        </WrapPanel.Resources>
    </WrapPanel>
</Window>

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

person Kent Boogaart    schedule 29.03.2009
comment
Обычно я предпочитаю вариант 2, если у меня уже есть определенный стиль и я использую его где-то еще, в противном случае вариант 1. Для чего он стоит. Отличный ответ, Кент. - person Bryan Anderson; 30.03.2009

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

<WrapPanel>
< WrapPanel. Resources >
<Style TargetType="{x:Type TextBlock}">
        <Setter Property="Margin" Value="5,0,5,0"/>
    </Style>
</WrapPanel.Resources/>
        <TextBlock Server</TextBlock>
        <TextBlock >IP</TextBlock>
        <TextBlock >Port</TextBlock>
        <TextBlock >Status</TextBlock>
    </WrapPanel>

используя синтаксис {x:type}, вам не нужен ключ x:, он установит стиль для всех текстовых блоков в панели переноса. если вам нужны разные стили, вы все равно можете использовать ключ x: и явно установить стиль в текстовом блоке.

person Muad'Dib    schedule 29.03.2009