WPF:从用户控件转换为CustomControl转换为、控件、用户、WPF

2023-09-04 04:43:27 作者:撩人女杀手

我有一个WPF 用户控件 - SegmentConrol ,即重新presents一些文本和行排列显示方向(>)。

因为我有自定义此控件风格,我决定切换到CustomControl,因为我读这是最好的方式......

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

特别,不知道的放在哪里< UserControl.Resources> 部分

如果任何专家能告诉我他们是欢迎的。

一个类似Office用户界面的WPF库

下面是我的用户:

 <用户控件X:类=MyNamespace.ctlWpfPlanDeLigne.SegmentControl
             的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
             的xmlns:X =htt​​p://schemas.microsoft.com/winfx/2006/xaml
             的xmlns:MC =htt​​p://schemas.openxmlformats.org/markup-compatibility/2006
             的xmlns:D =htt​​p://schemas.microsoft.com/ex$p$pssion/blend/2008
             MC:可忽略=D
             XMLNS:地方=CLR的命名空间:MyNamespace.ctlWpfPlanDeLigne
             D:DesignHeight =300D:DesignWidth =300
             X:名称=ParentSegmentControl>
    < UserControl.Resources>
        <地方:VisibilityConverter X:关键=VisibilityConverter/>
        <地方:BoolToVisibilityConverter X:关键=BoolToVisibilityConverter/>
        <地方:SegmentToStringConverter X:关键=SegmentToStringConverter/>
    < /UserControl.Resources>
    <帆布背景=透明>
        <行x:名称=行
              X1 ={结合的ElementName = ParentSegmentControl,路径= X1}
              Y1 ={结合的ElementName = ParentSegmentControl,路径= Y1}
              X2 ={结合的ElementName = ParentSegmentControl,路径= X2}
              Y2 ={结合的ElementName = ParentSegmentControl,路径= Y2}IsHitTestVisible =真/>

        <标号x:名称=标签
               前景={结合的ElementName = ParentSegmentControl,路径= LabelForeground}
               背景={结合的ElementName = ParentSegmentControl,路径= LabelBackground}
               能见度={结合的ElementName = ParentSegmentControl,路径= IsLabelUsed,转换器= {的StaticResource BoolToVisibilityConverter}}
               >
            < Label.Effect>
                < D​​ropShadowEffect BlurRadius =2颜色=白不透明度=1RenderingBias =性能ShadowDepth =0/>
            < /Label.Effect>
        < /标签>
        <多边形名称=箭头能见度={结合的ElementName = ParentSegmentControl,路径= IsArrowUsed,转换器= {的StaticResource BoolToVisibilityConverter}}/>
    < /帆布>
< /用户控件>
 

贝娄,是主题/ Generic.xaml 新CustomControl我重构旧的用户控件文件:

 <的ResourceDictionary
    的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
    的xmlns:X =htt​​p://schemas.microsoft.com/winfx/2006/xaml
    XMLNS:地方=CLR的命名空间:MyNamespace.ctlWpfPlanDeLigne>

    <风格的TargetType ={X:类型本地:SegmentControl}>
        < setter属性=模板>
            < Setter.Value>
                <的ControlTemplate的TargetType ={X:类型本地:SegmentControl}>
                    <帆布背景=透明>
                        <行x:名称=行......

                        <标号x:名称=标签?
                        <多边形X:名称=箭头...
                    < /帆布>
                < /控件模板>
            < /Setter.Value>
        < /二传手>
    < /样式和GT;
< / ResourceDictionary中>
 

修改

做什么用的code

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

this.line this.arrow 没有定义?谢谢你。

修改2

Generic.XAML:

 <风格的TargetType ={X:类型本地:SegmentControl}>
    < setter属性=模板>
        < Setter.Value>
            <的ControlTemplate的TargetType ={X:类型本地:SegmentControl}>
                <帆布背景=透明>
                    < BORDER背景={TemplateBinding背景}
                        BorderBrush ={TemplateBinding BorderBrush}
                        了borderThickness ={TemplateBinding了borderThickness}>
                    < /边框>
                    <行x:名称=PART_line
                          X1 ={结合的ElementName = ParentSegmentControl,路径= X1}
                          Y1 ={结合的ElementName = ParentSegmentControl,路径= Y1}
                          X2 ={结合的ElementName = ParentSegmentControl,路径= X2}
                          Y2 ={结合的ElementName = ParentSegmentControl,路径= Y2}
                          IsHitTestVisible =真/>

                    <标号x:名称=PART_label
                           前景={结合的ElementName = ParentSegmentControl,路径= LabelForeground}
                           背景={结合的ElementName = ParentSegmentControl,路径= LabelBackground}
                           能见度={结合的ElementName = ParentSegmentControl,路径= IsLabelUsed,转换器= {的StaticResource BoolToVisibilityConverter}}>
                        < Label.Effect>
                            < D​​ropShadowEffect BlurRadius =2颜色=白不透明度=1RenderingBias =性能ShadowDepth =0/>
                        < /Label.Effect>
                    < /标签>
                    <多边形X:名称=PART_arrow
                             能见度={结合的ElementName = ParentSegmentControl,路径= IsArrowUsed,转换器= {的StaticResource BoolToVisibilityConverter}}/>
                < /帆布>
            < /控件模板>
        < /Setter.Value>
    < /二传手>
< /样式和GT;
 

的.cs:

 公共覆盖无效OnApplyTemplate()
    {
        base.OnApplyTemplate();

        this.line = this.FindName(PART_line)为线; // 空值
        this.arrow = this.FindName(PART_arrow)为多边形; // 空值
        this.label = this.FindName(PART_label)作为标签; // 空值

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

解决方案

我不明白为什么你不能只是把它们直接进入资源字典?它们可以被重新用于其他样式/模板。

 <的ResourceDictionary
        的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
        的xmlns:X =htt​​p://schemas.microsoft.com/winfx/2006/xaml
        XMLNS:地方=CLR的命名空间:MyNamespace.ctlWpfPlanDeLigne>

            <地方:VisibilityConverter X:关键=VisibilityConverter/>
            <地方:BoolToVisibilityConverter X:关键=BoolToVisibilityConverter/>
            <地方:SegmentToStringConverter X:关键=SegmentToStringConverter/>

    <风格....
 

编辑:

在回答你的第二个问题,你需要做的code:

 行线= this.FindName(线)的线路;
多边形箭头= this.FindName(箭头)为多边形;
 

虽然它是常见的做法,所以它读取命名为PART_你的控件

 行线= this.FindName(PART_line)为线;
多边形箭头= this.FindName(PART_arrow)为多边形;
 

这名对应于x:在XAML给出名称。

修改3:

您将需要确保你的窗口知道你的资源字典是这样的:

 < Window.Resources>
        <的ResourceDictionary>
            < ResourceDictionary.MergedDictionaries>
                < ResourceDictionary中源=/ Namespace.Controls;组件/主题/ CustomControls.xaml/>
            < /ResourceDictionary.MergedDictionaries>
        < / ResourceDictionary中>
    < / WindowResources>
 

I have a WPF UserControl - SegmentConrol, that represents a line with some text and an array displaying the direction (>).

As I have to customize this control styles, I decided to switch to a CustomControl, because I read this is better in a way...

Now, I have some "troubles" to switch from UC to CC.

Particularly, no idea where to put the <UserControl.Resources> part.

If any of experts could advise me they are welcomed.

Here is my 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, is the Themes/Generic.xaml file of the new CustomControl I refactor the old 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>

Edit:

What to do with the code

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

when this.line or this.arrow is not defined? Thanks.

EDIT 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;
    }

解决方案

I don't see why you can't just put them straight into the resource dictionary? They can then be re-used by other styles/templates..

 <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....

EDIT:

In response to your second question, you will need to do this in code:

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

Although it's common practice to name your controls with "PART_" so it reads

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

This name corresponds to the x:Name given in the xaml..

EDIT 3:

You'll need to make sure your window knows about your resource dictionary like this:

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