You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让自定义UserControl支持在XAML中直接添加Step实例?

实现XAML直接向自定义UserControl添加Step实例的方案

需求背景

我有一个自定义UserControl(StepProgressBar),内部是包含横向进度条和ItemsControl的Grid,ItemsControl的ItemTemplate由两个Ellipse和一个TextBlock组成。数据项是Step类,希望无需编写C#代码,直接在XAML中给StepProgressBar添加Step实例,达到如下效果:

<Grid>
    <local:StepProgressBar x:Name="FirmwareBar" Margin="0,0,0,0">
        <local:Step Name="Test" InnerColor="Yellow" IsCompleted="false" />
        <local:Step Name="Test1" InnerColor="Green" IsCompleted="true" CompletedColor="#FF7DEEAF" />
    </local:StepProgressBar>
</Grid>

实现步骤

1. 完善Step类(实现属性变更通知)

为了让Step的属性变化能自动同步到UI,需要实现INotifyPropertyChanged接口:

using System.ComponentModel;
using System.Windows.Media;

public class Step : INotifyPropertyChanged
{
    public Step() { Name = string.Empty; }
    public Step(string name, Brush color) { Name = name; InnerColor = color; }

    private string _name;
    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged(nameof(Name));
        }
    }

    private Brush _innerColor;
    public Brush InnerColor
    {
        get => _innerColor;
        set
        {
            _innerColor = value;
            OnPropertyChanged(nameof(InnerColor));
        }
    }

    private Brush _outerColor;
    public Brush OuterColor
    {
        get => _outerColor;
        set
        {
            _outerColor = value;
            OnPropertyChanged(nameof(OuterColor));
        }
    }

    private Brush _completedColor;
    public Brush CompletedColor
    {
        get => _completedColor;
        set
        {
            _completedColor = value;
            OnPropertyChanged(nameof(CompletedColor));
        }
    }

    private bool _isCompleted;
    public bool IsCompleted
    {
        get => _isCompleted;
        set
        {
            _isCompleted = value;
            OnPropertyChanged(nameof(IsCompleted));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 给StepProgressBar添加可绑定的集合依赖属性

在StepProgressBar的后台代码中,定义一个ObservableCollection<Step>类型的依赖属性,并通过ContentPropertyAttribute指定该属性为控件的内容属性,这样XAML中直接编写的子元素会自动添加到这个集合中:

using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;

[ContentProperty(nameof(StepsCollection))]
public partial class StepProgressBar : UserControl
{
    public static readonly DependencyProperty StepsCollectionProperty =
        DependencyProperty.Register(nameof(StepsCollection), typeof(ObservableCollection<Step>), typeof(StepProgressBar), new PropertyMetadata(new ObservableCollection<Step>()));

    public ObservableCollection<Step> StepsCollection
    {
        get => (ObservableCollection<Step>)GetValue(StepsCollectionProperty);
        set => SetValue(StepsCollectionProperty, value);
    }

    public StepProgressBar()
    {
        InitializeComponent();
        // 将ItemsControl的数据源绑定到StepsCollection
        ItemsControlSteps.ItemsSource = StepsCollection;
    }
}

3. 修改StepProgressBar的XAML布局

调整横向进度条的自适应布局,同时给ItemsControl指定名称以便后台绑定:

<UserControl x:Class="YourNamespace.StepProgressBar"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <!-- 自适应宽度的横向进度条 -->
        <Rectangle Height="7" Fill="#FF00A8FF" Margin="10,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
        <!-- 步骤项容器 -->
        <ItemsControl x:Name="ItemsControlSteps">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" VerticalAlignment="Center"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <DataTemplate.Resources>
                        <Style TargetType="{x:Type Ellipse}">
                            <Setter Property="Margin" Value="10,15,0,0"/>
                            <Setter Property="HorizontalAlignment" Value="Center"/>
                        </Style>
                        <Style TargetType="{x:Type TextBlock}">
                            <Setter Property="Margin" Value="10,0,0,0"/>
                            <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
                            <Setter Property="HorizontalAlignment" Value="Center"/>
                        </Style>
                    </DataTemplate.Resources>
                    <StackPanel MaxWidth="75">
                        <Grid>
                            <Ellipse x:Name="EllipseOuter" Width="20" Height="20" Fill="#FF00A8FF"/>
                            <Ellipse x:Name="EllipseInner" Width="10" Height="10" Fill="{Binding InnerColor}"/>
                        </Grid>
                        <TextBlock Text="{Binding Name}"/>
                    </StackPanel>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsCompleted}" Value="true">
                            <Setter TargetName="EllipseInner" Property="Fill" Value="{Binding CompletedColor}"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</UserControl>

4. 在MainWindow中使用

现在可以直接在XAML中给StepProgressBar添加Step实例,无需额外C#代码:

<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:YourNamespace"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:StepProgressBar x:Name="FirmwareBar" Margin="20">
            <local:Step Name="Test" InnerColor="Yellow" IsCompleted="false"/>
            <local:Step Name="Test1" InnerColor="Green" IsCompleted="true" CompletedColor="#FF7DEEAF"/>
            <local:Step Name="Test2" InnerColor="Orange" IsCompleted="false"/>
        </local:StepProgressBar>
    </Grid>
</Window>

关键说明

  • [ContentProperty(nameof(StepsCollection))]:告诉WPF将控件的子元素自动填充到StepsCollection集合中,无需手动绑定。
  • ObservableCollection<Step>:保证集合的增删操作能自动通知UI更新,结合INotifyPropertyChanged实现单个Step属性变化的实时同步。
  • 移除了原DataTemplate中不必要的IsCompleted=false触发器,因为默认已绑定InnerColor,仅在IsCompleted=true时替换填充色即可。

内容的提问来源于stack exchange,提问作者Zero _000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 23:42:33