在 WPF 中实现向导进度控制 [英] Implementing a wizard progress control in WPF

查看:19
本文介绍了在 WPF 中实现向导进度控制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 WPF 中是否有最好的方法来实现这样的控件?

我可以轻松复制文本标签和进度条(每个标签上方没有圆形凸起"),但我想知道是否已经有控件或最佳实践来创建此类WPF 中的控件.

解决方案

很难说在这种情况下最佳实践是什么,但我会这样做.

屏幕截图中的向导控件看起来像是 ProgressBarItemsControl 的组合,在这种情况下,从 ItemsControl<派生似乎更容易/code> 并实现进度功能而不是其他方式,但这也取决于您希望它如何工作(例如,如果您想要平稳的进度或只是一个一个地点亮点).

使用 UniformGrid 作为 ItemsPanel 和下面的 ItemTemplate,我们得到以下外观(Steps is a List 字符串)

<ItemsControl.ItemsPanel><ItemsPanelTemplate><UniformGrid Rows="1"/></ItemsPanelTemplate></ItemsControl.ItemsPanel><ItemsControl.ItemTemplate><数据模板><网格><Grid.RowDefinitions><RowDefinition Height="自动"/><RowDefinition Height="自动"/></Grid.RowDefinitions><Ellipse Horizo​​ntalAlignment="Center" Height="20" Width="20" Stroke="Transparent" Fill="Blue"/><TextBlock Grid.Row="1" Text="{Binding}" Horizo​​ntalAlignment="Center" Margin="0,5,0,0"/></网格></数据模板></ItemsControl.ItemTemplate></ItemsControl>

DropShadowEffect 添加到 ItemsPanel、两个 Path 元素到 ItemTemplate 和两个 DataTriggers 确定当前项目是显示/隐藏左/右 Path 的第一个还是最后一个项目,我们可以获得与您的屏幕截图非常相似的外观

ItemsPanel

<UniformGrid.Effect><DropShadowEffect 颜色="黑色"模糊半径=5"不透明度=0.6"ShadowDepth="0"/></UniformGrid.Effect></UniformGrid>

ItemTemplate

<DataTemplate.Resources><Style TargetType="路径"><Setter Property="Data" Value="M0.0,0.0 L0.0,0.33 L1.0,0.33 L1.0,0.66 L0.0,0.66 L0.0,1.0"/><Setter Property="StrokeThickness" Value="0"/><Setter Property="Height" Value="21"/><Setter Property="Stretch" Value="Fill"/><Setter Property="Fill" Value="{StaticResource WizardBarBrush}"/><Setter Property="StrokeEndLineCap" Value="Square"/><Setter Property="StrokeStartLineCap" Value="Square"/><Setter Property="Stroke" Value="透明"/></风格></DataTemplate.Resources><网格><Grid.RowDefinitions><RowDefinition Height="自动"/><RowDefinition Height="自动"/></Grid.RowDefinitions><Grid.ColumnDefinitions><列定义/><列定义/></Grid.ColumnDefinitions><路径名称="leftPath"/><Path Name="rightPath" Grid.Column="1"/><Ellipse Grid.ColumnSpan="2" Horizo​​ntalAlignment="Center" Height="20" Width="20" Stroke="Transparent" Fill="{StaticResource WizardBarBrush}"/><TextBlock Grid.ColumnSpan="2" Grid.Row="1" Text="{Binding}" Horizo​​ntalAlignment="Center" Margin="0,5,0,0"/></网格><DataTemplate.Triggers><DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}"值="{x:Null}"><Setter TargetName="leftPath" Property="Visibility" Value="Collapsed"/></数据触发器><DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={markup:IsLastItemConverter}}"值="真"><Setter TargetName="rightPath" Property="Visibility" Value="Collapsed"/></数据触发器></DataTemplate.Triggers></数据模板>

如果你决定使用这种方法,你可能会想出如何让剩下的事情继续下去,比如

  • 在可重用的自定义控件中实现这一点
  • 只在进度部分而不是在文本中获取笔画(DropShadowEffect)
  • 实现进度功能等

无论如何,我上传了一个带有名为 WizardProgressBar 的自定义控件的示例项目和一个使用它的演示项目:

更新结束

这是上面示例代码中缺失的部分

<GradientStop Color="#FFE4E4E4" Offset="0.25"/><GradientStop Color="#FFededed" Offset="0.50"/><GradientStop Color="#FFFCFCFC" Offset="0.75"/></LinearGradientBrush>

IsLastItemConverter

公共类 IsLastItemConverter : MarkupExtension, IValueConverter{公共对象转换(对象值,类型目标类型,对象参数,System.Globalization.CultureInfo 文化){ContentPresenter contentPresenter = 作为 ContentPresenter 的值;ItemsControl itemsControl = ItemsControl.ItemsControlFromItemContainer(contentPresenter);int index = itemsControl.ItemContainerGenerator.IndexFromContainer(contentPresenter);返回(索引==(itemsControl.Items.Count - 1));}公共对象 ConvertBack(对象值,类型目标类型,对象参数,System.Globalization.CultureInfo 文化){抛出新的 NotSupportedException();}公共 IsLastItemConverter() { }公共覆盖对象 ProvideValue(IServiceProvider serviceProvider){返回这个;}}

Is there a best way to implement a control like this in WPF?

I can easily replicate the text labels and the progress bar (without the circular "bumps" above each label) but I'd like to know if there's a control already out there, or a best practice, for creating this sort of control in WPF.

解决方案

It's hard to say what the best practice is in this case but here is how I would do it.

The wizard control in your screenshot looks like a combination of a ProgressBar and an ItemsControl and in this case it seems easier to me to derive from ItemsControl and implement the progress functionality than the other way around but it also depends on how you want it to work (if you want a smooth progress or just light up the dots one-by-one for example).

Using a UniformGrid as ItemsPanel and the ItemTemplate below, we get the following look (Steps is a List of strings)

<ItemsControl ItemsSource="{Binding Steps}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Rows="1"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Ellipse HorizontalAlignment="Center" Height="20" Width="20" Stroke="Transparent" Fill="Blue"/>
                <TextBlock Grid.Row="1" Text="{Binding}" HorizontalAlignment="Center" Margin="0,5,0,0"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Adding a DropShadowEffect to the ItemsPanel, two Path elements to the ItemTemplate and two DataTriggers to determine if the current item is the first or last item to show/hide the left/right Path and we can get a pretty similar look to your screenshot

ItemsPanel

<UniformGrid Rows="1" SnapsToDevicePixels="True">
    <UniformGrid.Effect>
        <DropShadowEffect Color="Black"
                          BlurRadius="5"
                          Opacity="0.6"
                          ShadowDepth="0"/>
    </UniformGrid.Effect>
</UniformGrid>

ItemTemplate

<DataTemplate>
    <DataTemplate.Resources>
        <Style TargetType="Path">
            <Setter Property="Data" Value="M0.0,0.0 L0.0,0.33 L1.0,0.33 L1.0,0.66 L0.0,0.66 L0.0,1.0"/>
            <Setter Property="StrokeThickness" Value="0"/>
            <Setter Property="Height" Value="21"/>
            <Setter Property="Stretch" Value="Fill"/>
            <Setter Property="Fill" Value="{StaticResource wizardBarBrush}"/>
            <Setter Property="StrokeEndLineCap" Value="Square"/>
            <Setter Property="StrokeStartLineCap" Value="Square"/>
            <Setter Property="Stroke" Value="Transparent"/>
        </Style>
    </DataTemplate.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Path Name="leftPath"/>
        <Path Name="rightPath" Grid.Column="1"/>
        <Ellipse Grid.ColumnSpan="2" HorizontalAlignment="Center" Height="20" Width="20" Stroke="Transparent" Fill="{StaticResource wizardBarBrush}"/>
        <TextBlock Grid.ColumnSpan="2" Grid.Row="1" Text="{Binding}" HorizontalAlignment="Center" Margin="0,5,0,0"/>
    </Grid>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}"
                     Value="{x:Null}">
            <Setter TargetName="leftPath" Property="Visibility" Value="Collapsed"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={markup:IsLastItemConverter}}"
                     Value="True">
            <Setter TargetName="rightPath" Property="Visibility" Value="Collapsed"/>
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

If you decide to use this approach you can probably work out how to get the rest of it going, like

  • Implement this in a reusable custom control
  • Only get the stroke (DropShadowEffect) on the progress-part and not in the text
  • Implement the progress functionality etc.

Anyway, I uploaded a sample project with a custom control called WizardProgressBar and a demo project using it here: https://www.dropbox.com/s/ng9vfi6uwn1peot/WizardProgressBarDemo2.zip?dl=0

It looks like this

Things to note about the sample

  • I ended up in a situation where I would get the DropShadowEffect on the progress-part and the headers or get a thin line between each item (as seen in the picture). I can't think of an easy way to get rid of it so maybe this isn't the best approach after all :)
  • The progress-part is simple. It just has a value between 0-100 and then a converter decides if the item should be lit or not
  • This control might have a small performance impact but I can't be sure since my computer seems to be running everything slow today...

Update

Made a few changes to the sample project where I split the presentation into two ItemsControls to get rid of the thin lines between each item. It now looks like this

Uploaded it here: https://www.dropbox.com/s/ng9vfi6uwn1peot/WizardProgressBarDemo2.zip?dl=0

End of Update

And here are the missing parts from the sample code above

<LinearGradientBrush x:Key="wizardBarBrush" StartPoint="0.5,0.0" EndPoint="0.5,1.0">
    <GradientStop Color="#FFE4E4E4" Offset="0.25"/>
    <GradientStop Color="#FFededed" Offset="0.50"/>
    <GradientStop Color="#FFFCFCFC" Offset="0.75"/>
</LinearGradientBrush>

IsLastItemConverter

public class IsLastItemConverter : MarkupExtension, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ContentPresenter contentPresenter = value as ContentPresenter;
        ItemsControl itemsControl = ItemsControl.ItemsControlFromItemContainer(contentPresenter);
        int index = itemsControl.ItemContainerGenerator.IndexFromContainer(contentPresenter);
        return (index == (itemsControl.Items.Count - 1));
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    public IsLastItemConverter() { }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}

这篇关于在 WPF 中实现向导进度控制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆