WPF 实现步骤控件 框架使用.net40; Visual Studio 2019; Step 继承 ItemsControl 使用 Grid
WPF 实现步骤控件
Visual Studio 2019
;
Step
继承 ItemsControl
使用 Grid
嵌套 ProgressBar
和 ItemsPresenter
.
ProgressBar
用来当作步骤后面的线条,宽等于控件的(ActualWidth / Items.Count) * (Items.Count - 1)
,Maximum = Items.Count - 1
。ItemsPresenter
用来展示步骤 Item
。ItemsPanel - ItemsPanelTemplate - UnifORMGrid Rows="1"
横向展示,UniformGrid Columns="1"
可以控制竖向显示,只不过需要重新自定义 ItemContainerStyle
的样式。
然后创建 StepItem
继承 ContentControl
增加两个属性 Index
用来记录当前是步骤 与 State
记录状态 (等待中、进行中、已完成)。
因为继承了 ContentControl
所以可以在使用时指定 Content
显示内容,在每个步骤下方显示。
实现代码
1) Step.xaml
代码如下:
<ResourceDictionary xmlns="Http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:po="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:controls="clr-namespace:WPFDevelopers.Controls"
xmlns:converts="clr-namespace:WPFDevelopers.Converts">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Basic/ControlBasic.xaml"/>
</ResourceDictionary.MergedDictionaries>
<converts:IndexConverter x:Key="IndexConverter"/>
<Style x:Key="DefaultStepItem" TargetType="{x:Type controls:StepItem}"
BasedOn="{StaticResource ControlBasicStyle}">
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:StepItem}">
<StackPanel>
<controls:SmallPanel>
<Ellipse
Width="45"
Height="30"
Fill="{DynamicResource WindowForegroundColorBrush}"
HorizontalAlignment="Center"/>
<Border
Background="{TemplateBinding Background}"
HorizontalAlignment="Center"
CornerRadius="15"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Height="30"
Width="30">
<controls:SmallPanel>
<TextBlock Foreground="{TemplateBinding Foreground}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontSize="{TemplateBinding FontSize}"
Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls:StepItem}}, Converter={StaticResource IndexConverter}}"
Name="PART_Index"/>
<Path Data="{StaticResource PathComplete}"
Fill="{TemplateBinding Foreground}"
Stretch="Uniform"
Width="12"
Height="12"
Name="PART_PathComplete"
Visibility="Collapsed"/>
</controls:SmallPanel>
</Border>
</controls:SmallPanel>
<ContentPresenter HorizontalAlignment="Center"
TextElement.FontWeight="Black"
ContentTemplate="{Binding ItemTemplate,RelativeSource={RelativeSource AncestorType=controls:Step}}"
TextElement.Foreground="{DynamicResource RegularTextSolidColorBrush}"
Margin="0,6,0,0"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="Status" Value="Waiting">
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextSolidColorBrush}"/>
<Setter Property="Visibility" TargetName="PART_PathComplete" Value="Collapsed"/>
<Setter Property="Visibility" TargetName="PART_Index" Value="Visible"/>
<Setter Property="Background" Value="{DynamicResource BaseSolidColorBrush}"/>
</Trigger>
<Trigger Property="Status" Value="InProgress">
<Setter Property="Foreground" Value="{DynamicResource DefaultBackgroundSolidColorBrush}"/>
<Setter Property="Visibility" TargetName="PART_PathComplete" Value="Collapsed"/>
<Setter Property="Visibility" TargetName="PART_Index" Value="Visible"/>
<Setter Property="Background" Value="{DynamicResource PrimaryNormalSolidColorBrush}"/>
</Trigger>
<Trigger Property="Status" Value="Complete">
<Setter Property="BorderBrush" Value="{DynamicResource DefaultBackgroundSolidColorBrush}"/>
<Setter Property="Background" Value="{DynamicResource DefaultBackgroundSolidColorBrush}"/>
<Setter Property="Visibility" TargetName="PART_PathComplete" Value="Visible"/>
<Setter Property="Visibility" TargetName="PART_Index" Value="Collapsed"/>
<Setter Property="Foreground" Value="{DynamicResource PrimaryNormalSolidColorBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="DefaultStep" TargetType="{x:Type controls:Step}"
BasedOn="{StaticResource ControlBasicStyle}">
<Setter Property="ItemContainerStyle" Value="{StaticResource DefaultStepItem}"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:Step}">
<controls:SmallPanel>
<ProgressBar x:Name="PART_ProgressBar"
Margin="0,18"
Height="1"
Value="{Binding StepIndex,RelativeSource={RelativeSource AncestorType=controls:Step}}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
<ItemsPresenter/>
</controls:SmallPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:StepItem}" BasedOn="{StaticResource DefaultStepItem}" />
<Style TargetType="{x:Type controls:Step}" BasedOn="{StaticResource DefaultStep}" />
</ResourceDictionary>
2) Step.cs
代码如下:
using System;
using System.windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace WPFDevelopers.Controls
{
[TemplatePart(Name = ProgressBarTemplateName, Type = typeof(ProgressBar))]
public class Step : ItemsControl
{
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(Step), new PropertyMetadata(0, OnStepIndexChanged));
private static void OnStepIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var step = (Step)d;
var stepIndex = (int)e.NewValue;
step.UpdateStepItemState(stepIndex);
}
void UpdateStepItemState(int stepIndex)
{
var count = Items.Count;
if (count <= 0) return;
if (stepIndex >= count)
{
StepIndex--;
return;
}
if (stepIndex < 0)
{
StepIndex++;
return;
}
for (var i = 0; i < stepIndex; i++)
{
if (ItemContainerGenerator.ContainerFromIndex(i) is StepItem stepItem)
stepItem.Status = Status.Complete;
}
if (ItemContainerGenerator.ContainerFromIndex(stepIndex) is StepItem itemInProgress)
itemInProgress.Status = Status.InProgress;
for (var i = stepIndex + 1; i < Items.Count; i++)
{
if (ItemContainerGenerator.ContainerFromIndex(i) is StepItem stepItem)
stepItem.Status = Status.Waiting;
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_progressBar = GetTemplateChild(ProgressBarTemplateName) as ProgressBar;
}
protected override void OnRender(DrawinGContext drawingContext)
{
base.OnRender(drawingContext);
var 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 StepItem;
}
protected override DependencyObject GetContainerForItemOverride()
{
return new StepItem();
}
public Step()
{
ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
}
public void Next()
{
StepIndex++;
}
public void Previous()
{
StepIndex--;
}
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
var count = Items.Count;
if (count <= 0) return;
UpdateStepItemState(StepIndex);
}
}
}
}
3) StepItem.cs
代码如下:
using System.Windows;
using System.Windows.Controls;
namespace WPFDevelopers.Controls
{
public class StepItem : ContentControl
{
public static readonly DependencyProperty IndexProperty = DependencyProperty.Register(
"Index", typeof(int), typeof(StepItem), new PropertyMetadata(-1));
public int Index
{
get => (int)GetValue(IndexProperty);
internal set => SetValue(IndexProperty, value);
}
public static readonly DependencyProperty StatusProperty = DependencyProperty.Register(
"Status", typeof(Status), typeof(StepItem), new PropertyMetadata(Status.Waiting));
public Status Status
{
get => (Status)GetValue(StatusProperty);
internal set => SetValue(StatusProperty, value);
}
}
}
4) Status.cs
代码如下:
namespace WPFDevelopers.Controls
{
/// <summary>
///状态值
/// </summary>
public enum Status
{
/// <summary>
/// 等待中
/// </summary>
Waiting,
/// <summary>
/// 正在进行中
/// </summary>
InProgress,
/// <summary>
/// 完成
/// </summary>
Complete
}
}
5) StepExample.xaml
代码如下:
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.StepExample"
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"
xmlns:controls="clr-namespace:WPFDevelopers.Samples.Controls"
xmlns:wd="https://GitHub.com/WPFDevelopersOrg/WPFDevelopers"
xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<controls:CodeViewer>
<StackPanel VerticalAlignment="Center" >
<UniformGrid Columns="2" Name="PART_UniformGrid">
<wd:Step x:Name="PART_Step" StepIndex="{Binding Progress}">
<wd:StepItem Content="填写账号"/>
<wd:StepItem Content="身份验证"/>
<wd:StepItem Content="设置新密码"/>
<wd:StepItem Content="完成"/>
</wd:Step>
<wd:Step StepIndex="0" ItemsSource="{Binding Steps}">
</wd:Step>
</UniformGrid>
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="10">
<Button Content="上一步" Command="{Binding PreviousCommand}"
CommandParameter="{Binding ElementName=PART_UniformGrid}"
Style="{StaticResource PrimaryButton}"/>
<Button Content="下一步" Command="{Binding NextCommand}"
CommandParameter="{Binding ElementName=PART_UniformGrid}"
Style="{StaticResource PrimaryButton}"/>
</StackPanel>
</StackPanel>
<controls:CodeViewer.SourceCodes>
<controls:SourceCodeModel
CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/StepExample.xaml"
CodeType="Xaml"/>
<controls:SourceCodeModel
CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/StepExample.xaml.cs"
CodeType="CSharp"/>
</controls:CodeViewer.SourceCodes>
</controls:CodeViewer>
</UserControl>
6) StepExample.xaml.cs
代码如下:
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using WPFDevelopers.Controls;
using WPFDevelopers.Samples.Helpers;
namespace WPFDevelopers.Samples.ExampleViews
{
/// <summary>
/// StepExample.xaml 的交互逻辑
/// </summary>
public partial class StepExample : UserControl
{
public ObservableCollection<string> Steps
{
get;
set;
}
public StepExample()
{
InitializeComponent();
Steps = new ObservableCollection<string>();
Steps.Add("Step 1");
Steps.Add("Step 2");
Steps.Add("Step 3");
Steps.Add("Step 4");
this.DataContext = this;
}
public ICommand NextCommand => new RelayCommand(new Action<object>((sender) =>
{
var uniformGrid = sender as UniformGrid;
if (uniformGrid == null) return;
foreach (var step in uniformGrid.Children.OfType<Step>())
step.Next();
}));
public ICommand PreviousCommand => new RelayCommand(new Action<object>((sender) =>
{
var uniformGrid = sender as UniformGrid;
if (uniformGrid == null) return;
foreach (var step in uniformGrid.Children.OfType<Step>())
step.Previous();
}));
}
}
效果图
以上就是基于WPF实现步骤控件的示例代码的详细内容,更多关于WPF步骤控件的资料请关注编程网其它相关文章!
--结束END--
本文标题: 基于WPF实现步骤控件的示例代码
本文链接: https://lsjlt.com/news/177381.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0