Ответ 1
Трудно сказать, что лучше всего в этом случае, но вот как я это сделаю.
Элемент управления на вашем скриншоте выглядит как комбинация ProgressBar
и ItemsControl
, и в этом случае мне кажется, что мне легче получить от ItemsControl
и реализовать функциональность прогресса, а затем наоборот, но это также зависит от того, как вы хотите, чтобы он работал (если вы хотите добиться плавного хода или просто подсвечиваете точки один за другим, например).
Используя UniformGrid
как ItemsPanel
и ItemTemplate
ниже, мы получим следующий вид (Шаги - List
строк)
<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>
Добавление DropShadowEffect
в ItemsPanel
, два элемента Path
в ItemTemplate
и два DataTriggers
, чтобы определить, является ли текущий элемент первым или последним элементом, отображающим/скрывающим левый/правый Path
, и мы можем получить похожий вид на ваш скриншот
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>
Если вы решите использовать этот подход, вы, вероятно, сможете тренироваться, как сделать все остальное, например
- Реализовать это в настраиваемом настраиваемом элементе управления
- Только получить ход (
DropShadowEffect
) в части прогресса, а не в тексте - Внедрить функциональные возможности выполнения и т.д.
В любом случае, я загрузил образец проекта с помощью специального элемента управления WizardProgressBar
и демонстрационного проекта, использующего его здесь: https://www.dropbox.com/s/ng9vfi6uwn1peot/WizardProgressBarDemo2.zip?dl=0
Похоже, что это
Замечания о образце
- Я попал в ситуацию, когда я получил
DropShadowEffect
в части прогресса и заголовках или получал тонкую линию между каждым элементом (как видно на рисунке). Я не могу придумать простой способ избавиться от него, поэтому, возможно, это не лучший подход:) - Прогресс-часть проста. Он просто имеет значение от 0 до 100, а затем преобразователь решает, должен ли элемент гореть или нет.
- Этот элемент управления может иметь небольшое влияние на производительность, но я не могу быть уверен, поскольку на моем компьютере сегодня все работает медленнее.
Обновление
Сделал несколько изменений в примерном проекте, где я разделил презентацию на два ItemsControls
, чтобы избавиться от тонких линий между каждым элементом. Теперь это выглядит так:
Загрузите его здесь: https://www.dropbox.com/s/ng9vfi6uwn1peot/WizardProgressBarDemo2.zip?dl=0
Конец обновления
И вот недостающие части из примера кода выше
<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;
}
}