Es difícil decir que mejor práctica es en este caso, pero aquí es cómo lo haría.
El control asistente en la pantalla se ve como una combinación de un ProgressBar
y un ItemsControl
y en este caso parece más fácil para mí para derivar de ItemsControl
e implementar la funcionalidad progreso luego al revés, pero también depende de cómo se quiero que funcione (si quieres un progreso sin problemas o simplemente iluminas los puntos uno a uno, por ejemplo).
utilizando un UniformGrid
como ItemsPanel
y la ItemTemplate
continuación, obtenemos el siguiente aspecto (Steps es un List
de cadenas)
<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>
Adición de un DropShadowEffect
a los ItemsPanel
, dos Path
elementos a ItemTemplate
y dos DataTriggers
para determinar si el artículo actual es el primero o el último elemento para mostrar/ocultar la izquierda/derecha Path
y podemos conseguir un aspecto bastante similar a la captura de pantalla
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>
Si decide utilizar este enfoque probablemente pueda entrenamiento cómo hacer funcionar el resto, como
- implementar esto en un control personalizado resuable
- Sólo conseguir el accidente cerebrovascular (
DropShadowEffect
) en la parte progreso y no en el texto
- implementar la funcionalidad progreso etc.
De todos modos, subido un proyecto de ejemplo con un control personalizado llamado WizardProgressBar
y un proyecto de demostración de usarlo aquí: https://www.dropbox.com/s/ng9vfi6uwn1peot/WizardProgressBarDemo2.zip?dl=0
parece que este
cosas a tener en cuenta sobre la muestra
- terminé en una situación en la que tendría la
DropShadowEffect
en la parte progreso y los encabezados o de obtener una línea delgada entre cada elemento (como se ve en la imagen). No puedo pensar en una manera fácil de deshacerse de él, así que tal vez este no sea el mejor enfoque después de todo :)
- La parte de progreso es simple. Simplemente tiene un valor entre 0-100 y luego un convertidor decide si el elemento debe estar encendido o no
- Este control puede tener un pequeño impacto en el rendimiento pero no puedo estar seguro ya que mi computadora parece estar funcionando todo lento hoy ..
actualización
hizo algunos cambios en el proyecto de ejemplo en el que todo dividido la presentación en dos ItemsControls
para deshacerse de las líneas finas entre cada elemento.Ahora parece que esta
subido aquí: https://www.dropbox.com/s/ng9vfi6uwn1peot/WizardProgressBarDemo2.zip?dl=0
Fin de actualización
Y aquí son las partes que faltan en el código de ejemplo anterior
<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;
}
}
No creo que haya nada exactamente así ahora. Supongo que quieres que las etiquetas y los porcentajes sean dinámicos, ¿verdad? – Stimul8d
Preferiblemente. Me gustaría poder agregar un 'ItemsControl' (u otra lista) de etiquetas y seleccionar un paso o índice actual, pero estoy abierto a otras opciones. –