WPF 自定义实现步骤条控件

163 阅读3分钟

WPF实现描点导航步骤条控件

前言

在现代WPF应用程序中,用户界面的交互体验越来越受到重视。描点导航是一种常见的视觉反馈方式,常用于引导用户完成多步骤操作或展示流程进度。本文将详细介绍如何基于 ListBox 控件 实现一个可复用的描点导航步骤条控件,并通过样式、模板和转换器来增强其功能与表现力。

该控件具有良好的扩展性和灵活性,适用于注册向导、安装流程、任务引导等场景。


正文

一、实现原理

本步骤条控件是基于 WPF ListBox 控件实现的,通过对 ControlTemplateStyle 的自定义,结合数据绑定和值转换器(IValueConverter),实现了动态布局和选中状态高亮效果。

整体结构如下:

  • StepListBoxStyle:控制整个步骤条的外观,包括底部进度线;
  • NormalItemTemplate:未被选中时的单项模板;
  • SelectedTemplate:被选中时的单项模板;
  • ListBoxItemStyle:为每个列表项设置样式,并通过触发器切换模板;
  • StepListBarWidthConverter:动态计算每个步骤项的宽度,确保总长度固定。

二、XAML代码实现

以下是完整的 XAML 资源定义和控件使用示例:

<Window.Resources>
    <convert1:StepListBarWidthConverter x:Key="StepListStepWidthConverter" />

    <!-- 默认项模板 -->
    <ControlTemplate x:Key="NormalItemTemplate" TargetType="ListBoxItem">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition Height="20" />
            </Grid.RowDefinitions>
            <ContentPresenter HorizontalAlignment="Center" Content="{TemplateBinding Content}" />
            <Grid Grid.Row="1" Margin="2">
                <Ellipse
                    Width="10"
                    Height="10"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Fill="#55DCF5" />
            </Grid>
        </Grid>
    </ControlTemplate>

    <!-- 整体步骤条样式 -->
    <Style x:Key="StepListBoxStyle" TargetType="ListBox">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBox">
                    <Grid>
                        <Rectangle
                            Width="510"
                            Height="4"
                            Margin="0,0,0,8"
                            HorizontalAlignment="Center"
                            VerticalAlignment="Bottom"
                            Fill="#55DCF5" />
                        <ItemsPresenter />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- 选中项模板 -->
    <ControlTemplate x:Key="SelectedTemplate" TargetType="ListBoxItem">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition Height="20" />
            </Grid.RowDefinitions>
            <ContentPresenter HorizontalAlignment="Center" Content="{TemplateBinding Content}" />
            <Grid Grid.Row="1" Margin="2">
                <Ellipse
                    Width="8"
                    Height="8"
                    VerticalAlignment="Center"
                    Panel.ZIndex="3">
                    <Ellipse.Fill>
                        <SolidColorBrush Color="#FFFFFF" />
                    </Ellipse.Fill>
                </Ellipse>
                <Ellipse
                    Width="12"
                    Height="12"
                    VerticalAlignment="Center"
                    Panel.ZIndex="2">
                    <Ellipse.Fill>
                        <SolidColorBrush Color="#225BA7" />
                    </Ellipse.Fill>
                </Ellipse>
                <Ellipse
                    Width="16"
                    Height="16"
                    VerticalAlignment="Center"
                    Panel.ZIndex="1">
                    <Ellipse.Fill>
                        <SolidColorBrush Color="#FFFFFF" />
                    </Ellipse.Fill>
                </Ellipse>
            </Grid>
        </Grid>
    </ControlTemplate>

    <!-- 列表项样式及触发器 -->
    <Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
        <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Converter={StaticResource StepListStepWidthConverter}}" />
        <Setter Property="FontSize" Value="16" />
        <Setter Property="FontFamily" Value="SimHei" />
        <Setter Property="Foreground" Value="#ACF1FE" />
        <Setter Property="Template" Value="{StaticResource NormalItemTemplate}" />
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
                <Trigger.Setters>
                    <Setter Property="Template" Value="{StaticResource SelectedTemplate}" />
                    <Setter Property="FontSize" Value="20" />
                    <Setter Property="Foreground" Value="White" />
                    <Setter Property="FontFamily" Value="SimHei" />
                </Trigger.Setters>
            </Trigger>
        </Style.Triggers>
    </Style>

</Window.Resources>

<!-- 页面内容 -->
<StackPanel Background="SteelBlue">
    <ListBox
        Margin="0 200 0 0"
        x:Name="NavList"
        HorizontalAlignment="Center"
        BorderThickness="0"
        Foreground="#225BA7"
        IsEnabled="False"
        ItemContainerStyle="{StaticResource ListBoxItemStyle}"
        SelectedIndex="4"
        Style="{StaticResource StepListBoxStyle}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel IsItemsHost="False" Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBoxItem>1</ListBoxItem>
        <ListBoxItem>2</ListBoxItem>
        <ListBoxItem>3</ListBoxItem>
        <ListBoxItem>4</ListBoxItem>
        <ListBoxItem>5</ListBoxItem>
        <ListBoxItem>6</ListBoxItem>
    </ListBox>
    <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
        <Button Click="Button_Click">下一步</Button>
        <Button Margin="100,0,0,0" Click="Button_Click_1">首页</Button>
    </StackPanel>
</StackPanel>

三、转换器实现

为了实现步骤条总长度固定并根据项数自动调整每项宽度,我们编写了一个简单的值转换器:

class StepListBarWidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        ListBox listBox = value as ListBox;
        if (listBox == null || listBox.Items.Count == 0)
        {
            return Binding.DoNothing;
        }
        return 510.0 / (listBox.Items.Count - 1);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

该转换器通过绑定到 ListBox.Width 属性,动态计算出每个步骤项应占宽度,从而保证整体控件宽度为 510px。


总结

本文详细介绍了如何使用 WPF 中的 ListBox 控件,结合样式、模板和值转换器,实现一个美观且实用的描点导航步骤条控件。该控件具备以下特点:

  • 支持动态项数与自动宽度分配;
  • 提供默认项与选中项的不同样式;
  • 易于集成到 MVVM 架构中;
  • 可通过绑定 SelectedItemSelectedIndex 实现程序化控制。

通过本文的学习,开发者可以快速构建属于自己的导航控件,并应用在实际项目中提升用户体验。


关键词

WPF、描点导航、步骤条控件、ListBox、ControlTemplate、样式模板、IValueConverter、数据绑定、MVVM、UI设计

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:MrKing

出处:cnblogs.com/king10086/p/11883304.html

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!