WPF:从UserControl转换为CustomControl

时间:2011-03-01 11:12:24

标签: .net wpf user-controls wpf-controls

我有一个WPF UserControl - SegmentConrol,它代表一条带有一些文字的行和一个显示方向的数组(>)。

由于我必须自定义这种控件样式,所以我决定切换到CustomControl,因为我认为这在某种程度上更好......

现在,我有一些“麻烦”从UC切换到CC。

特别是,不知道放置<UserControl.Resources>部分的位置。

如果有任何专家建议我欢迎他们。

这是我的UserControl:

<UserControl x:Class="MyNamespace.ctlWpfPlanDeLigne.SegmentControl"
             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" 
             mc:Ignorable="d" 
             xmlns:local="clr-namespace:MyNamespace.ctlWpfPlanDeLigne"
             d:DesignHeight="300" d:DesignWidth="300"
             x:Name="ParentSegmentControl">
    <UserControl.Resources>
        <local:VisibilityConverter x:Key="VisibilityConverter"/>
        <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
        <local:SegmentToStringConverter x:Key="SegmentToStringConverter"/>
    </UserControl.Resources>
    <Canvas Background="Transparent">
        <Line x:Name="line"              
              X1="{Binding ElementName=ParentSegmentControl, Path=X1}"
              Y1="{Binding ElementName=ParentSegmentControl, Path=Y1}"
              X2="{Binding ElementName=ParentSegmentControl, Path=X2}"
              Y2="{Binding ElementName=ParentSegmentControl, Path=Y2}"  IsHitTestVisible="True"/>

        <Label x:Name="label" 
               Foreground="{Binding ElementName=ParentSegmentControl, Path=LabelForeground}" 
               Background="{Binding ElementName=ParentSegmentControl, Path=LabelBackground}"
               Visibility="{Binding ElementName=ParentSegmentControl, Path=IsLabelUsed, Converter={StaticResource BoolToVisibilityConverter}}"
               >
            <Label.Effect>
                <DropShadowEffect BlurRadius="2" Color="White" Opacity="1" RenderingBias="Performance" ShadowDepth="0" />
            </Label.Effect>
        </Label>
        <Polygon Name="arrow" Visibility="{Binding ElementName=ParentSegmentControl, Path=IsArrowUsed, Converter={StaticResource BoolToVisibilityConverter}}"/>
    </Canvas>
</UserControl>

Bellow,是新CustomControl的Themes/Generic.xaml文件,我重构了旧的UserControl:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyNamespace.ctlWpfPlanDeLigne">

    <Style TargetType="{x:Type local:SegmentControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:SegmentControl}">
                    <Canvas Background="Transparent">
                        <Line x:Name="line"...

                        <Label x:Name="label"...
                        <Polygon x:Name="arrow" ...
                    </Canvas>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

编辑:

如何处理代码

    public SegmentControl()
    {
        this.line.StrokeDashCap = PenLineCap.Round;
        this.arrow.StrokeLineJoin = PenLineJoin.Round;
        this.Background = Brushes.Transparent;
    }

未定义this.linethis.arrow时?感谢。

编辑2

Generic.XAML:

<Style TargetType="{x:Type local:SegmentControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:SegmentControl}">
                <Canvas Background="Transparent">
                    <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    </Border>
                    <Line x:Name="PART_line"
                          X1="{Binding ElementName=ParentSegmentControl, Path=X1}"
                          Y1="{Binding ElementName=ParentSegmentControl, Path=Y1}"
                          X2="{Binding ElementName=ParentSegmentControl, Path=X2}"
                          Y2="{Binding ElementName=ParentSegmentControl, Path=Y2}"
                          IsHitTestVisible="True"/>

                    <Label x:Name="PART_label"
                           Foreground="{Binding ElementName=ParentSegmentControl, Path=LabelForeground}"
                           Background="{Binding ElementName=ParentSegmentControl, Path=LabelBackground}"
                           Visibility="{Binding ElementName=ParentSegmentControl, Path=IsLabelUsed, Converter={StaticResource BoolToVisibilityConverter}}">
                        <Label.Effect>
                            <DropShadowEffect BlurRadius="2" Color="White" Opacity="1" RenderingBias="Performance" ShadowDepth="0" />
                        </Label.Effect>
                    </Label>
                    <Polygon x:Name="PART_arrow" 
                             Visibility="{Binding ElementName=ParentSegmentControl, Path=IsArrowUsed, Converter={StaticResource BoolToVisibilityConverter}}"/>
                </Canvas>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>  

.cs:

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        this.line = this.FindName("PART_line") as Line;      // null
        this.arrow = this.FindName("PART_arrow") as Polygon; // null
        this.label = this.FindName("PART_label") as Label;   // null

        this.line.StrokeDashCap = PenLineCap.Round;
        this.arrow.StrokeLineJoin = PenLineJoin.Round;
    }

2 个答案:

答案 0 :(得分:6)

我不明白为什么你不能把它们直接放入资源词典?然后可以通过其他样式/模板重复使用它们。

 <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyNamespace.ctlWpfPlanDeLigne">

            <local:VisibilityConverter x:Key="VisibilityConverter"/>
            <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
            <local:SegmentToStringConverter x:Key="SegmentToStringConverter"/>

    <Style....

修改

在回答第二个问题时,您需要在代码中执行此操作:

Line line = this.FindName("line") as Line;
Polygon arrow = this.FindName("arrow") as Polygon;

虽然通常的做法是使用“PART_”命名控件,使其显示为

Line line = this.FindName("PART_line") as Line;
Polygon arrow = this.FindName("PART_arrow") as Polygon;

此名称对应于xaml中给出的x:名称。

编辑3:

您需要确保您的窗口知道您的资源字典,如下所示:

 <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Namespace.Controls;component/Themes/CustomControls.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </WindowResources>

答案 1 :(得分:1)

另请注意,您必须添加

    static SegmentControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(SegmentControl), new FrameworkPropertyMetadata(typeof(SegmentControl)));
    }

SegmentControl以便应用默认主题而不直接指定样式。