wpf - Style setter on the attached property

I believe that you are familiar with the setter in wpf, which enables to set properties of the target control so that you can control the visual/content/template of the controls, normally what you will do is directly set the property which is owned by the target control (or properties from the parent of the target control)

 

while the setter can do more than that, it can also be used to set the attached properties,. here is some example which is used to set the control template of the Contorl called "Expander".

 

 

	<Style x:Key="NomuraExpanderStyle" TargetType="{x:Type Expander}">
		<Setter Property="FocusVisualStyle" Value="{DynamicResource NomuraFocusVisualStyle}"/>		
		<Setter Property="Background" Value="Transparent"/>
		<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
		<Setter Property="VerticalContentAlignment" Value="Stretch"/>
		<Setter Property="BorderBrush" Value="Transparent"/>
		<Setter Property="BorderThickness" Value="1"/>
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="{x:Type Expander}">
					<Border SnapsToDevicePixels="true">
						<DockPanel>
							<ToggleButton x:Name="HeaderSite" FocusVisualStyle="{DynamicResource NomuraFocusVisualStyle}" MinHeight="0" MinWidth="0" Style="{DynamicResource NomuraDownExpanderToggleButtonStyle}" Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" FontStretch="{TemplateBinding FontStretch}" FontStyle="{TemplateBinding FontStyle}" FontWeight="{TemplateBinding FontWeight}" Foreground="{DynamicResource ForegroundBrush}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" DockPanel.Dock="Top"/>
							<ContentPresenter x:Name="ExpandSite" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Focusable="false" Visibility="Collapsed" DockPanel.Dock="Bottom"/>
						</DockPanel>
					</Border>
					<ControlTemplate.Triggers>
						<Trigger Property="IsExpanded" Value="true">
							<Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
						</Trigger>
						<Trigger Property="ExpandDirection" Value="Right">
							<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
							<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
							<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource NomuraRightExpanderToggleButtonStyle}"/>
						</Trigger>
						<Trigger Property="ExpandDirection" Value="Up">
							<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
							<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
							<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource NomuraUpExpanderToggleButtonStyle}"/>
						</Trigger>
						<Trigger Property="ExpandDirection" Value="Down">
							<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Bottom"/>
							<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Top"/>
							<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource NomuraDownExpanderToggleButtonStyle}"/>
						</Trigger>
						<Trigger Property="ExpandDirection" Value="Left">
							<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
							<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
							<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource NomuraLeftExpanderToggleButtonStyle}"/>
						</Trigger>
					</ControlTemplate.Triggers>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
		<Setter Property="Foreground" Value="{DynamicResource ForegroundBrush}"/>
		<Setter Property="ExpandDirection" Value="Down"/>
	</Style>

 

The code is apparent on a Attached properties. 

 

<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>

 

What about if the attached properties is home-made one, can you do the same as well?

well the answer is Yes, you can, but you have to watch for namespace prefix. . 

 

Now, suppose that I have endow the control of the ability to swtich between themes, and I have created an attache properties to help attached the very important information to the Control which it decorate, the control is called c1:FlexGrid....

 

Now here is my Behavior's code. 

 

public class ThemeKindChangedEventArgs : EventArgs
    {
        public ThemeKind ThemeKind { get; internal set; }
    }

    public delegate void ThemeKindChanged(DependencyObject d, ThemeKindChangedEventArgs e);

    public class ThemeKindBehavior
    {
        public static readonly DependencyProperty ThemeKindProperty =
            DependencyProperty.RegisterAttached("ThemeKind", typeof (ThemeKind), typeof (ThemeKindBehavior), new PropertyMetadata(default(ThemeKind), new PropertyChangedCallback(OnThemeKindChanged)));

        public static void SetThemeKind(UIElement element, ThemeKind value)
        {
            element.SetValue(ThemeKindProperty, value);
        }

        public static ThemeKind GetThemeKind(UIElement element)
        {
            return (ThemeKind)element.GetValue(ThemeKindProperty);
        }

        public static event ThemeKindChanged ThemeKindChanged;

        public static void OnThemeKindChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (null != d)
            {
                var flexGrid = d as C1FlexGrid;
                if (flexGrid != null)
                {

                    var oldTheme = (ThemeKind) e.OldValue;
                    var theme = (ThemeKind) e.NewValue;
                    var fac = flexGrid.CellFactory as FilterRowCellFactoryWrapper;
                    fac = new FilterRowCellFactoryWrapper(theme);
                    flexGrid.CellFactory = fac;
                    if (oldTheme != theme)
                    {
                        ThemeKindChanged themeChanged = ThemeKindChanged;
                        if (themeChanged != null)
                        {
                            themeChanged(d, new ThemeKindChangedEventArgs() { ThemeKind = theme });
                        }
                    }
                }
            }

        }
    }

 

To use that, I can use the following. 

<dataitemtheme:ThemeKind x:Key="ThemeKind">Unity</dataitemtheme:ThemeKind>

    <Style  TargetType="c1:C1FlexGrid"
            x:Key="RPMC1FlexGrid"
            >
        <Setter Property="ColumnHeaderBackground" Value="{StaticResource C1FlexGridColumnHeaderBackground}" />
        <Setter Property="ColumnHeaderSelectedBackground" Value="{StaticResource C1FlexGridColumnHeaderSelectedBackground}" />
        <Setter Property="GridLinesBrush">
            <Setter.Value>
                <SolidColorBrush Color="#FFC6D7ED" />
            </Setter.Value>
        </Setter>
        <Setter Property="GroupRowBackground">
            <Setter.Value>
                <SolidColorBrush Color="#FFC6D7ED" />
            </Setter.Value>
        </Setter>
		
		
		<!-- here is where you will do the changes -->
		
		<Setter Property="local:ThemeKindBehavior.ThemeKind" Value="{DynamicResource ThemeKind}" />
    </Style>


 So the key here is the use of namespace prefixed names in the "Property" field of Setter object. 

 

 

 

你可能感兴趣的:(WPF)