WPF范围选择控件(RangeSelector)

本文介绍了如何在WPF中创建一个范围选择控件RangeSelector,用于可视化的范围选择。该控件由四个部分组成,包括整个选择范围、选中范围、两个可移动的选择器和选择信息显示按钮。文章详细阐述了控件的基本结构、代码组织、默认模板设计以及如何在实际应用中绑定属性和更改颜色。
摘要由CSDN通过智能技术生成


       在某些应用场景中,我们需要做可视化的范围选择。例如,在进行录像剪辑的时候,我们希望在播放时间轴上通过拖动两个可移动的控件来确定两控件之间的时间轴为我们希望进行录像剪辑的时间范围。WPF中并没有这样的预定义控件,所以如果需要有这样的应用场景,则需要自定义这样的控件。本文便是简述定制这样一个控件的基本的思路。


       一 基本结构

      

       先来看一下这样一个控件的基本结构,如上图所示,总体可分为4个部分,1是整个可选择的范围,2是选中的范围,3是左右两个选择器,可在选择范围轴上移动,4是选择信息显示按钮。

       从控件构成来说,1、2都可以用Path来实现,3的上下两个部分也可以用Path实现,4则是一个TextBlock(之所以不选择Label,是希望能用到TextBlock的TextTrimming属性)。


       二 代码结构

       

       为了便于复用,我将此控件单独封装成了一个库(如有需要,也可以很方便的与其他自定义空间库合并),总体上代码的结构非常简单:一个RangeSelector类的cs代码文件RangeSelector.cs,用于控件的逻辑控制;一个控件默认模板的xaml代码文件RangeSelector.xaml;另外还有三个用于控件辅助控制的数据转换类(Converter)。

       

       三 默认模板

       RangeSelector.xaml定义了控件的默认外观,根据(一)里的基本结构,控件必须要包含以下几个命名部分:

       PART_Range:为Path控件,用于展示总的选择范围。

       PART_Canvas:为Canvas控件,用于承载其他绘制控件的容器,之所以选择Canvas,因为他可以通过SetLeft和SetTop方法方便的设置控件的绝对位置,为选择器的移动提供了方便。

       PART_SelectedRange:为Path控件,选中的范围。

       PART_RangeSelector1/PART_RangeSelector2:范围选择器,本文用两个Path组合的Grid来实现。

       PART_LowerMessageTextBlock/PART_UpperMessageTextBlock:为TextBlock控件,用于显示选择的范围信息。

       具体代码如下:

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

    <cvt:DoubleToGridLengthConverter x:Key="doubleToGridLengthConverter"/>
    <cvt:RangePathMarginConverter x:Key="rangePathMarginConverter"/>
    <cvt:SelectorUpShapeConverter x:Key="selectorUpShapeConverter"/>
    <cvt:SelectorDownShapeConverter x:Key="selectorDownShapeConverter"/>

    <Style TargetType="{x:Type local:RangeSelector}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:RangeSelector}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition/>
                                <RowDefinition Height="auto"/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>

                            <Path x:Name="PART_Range" Grid.Row="1" Panel.ZIndex="0" 
                                  Fill="{TemplateBinding RangeColor}"
                                  HorizontalAlignment="Stretch" 
                                  VerticalAlignment="Stretch"
                                  Stretch="Fill">
                                <Path.Margin>
                                    <MultiBinding Converter="{StaticResource rangePathMarginConverter}">
                                        <Binding Path="SelectorWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type local:RangeSelector}}"/>
                                        <Binding Path="SelectorHeight" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type local:RangeSelector}}"/>
                                    </MultiBinding>
                                </Path.Margin>
                            </Path>

                            <Canvas x:Name="PART_Canvas" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Top">

                                <Path x:Name="PART_SelectedRange" Grid.Row="1" Panel.ZIndex="1"
                                      Fill="{TemplateBinding SelectedRangeColor}" 
                                      HorizontalAlignment="Stretch" 
                                      VerticalAlignment="Stretch"
                                      Stretch="Fill">
                                    <Path.Margin>
                                        <MultiBinding Converter="{StaticResource rangePathMarginConverter}">
                                            <Binding Path="SelectorWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type local:RangeSelector}}"/>
                                            <Binding Path="SelectorHeight" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type local:RangeSelector}}"/>
                                        </MultiBinding>
                                    </Path.Margin>
                                </Path>

                                <Grid x:Name="PART_RangeSelector1" Panel.ZIndex="0"
                                      Canvas.Left="0" Canvas.Top="0" Background="Transparent">
                                    <Grid.RowDefinitions>
                            
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值