Основная проблема заключается в том, что первый элемент в вашей настройке должен иметь ширину, отличную от других элементов.Это невозможно с UniformGrid
.
. Я могу предложить вам следующее решение.
Целевая конфигурация будет выглядеть следующим образом:
|··O––|––O––|––O––|––O··|
У вас будетШирокий край полуэлемента слева и справа (представлен точками выше).При желании вы можете использовать их, указав поля своего элемента управления.
Кроме того, мы можем упростить ваши шаблоны данных.На самом деле, нам не нужны отдельные шаблоны для первого и других элементов.См. Ниже.
Настройка
Здесь мы будем использовать три уловки:
- свойство
ItemsControl.AlternationIndex
для получения первого элемента в ItemsControl
- a
Canvas
, позволяющий рисовать соединительные линии вне соответствующих UniforGrid
ячеек - специального
IValueConverter
, который поможет нам рассчитать необходимое положение линии
Теперь, это стиль для вашего ItemsControl
:
<Style x:Key="WizardProgressBar" TargetType="{x:Type ItemsControl}">
<Style.Resources>
<local:LinearConverter x:Key="Multiplier" Scale="-0.5" Offset="16"/>
<DataTemplate DataType="{x:Type local:YourItemType}">
<Grid>
<Canvas>
<Rectangle x:Name="leftPath" Height="2" Stroke="Blue" Canvas.Top="16"
Canvas.Left="{Binding Width, RelativeSource={RelativeSource Self}, Converter={StaticResource Multiplier}}"
Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}}"/>
</Canvas>
<Ellipse Name="ellipse" HorizontalAlignment="Center" Height="32" Width="32" Stroke="Blue"/>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter TargetName="leftPath" Property="Visibility" Value="Collapsed"/>
</Trigger>
<DataTrigger Binding="{Binding Completed}" Value="False">
<Setter TargetName="ellipse" Property="Stroke" Value="{DynamicResource DisabledBrush}" />
<Setter TargetName="leftPath" Property="Stroke" Value="{DynamicResource DisabledBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding InProgress}" Value="True">
<Setter TargetName="ellipse" Property="Stroke" Value="{DynamicResource PrimaryTextBrush}"/>
<Setter TargetName="leftPath" Property="Stroke" Value="{DynamicResource PrimaryTextBrush}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Style.Resources>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="AlternationCount" Value="100"/>
</Style>
Обратите внимание на следующие изменения:
- есть только один
DataTemplate
нет необходимости в двух разных - больше не нужен селектор шаблонов
- нам нужен специальный конвертер в нашем стиле (код ниже)
Ellipse
илиния (как Rectangle
) помещается в 1x1 Grid
в ту же ячейку - сама линия находится в
Canvas
- *
Ellipse
центрирована горизонтально - есть дополнительный
Trigger
, который ловит значение AlternationIndex
0 и скрывает строку - это для первого элемента - стиль устанавливает
AlternationCount
до 100, если у вас будет максимум 100 страниц мастера
Вот конвертер:
class LinearConverter : IValueConverter
{
public double Scale { get; set; }
public double Offset { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// TODO: exception handling
return System.Convert.ToDouble(value) * Scale + Offset;
}
// ConvertBack just throws a NotImplementedException
}
Пояснение
Каждый Ellipse
представляетСтраница мастера и находится в центре соответствующей ячейки UniformGrid
.Линии расположены слева от эллипсов.Ширина линий устанавливается равной ширине отдельной ячейки UnifiormGrid
, а их горизонтальное положение в Canvas
устанавливается по формуле: WidthOfEllipse / 2 - WidthOfCell / 2
.Это обеспечивает правильное размещение.
Для первой страницы мастера линия будет скрыта.
Обратите внимание, что вы можете использовать Fill
для эллипсов, чтобы скрыть нижележащие линии.