相关文章推荐
知识渊博的帽子  ·  scrapy ...·  3 周前    · 
知识渊博的帽子  ·  Anonymous user has no ...·  7 月前    · 
知识渊博的帽子  ·  开源C# ...·  8 月前    · 
知识渊博的帽子  ·  Project Converter ...·  8 月前    · 
知识渊博的帽子  ·  [Solved] Chicken and ...·  9 月前    · 
知识渊博的帽子  ·  The Basics — CVX ...·  9 月前    · 
威武的香瓜  ·  [转]Entity Framework ...·  3 小时前    · 
WPF上位机自定义控件系列:步骤 WxStepBar

WPF上位机自定义控件系列:步骤 WxStepBar

WPF 上位机自定义控件系列

  • 步骤 WxStepBar

类似 ListBox、TabControl 等控件,包含两项内容:WxStepBar 和 WxStepBarItem,分别继承自 ContentControl 和 ItemsControl,支持数据绑定

WxStepBarItem 控件,包含三种状态

public enum StepBarState
    Default,
    Busy,
    Complete,


using System.Windows;
using System.Windows.Controls;
namespace WpfControlsX.ControlX
    /// ----------------------------------------------------------------
    /// Author      : BigWang
    /// Created Time: 2023/4/4 22:32:06
    /// Description :
    /// ----------------------------------------------------------------
    /// Version      Modified Time              Modified By     Modified Content
    /// V1.0.0.0     2023/4/4 22:32:06                     BigWang         首次编写         
    public class WxStepBarItem : ContentControl
        /// <summary>
        /// 序号
        /// </summary>
        public int Index
            get => (int)GetValue(IndexProperty);
            internal set => SetValue(IndexProperty, value);
        public static readonly DependencyProperty IndexProperty =
            DependencyProperty.Register("Index", typeof(int), typeof(WxStepBarItem), new PropertyMetadata(-1));
        /// <summary>
        /// 当前状态
        /// </summary>
        public StepBarState State
            get => (StepBarState)GetValue(StateProperty);
            set => SetValue(StateProperty, value);
        public static readonly DependencyProperty StateProperty =
            DependencyProperty.Register("State", typeof(StepBarState), typeof(WxStepBarItem), new PropertyMetadata(StepBarState.Default));
        /// <summary>
        /// 图标尺寸
        /// </summary>
        public double IconSize
            get => (double)GetValue(IconSizeProperty);
            set => SetValue(IconSizeProperty, value);
        public static readonly DependencyProperty IconSizeProperty =
            DependencyProperty.Register("IconSize", typeof(double), typeof(WxStepBarItem), new PropertyMetadata(12d));
        /// <summary>
        /// 圆角
        /// </summary>
        public CornerRadius CornerRadius
            get => (CornerRadius)GetValue(CornerRadiusProperty);
            set => SetValue(CornerRadiusProperty, value);
        public static readonly DependencyProperty CornerRadiusProperty =
            DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(WxStepBarItem), new PropertyMetadata(new CornerRadius(0)));

WxStepBar 控件

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace WpfControlsX.ControlX
    [TemplatePart(Name = ProgressBarTemplateName, Type = typeof(ProgressBar))]
    public class WxStepBar : ItemsControl
        static WxStepBar()
            DefaultStyleKeyProperty.OverrideMetadata(typeof(WxStepBar), new FrameworkPropertyMetadata(typeof(WxStepBar)));
        private const string ProgressBarTemplateName = "PART_ProgressBar";
        private ProgressBar _progressBar;
        public int StepIndex
            get => (int)GetValue(StepIndexProperty);
            set => SetValue(StepIndexProperty, value);
        public static readonly DependencyProperty StepIndexProperty =
            DependencyProperty.Register("StepIndex", typeof(int), typeof(WxStepBar), new PropertyMetadata(0, OnStepIndexChanged));
        private static void OnStepIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            WxStepBar step = (WxStepBar)d;
            int stepIndex = (int)e.NewValue;
            step.UpdateStepItemState(stepIndex);
        private void UpdateStepItemState(int stepIndex)
            int count = Items.Count;
            if (count <= 0)
                return;
            for (int i = 0; i < Items.Count; i++)
                if (ItemContainerGenerator.ContainerFromIndex(i) is WxStepBarItem stepItem)
                    stepItem.State = i < stepIndex ? StepBarState.Complete : i == stepIndex ? StepBarState.Busy : StepBarState.Default;
        public override void OnApplyTemplate()
            base.OnApplyTemplate();
            _progressBar = GetTemplateChild(ProgressBarTemplateName) as ProgressBar;
        protected override void OnRender(DrawingContext drawingContext)
            base.OnRender(drawingContext);
            int count = Items.Count;
            if (_progressBar == null || count <= 0)
                return;
            _progressBar.Maximum = count - 1;
            _progressBar.Value = StepIndex;
            _progressBar.Width = ActualWidth / count * (count - 1);
        protected override bool IsItemItsOwnContainerOverride(object item)
            return item is WxStepBarItem;
        protected override DependencyObject GetContainerForItemOverride()
            return new WxStepBarItem();
        public WxStepBar()
            ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
        public void Next()
            if (StepIndex >= Items.Count)
                StepIndex = Items.Count - 1;
            StepIndex++;
        public void Prev()
            if (StepIndex < 0)
                StepIndex = -1;
                StepIndex--;
        private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
            if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                int count = Items.Count;
                if (count <= 0)
                    return;
                UpdateStepItemState(StepIndex);

xaml 样式

<!--#region WxStepBar -->
<Style x:Key="StepBarItemStyle" TargetType="{x:Type cx:WxStepBarItem}">
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="BorderBrush" Value="{DynamicResource BrushWaterMark}"/>
    <Setter Property="Foreground" Value="{DynamicResource BrushText}"/>
    <Setter Property="Background" Value="{DynamicResource BrushRegion}"/>
    <Setter Property="FontSize" Value="16"/>
    <Setter Property="CornerRadius" Value="16"/>
    <Setter Property="IconSize" Value="32"/>
    <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type cx:WxStepBarItem}">
                    <StackPanel>
                        <cx:WxSimplePanel>
                            <Ellipse Width="{TemplateBinding IconSize}" Height="{TemplateBinding IconSize}" Fill="{TemplateBinding Background}" HorizontalAlignment="Center"/>
                            <Border Background="{TemplateBinding Background}" HorizontalAlignment="Center" CornerRadius="{TemplateBinding CornerRadius}"
                                    BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}"
                                    Height="{TemplateBinding IconSize}" Width="{TemplateBinding IconSize}">
                                <cx:WxSimplePanel>
                                    <TextBlock Name="PART_Index" Foreground="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="{TemplateBinding FontSize}"
                                               Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type cx:WxStepBarItem}}, Converter={StaticResource WxStepBarItem2Index}}"/>
                                    <Path Name="PART_PathComplete" Data="{StaticResource IconCheck}" Fill="{TemplateBinding Foreground}" Stretch="Uniform"
                                          Width="14" Height="14" Visibility="Collapsed"/>
                                </cx:WxSimplePanel>
                            </Border>
                        </cx:WxSimplePanel>
                        <ContentPresenter HorizontalAlignment="Center" TextElement.FontWeight="Black" TextElement.Foreground="{DynamicResource BrushText}" Margin="0,6,0,0"
                                          ContentTemplate="{Binding ItemTemplate,RelativeSource={RelativeSource AncestorType=cx:WxStepBar}}"/>
                    </StackPanel>
                    <ControlTemplate.Triggers>
                        <Trigger Property="State" Value="Default">
                            <Setter Property="Foreground" Value="{DynamicResource BrushText}"/>
                            <Setter Property="Background" Value="{DynamicResource BrushRegion}"/>
                            <Setter TargetName="PART_PathComplete" Property="Visibility" Value="Collapsed"/>
                            <Setter TargetName="PART_Index" Property="Visibility" Value="Visible"/>
                        </Trigger>
                        <Trigger Property="State" Value="Busy">
                            <Setter Property="Background" Value="{DynamicResource BrushPrimary}"/>
                            <Setter Property="BorderBrush" Value="{DynamicResource BrushPrimary}"/>
                            <Setter Property="Foreground" Value="{DynamicResource BrushReversedText}"/>
                            <Setter TargetName="PART_PathComplete" Property="Visibility" Value="Collapsed"/>
                            <Setter TargetName="PART_Index" Property="Visibility" Value="Visible"/>
                        </Trigger>
                        <Trigger Property="State" Value="Complete">
                            <Setter Property="Background" Value="{DynamicResource BrushSuccess}"/>
                            <Setter Property="BorderBrush" Value="{DynamicResource BrushSuccess}"/>
                            <Setter Property="Foreground" Value="{DynamicResource BrushReversedText}"/>
                            <Setter TargetName="PART_PathComplete" Property="Visibility" Value="Visible"/>
                            <Setter TargetName="PART_Index" Property="Visibility" Value="Collapsed"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
</Style>
<Style TargetType="{x:Type cx:WxStepBar}">
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="Focusable" Value="False"/>
    <Setter Property="Background" Value="Red"/>
    <Setter Property="ItemContainerStyle" Value="{StaticResource StepBarItemStyle}"/>
    <Setter Property="VerticalContentAlignment" Value="Top"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type cx:WxStepBar}">
                <cx:WxSimplePanel>
                    <ProgressBar x:Name="PART_ProgressBar" Margin="0,18" Height="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                 HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                 Value="{Binding StepIndex,RelativeSource={RelativeSource AncestorType=cx:WxStepBar}}"/>
                    <ItemsPresenter/>
                </cx:WxSimplePanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
 
推荐文章