开发者

WPF Style Property Setters not work for all types

开发者 https://www.devze.com 2023-02-15 18:07 出处:网络
I read the description on Styles, Style.Triggers andProperty-Setters several times, but I still, if the styles are applied or not seem to be completely random.

I read the description on Styles, Style.Triggers andProperty-Setters several times, but I still, if the styles are applied or not seem to be completely random.

In the following example, the Canvas will turn white, the Path, however, is not affected at all:

<UserControl x:Class="Still.Tooll.CurveEditPoint"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Still.Tooll"
             >
    <UserControl.Style>
        <Style>
        开发者_如何转开发    <Style.Triggers>
                <Trigger Property="local:CurveEditPoint.IsSelected" Value="true">
                    <Setter Property="Path.Stroke" Value="#fff"/>
                    <Setter Property="Canvas.Background" Value="#fff"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </UserControl.Style>
    <Canvas>
        <Path StrokeThickness="0.5" Data="M 0, 0 L 40,20"/>  
    </Canvas>
</UserControl>

I guess this has to do something with the nesting of the Path inside the Canvas, but then again, there must be a way to style sub elements of a control.

I have to admit, that coming from HTML/CSS, I find the WPF styling unnecessarily difficult! Any points or explanations welcome!

thanks, tom


You cannot access the visual elements of the UserControl in that manner. The Style can only set properties on the UserControl. So your first setter ("Path.Stroke") will look for a property on your UserControl named Path, and then set it's Stroke. It doesn't apply it to all Paths in your UserControl or the one you have defined below.

The Canvas's Background is not being set. The background of the UserControl is being set, and the canvas will continue to have no background. The reason the setter works on the UserControl is because the Canvas.BackgroundProperty and UserControl.BackgroundProperty are the same dependency property (even though they are different owners).

I'd recommend exposing dependency properties on your UserControl, which are changed by your Style and bound to by your elements. Something like this (which reuses the Background/Foreground properties):

<UserControl x:Name="userControl" x:Class="Still.Tooll.CurveEditPoint"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Still.Tooll"
         >

    <UserControl.Style>
        <Style>
            <Style.Triggers>
                <Trigger Property="local:CurveEditPoint.IsSelected" Value="true">
                    <Setter Property="Foreground" Value="#fff"/>
                    <Setter Property="Background" Value="#fff"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </UserControl.Style>

    <Canvas>
        <Path Stroke="{Binding Element=userControl, Path=Foreground}" StrokeThickness="0.5" Data="M 0, 0 L 40,20"/>  
    </Canvas>
</UserControl>


Though not through style but here is a workaround that i used to achieve this thing in my app.

*Visual Children Finder *

    /// <summary>
    /// This function iterates through the visual tree and returns the child item of the type child item.
    /// </summary>
    /// <typeparam name="childItem"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static TChild FindVisualChild<TChild>(DependencyObject obj)
        where TChild : DependencyObject
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);

            if (child != null && child is TChild)
            {
                return (TChild)child;
            }
            else
            {
                TChild childOfChild = FindVisualChild<TChild>(child);

                if (childOfChild != null)
                {
                    return childOfChild;
                }
            }
        }

        return null;
    }

Use it in some code behind like - ListBox deviceImagesListBox = UtilityFunctions.FindVisualChild<RealisticListBox>(selectedRoomListBox);

Now you have the control and you can play with it in Code Behind. I agree we should look for something to acheive this using STYLE in XAML


If you define the Style as a Resourceon the UserControl and then apply it to each of the elements it might work:

<UserControl x:Class="Still.Tooll.CurveEditPoint"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Still.Tooll"
         >

<UserControl.Resources>

    <Style x:Key="style">
        <Style.Triggers>
            <Trigger Property="local:CurveEditPoint.IsSelected" Value="true">
                <Setter Property="Path.Stroke" Value="#fff"/>
                <Setter Property="Canvas.Background" Value="#fff"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

<Canvas Style="{StaticResource style}">
    <Path StrokeThickness="0.5"   Data="M 0, 0 L 40,20" Style="{StaticResource style}"/>
</Canvas>

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号