WPF自定义控件(教程含源码)-用量进度条

实战需求

在称量过程中,显示实时重量。且可以直观体现“接近量”、“目标量”、“超过量”。

控件最终效果如下图所示。

蓝色表示接近量、绿色表示目标量、红色表示超过量。

话不多说,下面展示源码,有问题的在留言区留言,我会及时回复.

控件模板前台定义RProgress.xaml如下:

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

    <!--游标偏移转换-->
    <local:CursorOffsetConverter x:Key="cursorOffsetConverter" />
    
    <!--进度条宽度转换-->
    <local:ProgressWidthConverter x:Key="progressWidthConverter" />

    <!--游标样式-->
    <Style x:Key="CursorStyle" TargetType="{x:Type ContentControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">
                    <Grid HorizontalAlignment="Right" >
                        <Path  Stroke="{TemplateBinding Background}" StrokeThickness="1" Fill="{TemplateBinding Background}" Stretch="Uniform" HorizontalAlignment="Right" VerticalAlignment="Top"  Width="20" Height="10"
                               Data="M0,0 L1,-1 L-1,-1 z" SnapsToDevicePixels="True" />
                        <Path Stroke="{TemplateBinding Background}" StrokeThickness="1" Fill="{TemplateBinding Background}" Stretch="Uniform" HorizontalAlignment="Center" 
                               Data="M0,0 L0,4" SnapsToDevicePixels="True"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <ControlTemplate x:Key="RProgress_Template" TargetType="local:RProgress">
        <Grid ClipToBounds="True">
            <Grid.RowDefinitions>
                <RowDefinition Height="10" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>

            <Border Grid.Row="1" SnapsToDevicePixels="True" BorderBrush="#C2C2C2" BorderThickness="1" />
            <Border Grid.Row="1" SnapsToDevicePixels="True" Background="SkyBlue" Margin="1" x:Name="progress"  HorizontalAlignment="Left">
                <Border.Width>
                    <MultiBinding Converter="{StaticResource progressWidthConverter}">
                        <Binding Path="Value" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RProgress}" />
                        <Binding Path="High" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RProgress}" />
                        <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RProgress}" />
                    </MultiBinding>
                </Border.Width>
            </Border>
            <TextBlock Grid.Row="1" Text="{TemplateBinding Text}" VerticalAlignment="Center" Margin="10 0"/>

            <Grid Grid.RowSpan="2" HorizontalAlignment="Right">
                <ContentControl x:Name="cursorLow" Style="{StaticResource CursorStyle}" HorizontalAlignment="Right" Background="Blue" >
                    <ContentControl.RenderTransform>
                        <TranslateTransform  >
                            <TranslateTransform.X>
                                <MultiBinding Converter="{StaticResource cursorOffsetConverter}">
                                    <Binding Path="Low" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RProgress}" />
                                    <Binding Path="High" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RProgress}" />
                                    <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RProgress}" />
                                </MultiBinding>
                            </TranslateTransform.X>
                        </TranslateTransform>
                    </ContentControl.RenderTransform>
                </ContentControl>
                <ContentControl x:Name="cursorNormal" Style="{StaticResource CursorStyle}" HorizontalAlignment="Right" Background="Green" >
                    <ContentControl.RenderTransform>
                        <TranslateTransform  >
                            <TranslateTransform.X>
                                <MultiBinding Converter="{StaticResource cursorOffsetConverter}">
                                    <Binding Path="Target" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RProgress}" />
                                    <Binding Path="High" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RProgress}" />
                                    <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RProgress}" />
                                </MultiBinding>
                            </TranslateTransform.X>
                        </TranslateTransform>
                    </ContentControl.RenderTransform>
                </ContentControl>
                <ContentControl x:Name="cursorHigh" Style="{StaticResource CursorStyle}" HorizontalAlignment="Right" Background="Red"  />
            </Grid>
        </Grid>
    </ControlTemplate>
</ResourceDictionary>

后台代码cs如下:

 public partial class RProgress: RangeBase
    {
        public const double CursorWidth = 20;

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

        #region TextProperty 进度跳上显示的文本
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(RProgress), new PropertyMetadata(""));

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
        #endregion

        #region LowProperty 最小用量
        public static readonly DependencyProperty LowProperty =
            DependencyProperty.Register("Low", typeof(double), typeof(RProgress), new PropertyMetadata(0d));

        public double Low
        {
            get { return (double)GetValue(LowProperty); }
            set { SetValue(LowProperty, value); }
        }
        #endregion

        #region TargetProperty 目标用量
        public static readonly DependencyProperty TargetProperty =
            DependencyProperty.Register("Target", typeof(double), typeof(RProgress), new PropertyMetadata(0d));

        public double Target
        {
            get { return (double)GetValue(TargetProperty); }
            set { SetValue(TargetProperty, value); }
        }
        #endregion

        #region HighProperty 最大用量
        public static readonly DependencyProperty HighProperty =
            DependencyProperty.Register("High", typeof(double), typeof(RProgress), new PropertyMetadata(0d));

        public double High
        {
            get { return (double)GetValue(HighProperty); }
            set { SetValue(HighProperty, value); }
        }
        #endregion

        #region ValueProperty 当前用量
        public new static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(RProgress), new PropertyMetadata(0d));

        public new double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        #endregion
    }

    //游标偏移转换
    public class CursorOffsetConverter : IMultiValueConverter
    {

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values.Length == 3 && values[0] is double value && values[1] is double high && values[2] is double width)
            {
                return high == 0 ? 0 : (value / high - 1) * (width - RProgress.CursorWidth * 0.5);
            }
            else
            {
                return -40;
            }
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    // 进度值宽度转换
    public class ProgressWidthConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values.Length == 3 && values[0] is double value && values[1] is double high && values[2] is double width)
            {
                return Math.Min(width-2, Math.Max(0, (width - RProgress.CursorWidth * 0.5) * value / high));
            }
            else
            {
                return 0;
            }
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

 使用控件的代码如下:

<Window x:Class="WPFCustomControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFCustomControl"
        xmlns:cr="clr-namespace:WPFCustomControl.Controls"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <cr:RProgress Template="{StaticResource RProgress_Template}" Margin="10" Height="40"
                      Value="110"
                      Low="80" Target="100" High="120"
                      Text="标量刻度显示"/> 
    </Grid>
</Window>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lhyriver

制作不易,打赏给我提供动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值