web-dev-qa-db-fra.com

Fusion de ressources dynamiques sans application de styles au premier contrôle

J'ai essayé d'appliquer un nouveau style pour mes contrôles personnalisés en fusionnant les ressources de style aux ressources de l'application tout en ajoutant le contrôle à l'interface utilisateur, mais les nouveaux styles ne sont pas appliqués aux contrôles pour la première fois.

Contrôle des échantillons

CustomTextBoxExt.cs

 public class CustomTextBoxExt : TextBox
    {
        static CustomTextBoxExt()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomTextBoxExt), new FrameworkPropertyMetadata(typeof(CustomTextBoxExt)));
        }
    }

style par défaut Generic.xaml

 <Style x:Key="TextBoxExtStyle" TargetType="{x:Type local:CustomTextBoxExt}">
    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
    <Setter Property="BorderBrush" Value="Red" />
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
    <Setter Property="HorizontalContentAlignment" Value="Left" />
    <Setter Property="FocusVisualStyle" Value="{x:Null}" />
    <Setter Property="AllowDrop" Value="True" />
    <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
    <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomTextBoxExt}">
                <Border
                    x:Name="border"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    SnapsToDevicePixels="True">
                    <ScrollViewer
                        x:Name="PART_ContentHost"
                        Focusable="False"
                        HorizontalScrollBarVisibility="Hidden"
                        VerticalScrollBarVisibility="Hidden" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter TargetName="border" Property="Opacity" Value="0.56" />
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="border" Property="BorderBrush" Value="#FF7EB4EA" />
                    </Trigger>
                    <Trigger Property="IsKeyboardFocused" Value="True">
                        <Setter TargetName="border" Property="BorderBrush" Value="#FF569DE5" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>

        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsInactiveSelectionHighlightEnabled" Value="True" />
                <Condition Property="IsSelectionActive" Value="False" />
            </MultiTrigger.Conditions>
            <Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}" />
        </MultiTrigger>
    </Style.Triggers>
</Style>
<Style BasedOn="{StaticResource TextBoxExtStyle}" TargetType="{x:Type local:CustomTextBoxExt}" />

Thème personnalisé TextBoxExtStyle.xaml

<Style x:Key="MaterialTextBoxExtStyle" TargetType="{x:Type local:CustomTextBoxExt}">
    <Setter Property="FocusVisualStyle" Value="{x:Null}" />
    <Setter Property="Foreground" Value="#DD000000" />
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="BorderBrush" Value="#FF9E9E9E" />
    <Setter Property="BorderThickness" Value="0,0,0,1" />
    <Setter Property="FontSize" Value="12" />
    <Setter Property="FontWeight" Value="Normal" />
    <Setter Property="SelectionBrush" Value="#FF0279FF" />
    <Setter Property="AllowDrop" Value="true" />
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
    <Setter Property="HorizontalContentAlignment" Value="Left" />
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="AllowDrop" Value="true" />
    <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
    <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
    <Setter Property="CaretBrush" Value="#DD000000" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomTextBoxExt}">
                <Grid>
                    <Border
                        x:Name="border"
                        Padding="{TemplateBinding Padding}"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        SnapsToDevicePixels="true">
                        <ScrollViewer
                            x:Name="PART_ContentHost"
                            Background="Transparent"
                            Focusable="False"
                            HorizontalScrollBarVisibility="Hidden"
                            VerticalScrollBarVisibility="Hidden" />
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter TargetName="border" Property="BorderBrush" Value="#FF757575" />
                        <Setter TargetName="border" Property="Background" Value="Transparent" />
                        <Setter Property="Foreground" Value="#DD000000" />
                        <Setter Property="CaretBrush" Value="#DD000000" />
                    </Trigger>
                    <Trigger Property="IsKeyboardFocused" Value="true">
                        <Setter TargetName="border" Property="BorderBrush" Value="#FF0279FF" />
                        <Setter Property="BorderThickness" Value="0,0,0,2" />
                        <Setter Property="Padding" Value="0,0,0,-1" />
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter TargetName="border" Property="Background" Value="Transparent" />
                        <Setter TargetName="border" Property="BorderBrush" Value="#FFE0E0E0" />
                        <Setter Property="Foreground" Value="#60000000" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style BasedOn="{StaticResource MaterialTextBoxExtStyle}" TargetType="{x:Type local:CustomTextBoxExt}" />

et en utilisant la propriété jointe, en essayant de changer le style du style par défaut,

public class SkinExt
{
    public static string GetTheme(DependencyObject obj)
    {
        return (string)obj.GetValue(ThemeProperty);
    }

    public static void SetTheme(DependencyObject obj, string value)
    {
        obj.SetValue(ThemeProperty, value);
    }

    // Using a DependencyProperty as the backing store for Theme.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ThemeProperty =
        DependencyProperty.RegisterAttached("Theme", typeof(string), typeof(SkinExt), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnVisualStyleChanged)));


    private static void OnVisualStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue != e.OldValue && !string.IsNullOrEmpty(e.NewValue.ToString()) /*&& d is FrameworkElement && (d as FrameworkElement).IsLoaded*/)
        {
            SkinExt.ApplyTheme(d, e.NewValue.ToString());
        }
    }

    internal static void ApplyTheme(DependencyObject obj, string style)
    {
        Type itemType = obj.GetType();

        List<string> styles = GetDictionaries(obj.GetType().Name.ToString(), style);

        if (styles != null && styles.Count > 0)
        {
            foreach (var path in styles)
            {
                var rdict = new ResourceDictionary() { Source = new Uri(path, UriKind.RelativeOrAbsolute) };
                bool alreadyExist = false;
                foreach (var dictionaryFiles in Application.Current.Resources.MergedDictionaries)
                {
                    if (dictionaryFiles.Source.OriginalString.Contains(path))
                    {
                        alreadyExist = true;
                        break;
                    }
                }

                if (!alreadyExist)
                {
                    Application.Current.Resources.MergedDictionaries.Add(rdict);
                    Console.WriteLine(path);
                }
            }

        }
    }

    internal static List<string> GetDictionaries(String type, string style)
    {
        List<string> styles = new List<string>();
        #region Switch

        switch (type)
        {
            case "CustomTextBoxExt":
                styles.Add("/TextBoxExt;component/TextBoxExt/TextBoxExtStyle.xaml");
                break;
            case "ButtonExt":
                styles.Add("/TextBoxExt;component/ButtonExt/ButtonExtStyle.xaml");
                break;
            case "Label":
                styles.Add("/TextBoxExt;component/LabelStyle.xaml");
                break;
        }

        # endregion

        return styles;
    }

}

réglage

local:SkinExt.Theme="Material" 

dans mainwindow/grid fonctionne comme prévu lorsque les enfants sont ajoutés directement. Mais, lorsque vous utilisez le style de lazyextension ci-dessous, cela ne fonctionne pas.

public static class LazyLoadExtensions
{
    public static LazyUIElementCollection GetLazyChildrens(DependencyObject obj)
    {
        return (LazyUIElementCollection)obj.GetValue(LazyChildrensProperty);
    }

    public static void SetLazyChildrens(DependencyObject obj, LazyUIElementCollection value)
    {
        obj.SetValue(LazyChildrensProperty, value);
    }

    public static readonly DependencyProperty LazyChildrensProperty =
        DependencyProperty.RegisterAttached("LazyChildrens", typeof(LazyUIElementCollection), typeof(LazyLoadExtensions), new PropertyMetadata(OnLazyChildrensChanged));

    private static void OnLazyChildrensChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var wrapPanel = d as WrapPanel;
        var childrens = LazyLoadExtensions.GetLazyChildrens(wrapPanel);
        for (int i = 0; i < childrens.Count; i++)
        {
            var child = childrens[i];

                wrapPanel.Children.Add(child);
        }

    }
}

public class LazyUIElementCollection : List<UIElement>
{
    public LazyUIElementCollection()
    {

    }
}

Travaux

 <Grid local:SkinExt.Theme="Material">
    <WrapPanel x:Name="wrapPanel">
        <!--<local:LazyLoadExtensions.LazyChildrens>-->
        <!--<local:LazyUIElementCollection>-->
        <StackPanel Margin="10">
            <TextBlock Margin="0,0,0,8" Text="MS Label" />
            <Label
                Width="200"
                Height="25"
                Content="Material" />
        </StackPanel>
        <StackPanel Margin="10">
            <TextBlock Margin="0,0,0,8" Text="Custom TextBox" />
            <local:CustomTextBoxExt
                Width="200"
                Height="25"
                Text="Material" />
        </StackPanel>
        <!--</local:LazyUIElementCollection>-->
        <!--</local:LazyLoadExtensions.LazyChildrens>-->
    </WrapPanel>
</Grid>

Ne fonctionne pas

<Grid local:SkinExt.Theme="Material">
    <WrapPanel x:Name="wrapPanel">
        <local:LazyLoadExtensions.LazyChildrens>
            <local:LazyUIElementCollection>
                <StackPanel Margin="10">
                    <TextBlock Margin="0,0,0,8" Text="MS Label" />
                    <Label
                        Width="200"
                        Height="25"
                        Content="Material" />
                </StackPanel>
                <StackPanel Margin="10">
                    <TextBlock Margin="0,0,0,8" Text="Custom TextBox" />
                    <local:CustomTextBoxExt
                        Width="200"
                        Height="25"
                        Text="Material" />
                </StackPanel>
            </local:LazyUIElementCollection>
        </local:LazyLoadExtensions.LazyChildrens>
    </WrapPanel>
</Grid>

Fonctionne pour le deuxième élément

Le style s'applique correctement pour la deuxième boîte de texte personnalisée

<Grid local:SkinExt.Theme="Material">
    <WrapPanel x:Name="wrapPanel">
        <local:LazyLoadExtensions.LazyChildrens>
            <local:LazyUIElementCollection>
                <StackPanel Margin="10">
                    <TextBlock Margin="0,0,0,8" Text="MS Label" />
                    <Label
                        Width="200"
                        Height="25"
                        Content="Material" />
                </StackPanel>
                <StackPanel Margin="10">
                    <TextBlock Margin="0,0,0,8" Text="Custom TextBox" />
                    <local:CustomTextBoxExt
                        Width="200"
                        Height="25"
                        Text="Material" />
                    <local:CustomTextBoxExt
                        Width="200"
                        Height="25"
                        Text="Material" />
                </StackPanel>
            </local:LazyUIElementCollection>
        </local:LazyLoadExtensions.LazyChildrens>
    </WrapPanel>
</Grid>

Exemple reproductible: https://drive.google.com/open?id=1iB9sY90T7aRaaRTzVc1EvE2qFU13fHG7

Consultez l'exemple ci-dessus et faites-moi savoir vos idées

5
Durga S

Si cela est utile, l'application du thème à l'intérieur du répartiteur fonctionne comme prévu,

  d.Dispatcher.BeginInvoke(new Action(() =>
            {
                SkinExt.ApplyTheme(d, e.NewValue.ToString());
            }));
1
WPFUser