当前位置:首页 > Windows程序 > 正文

WPF自定义控件第一

2021-03-26 Windows程序

前期一个小任务需要实现一个类似含步骤进度条的控件。虽然对于XAML的了解还不是足够深入,还是摸索着做了一个。这篇文章介绍下实现这个控件的步骤,最后会放出代码。还请高手们给出更好的思路。同时也希望这里的思路能给同道中人一些帮助。话不多说,开始正题。

实现中的一些代码采用了网上现有的方案,代码中通过注释标记了来源,再次对代码作者一并表示感谢。

首先放一张最终效果图。

节点可以被点击

控件会根据绑定的集合数据生成一系列节点,根据集合中的数据还可以按比例放置节点的位置。

节点的实体代码如下:

public class FlowItem {     public FlowItem()     {     }     public FlowItem(int id, string title,double offsetRate)     {         Id = id;         Title = title;         OffsetRate = offsetRate;     }     public int Id { get; set; }     public string Title { get; set; }     public double OffsetRate { get; set; } }

其中三个属性分别代表了节点的编号,标题和偏移量(用来确定节点在整个条中的位置)。

控件的实现

忘了很久以前在哪看到过一句话,说设计WPF控件时不一定按照MVVM模式来设计,但一定要确保设计的控件可以按照MVVM模式来使用。本控件也是本着这么目标来完成。

控件实现为TemplatedControl,个人认为这种方式更为灵活,做出来的控件可复用度更高。反之UserControl那种组合控件的方式更适用于一个项目内复用的需要。

遵循一般的原则,,我们将控件单独放于一个项目中。在TemplatedControl项目中,“模板”即XAML内容一般都放置在一个名为Generic.xaml文件中,这个文件应该放置在解决方案Themes文件夹下。

如果要使用Themes/Generic.xaml这个默认的模板样式地址,要保证AssemblyInfo.cs中如下语句:

[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]

另外也不要试图修改Themes/Generic.xaml这个文件位置了。虽然据说是可以改,但不知道会不会有潜在问题。RoR流行时常说“约定大于配置”,就把这个路径当作一个约定就好了。

一般来说控件的模板也不宜直接放到Generic.xaml而是每个控件都定义到一个单独的xaml文件,然后在Generic中用如下方式进行引用。这样可以有效的防止Generic.xaml文件变的过大,也可以更利于项目模板的查找和修改(直接定位到相关文件即可,博主常用Ctrl+T键定位文件,也不知道这个是VS的功能还是Resharper的功能)。

<ResourceDictionary Source="/Zq.Control;component/Flow/FlowControl.xaml"></ResourceDictionary>

这样控件的模板就可以移入FlowControl.xaml中,接着我们就看一下这里面控件模板的定义:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"                     xmlns:system="clr-namespace:System;assembly=mscorlib"                     xmlns:flow="clr-namespace:Zq.Control.Flow">     <flow:MultiThicknessConverter x:Key="FlowMultiThicknessConverter"></flow:MultiThicknessConverter>     <flow:MultiWidthAnimationConverter x:Key="FlowMultiWidthAnimationConverter"></flow:MultiWidthAnimationConverter>     <system:Double x:Key="FlowDoubleZero">0</system:Double>     <Duration x:Key="FlowDuration">0:0:1.5</Duration>     <Style TargetType="{x:Type flow:FlowControl}">         <Setter Property="NodeWidth" Value="30"></Setter>         <Setter Property="Template">             <Setter.Value>                 <ControlTemplate TargetType="{x:Type flow:FlowControl}">                     <Grid VerticalAlignment="Top">                         <Grid.Triggers>                             <EventTrigger RoutedEvent="SizeChanged">                                 <BeginStoryboard>                                     <Storyboard >                                         <DoubleAnimation Storyboard.TargetName="Bar" Storyboard.TargetProperty="Tag"                                              From="0" To="1" Duration="{StaticResource FlowDuration}"/>                                     </Storyboard>                                 </BeginStoryboard>                             </EventTrigger>                         </Grid.Triggers>                         <Rectangle x:Name="Bar" Panel.ZIndex="0" StrokeThickness="0" Fill="#61d0b3"                                     HorizontalAlignment="Left" VerticalAlignment="Top"                                    Height="{TemplateBinding BarHeight}">                             <Rectangle.Margin>                                 <MultiBinding Converter="{StaticResource FlowMultiThicknessConverter}">                                     <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="BarMarginLeft"></Binding>                                     <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="BarMarginTop"></Binding>                                     <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="BarMarginLeft"></Binding>                                     <Binding Source="{StaticResource FlowDoubleZero}"></Binding>                                 </MultiBinding>                             </Rectangle.Margin>                             <Rectangle.Tag>                                 <system:Double>0.0</system:Double>                             </Rectangle.Tag>                             <Rectangle.Width>                                 <MultiBinding Converter="{StaticResource FlowMultiWidthAnimationConverter}">                                     <Binding Path="ShadowWidth" RelativeSource="{RelativeSource TemplatedParent}" />                                     <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />                                 </MultiBinding>                             </Rectangle.Width>                         </Rectangle>                         <ItemsPresenter />                     </Grid>                 </ControlTemplate>             </Setter.Value>         </Setter>         <Setter Property="ItemsPanel">             <Setter.Value>                 <ItemsPanelTemplate>                     <flow:FlowControlPanel AnimationDuration="{StaticResource FlowDuration}" />                 </ItemsPanelTemplate>             </Setter.Value>         </Setter>     </Style> </ResourceDictionary>

这个xaml文件的根节点是ResourceDictionary,表示其中内容是各种资源:样式,模板等等..

最开始的部分定义了模板中用到的一些Conveter及常量值。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/67830.html