Установка локального неявного стиля, отличного от стиля темы / альтернативы BasedOn DynamicResource - PullRequest
6 голосов
/ 22 декабря 2011

представьте себе wpf-приложение, в котором я могу динамически менять тему. Я делаю это путем замены ResourceDictionaries на уровне приложений-ресурсов. В тематических ресурсах есть неявные стили, определенные для TextBox и т. П.

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

Я бы хотел сделать это (используя DynamicResource, потому что тему можно изменить во время выполнения):

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="TextBox" BasedOn="{DynamicResource NonDefaultTextBoxStyle}"/>
    </StackPanel.Resources>
    <TextBox .../>
    <TextBox .../>
    <TextBox .../>
</StackPanel>

вместо того, чтобы делать это:

<StackPanel>
    <TextBox Style="{DynamicResource NonDefaultTextBoxStyle}" .../>
    <TextBox Style="{DynamicResource NonDefaultTextBoxStyle}" .../>
    <TextBox Style="{DynamicResource NonDefaultTextBoxStyle}" .../>
</StackPanel>

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

Это хорошая идея? Есть ли более простые способы? Я что-то упустил?

это в значительной степени сводится к: Что является альтернативой BasedOn = "{DynamicResource ...} в стиле?

Ответы [ 2 ]

4 голосов
/ 01 марта 2012

У меня была точно такая же проблема, но для ItemsContainerStyle ... поэтому я сделал в значительной степени то, что вы сказали, и написал AttachedProperty, который позволил бы динамический ресурс для BasedOn.

DynamicResource для Style BasedOn

Вот решение, измененное для вашей ситуации:

public class DynamicStyle
{
    public static Style GetBaseStyle(DependencyObject obj)
    {
        return (Style)obj.GetValue(BaseStyleProperty);
    }

    public static void SetBaseStyle(DependencyObject obj, Style value)
    {
        obj.SetValue(BaseStyleProperty, value);
    }

    // Using a DependencyProperty as the backing store for BaseStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty BaseStyleProperty =
        DependencyProperty.RegisterAttached("BaseStyle", typeof(Style), typeof(DynamicStyle), new UIPropertyMetadata(DynamicStyle.StylesChanged));

    public static Style GetDerivedStyle(DependencyObject obj)
    {
        return (Style)obj.GetValue(DerivedStyleProperty);
    }

    public static void SetDerivedStyle(DependencyObject obj, Style value)
    {
        obj.SetValue(DerivedStyleProperty, value);
    }

    // Using a DependencyProperty as the backing store for DerivedStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DerivedStyleProperty =
        DependencyProperty.RegisterAttached("DerivedStyle", typeof(Style), typeof(DynamicStyle), new UIPropertyMetadata(DynamicStyle.StylesChanged));

    private static void StylesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        if (!typeof(FrameworkElement).IsAssignableFrom(target.GetType()))
            throw new InvalidCastException("Target must be FrameworkElement");

        var Element = (FrameworkElement)target;

        var Styles = new List<Style>();

        var BaseStyle = GetBaseStyle(target);

        if (BaseStyle != null)
            Styles.Add(BaseStyle);

        var DerivedStyle = GetDerivedStyle(target);

        if (DerivedStyle != null)
            Styles.Add(DerivedStyle);

        Element.Style = MergeStyles(Styles);
    }

    private static Style MergeStyles(ICollection<Style> Styles)
    {
        var NewStyle = new Style();

        foreach (var Style in Styles)
        {
            foreach (var Setter in Style.Setters)
                NewStyle.Setters.Add(Setter);

            foreach (var Trigger in Style.Triggers)
                NewStyle.Triggers.Add(Trigger);
        }

        return NewStyle;
    }
}

А вот пример его использования:

<!-- xmlns:ap points to the namespace where DynamicStyle class lives -->
<Button ap:DynamicStyle.BaseStyle="{DynamicResource {x:Type Button}}">
    <ap:DynamicStyle.DerivedStyle>
        <Style TargetType="Button">
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=FirstButtonWarning}" Value="True"/>
                        <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}" Value="True"/>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.Setters>
                        <Setter Property="Background" Value="{DynamicResource WarningBackground}"/>
                        <Setter Property="Foreground" Value="{DynamicResource WarningForeground}"/>
                    </MultiDataTrigger.Setters>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </ap:DynamicStyle.DerivedStyle>
    <TextBlock Text="Button that changes background and foreground when warning is active"/>
</Button>
3 голосов
/ 25 апреля 2013

действительно ли это должен быть DynamicResource?так что, возможно, это поможет вам

, если не здесь, это простой пример StaticResource

App.xaml

<Application.Resources>
        <Style x:Key="myResource" TargetType="Button">
            <Setter Property="Background" Value="Black"/>
            <Setter Property="Foreground" Value="White"/>
        </Style>         
    </Application.Resources>

MainWindow.xaml

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="Button" BasedOn="{StaticResource myResource}"/>
    </StackPanel.Resources>
    <Button Content="blubb" Height="23" Width="75" />
</StackPanel>

, если и то, и другое не поможет вам, возможно, вы могли бы предоставить способ добавления своего ресурса

Редактировать

Хорошо, теперь следует ответить на ваш вопрос

App.xaml

<Application.Resources>

    <SolidColorBrush  x:Key="background"  Color="Red" />
    <SolidColorBrush  x:Key="foreground"  Color="Blue" />

    <Style x:Key="NonDefaultTextBoxStyle" >
        <Setter Property="TextBox.Background" Value="{DynamicResource background}"/>
        <Setter Property="TextBox.Foreground" Value="{DynamicResource foreground}"/>
    </Style>

</Application.Resources>

MainWindow.xaml

<StackPanel>
    <Button Content="Button" Height="23" Width="75" Click="Button_Click" />

    <StackPanel>
        <StackPanel.Resources>
            <Style   TargetType="{x:Type TextBox}" BasedOn="{StaticResource NonDefaultTextBoxStyle}">
            </Style>
        </StackPanel.Resources>
        <TextBox Text="bliii" Height="23" Width="75" />
        <TextBox Text="blaaa" Height="23" Width="75" />
        <TextBox Text="blubb" Height="23" Width="75" />
    </StackPanel>

</StackPanel>

MainWindow.cs

private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Resources["background"] = Brushes.Black;
            this.Resources["foreground"] = Brushes.Yellow;
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...