我想用ListView创建一个简单的痕迹导轨栏。按照简单的线框截图,我希望将来存档:
现在,我已经创建了一些代码,主要使用DataTemplates来实现,实际上效果很好,但是我有一些我无法解决的视觉问题:
这是实际的代码:
<ListView DockPanel.Dock="Left" ItemsSource="{Binding TagList}"
MinWidth="300" Background="Transparent" BorderThickness="0"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollBarVisibility="Hidden" Margin="8,0,0,0">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="-8,0,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="8"/>
</Grid.ColumnDefinitions>
<Path Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FFC64242" Data="F1 M 112,144L 104,144L 112,160L 104,176L 112,176" HorizontalAlignment="Stretch" Height="Auto" VerticalAlignment="Stretch" Width="Auto"/>
<Grid HorizontalAlignment="Stretch" Height="Auto" VerticalAlignment="Stretch" Width="Auto" Grid.Column="1">
<Rectangle Stretch="Fill" Fill="#FFC64242" HorizontalAlignment="Stretch" Height="Auto" Margin="0.5" VerticalAlignment="Stretch" Width="Auto"/>
<Path Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Data="F1 M 128,144L 160,144" HorizontalAlignment="Stretch" Height="1" Margin="0" VerticalAlignment="Top" Width="Auto"/>
<Path Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Data="F1 M 128,176L 160,176" HorizontalAlignment="Stretch" Height="1" Margin="0" VerticalAlignment="Bottom" Width="Auto"/>
</Grid>
<Path Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FFC64242" Data="F1 M 168,144L 176,160L 168,176" Height="Auto" VerticalAlignment="Center" Width="8" HorizontalAlignment="Right" Grid.Column="2" d:LayoutOverrides="GridBox"/>
<DockPanel LastChildFill="True" Grid.ColumnSpan="2" Grid.Column="1">
<Label DockPanel.Dock="Left" FontSize="12" Content="{Binding Content, FallbackValue=Tagname n/a}" HorizontalAlignment="Left" Grid.Column="0" VerticalAlignment="Center" d:LayoutOverrides="Height" Margin="8,0"/>
<Button DockPanel.Dock="Right" Content="X" Background="Transparent" FontSize="12" Command="{Binding RemoveTagBtn}" Grid.Column="0" Width="13.077" d:LayoutOverrides="Height" VerticalAlignment="Center" Margin="0,0,8,0"/>
<!--<Border Background="#FFf7f7f7" BorderBrush="#FFc9c9c9" BorderThickness="1" CornerRadius="4" HorizontalAlignment="Left" Margin="0,0,0,5.96" d:LayoutOverrides="Height"/> -->
</DockPanel>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
答案 0 :(得分:13)
现在我必须在短时间内找到答案,这是我目前的解决方案。此外,如果您不需要ListBox的“可选”功能,则可以使用ItemControl进行交换。
这是代码。请注意,我已经注释掉ItemStyleContainer的“IsSelected”触发器......
<ListBox Padding="0" DockPanel.Dock="Left" ItemsSource="{Binding TagList}"
MinWidth="300" Background="Transparent" BorderThickness="0"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Margin="8,0,0,0" Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="{DynamicResource LXBarButtonBackgroundNormal}"/>
<Setter Property="BorderBrush" Value="{DynamicResource LXBarButtonBorderNormal}"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<DockPanel LastChildFill="True" Margin="-8,0,0,0">
<Path DockPanel.Dock="Left" Stroke="{DynamicResource LXBarButtonBorderNormal}" Fill="{DynamicResource LXBarButtonBackgroundNormal}" Data="F1 M 112,144L 104,144L 112,160L 104,176L 112,176" Stretch="Fill" Height="32" Width="8" />
<Path DockPanel.Dock="Right" Stroke="{DynamicResource LXBarButtonBorderNormal}" Fill="{DynamicResource LXBarButtonBackgroundNormal}" Data="F1 M 168,144L 176,160L 168,176" Stretch="Fill" Height="32" Width="8" />
<Border Name="Border" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Padding="{TemplateBinding Padding}" BorderThickness="0,1" VerticalAlignment="Center">
<ContentPresenter />
<!--
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="Background"
Value="Blue"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground"
Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
-->
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel VerticalAlignment="Center" Height="30">
<local:LXImageButton BorderThickness="0" Style="{DynamicResource LXBarImageButton}" Padding="0" DockPanel.Dock="Right" Background="Transparent" Command="{Binding RemoveTagBtn}" Height="16" Width="16"
NormalImage="/com.example.Views;component/Resources/Icons/Buttons/btnCloseXS_normal.png"
ActiveImage="/com.example.Views;component/Resources/Icons/Buttons/btnCloseXS_active.png"
HoverImage="/com.example.Views;component/Resources/Icons/Buttons/btnCloseXS_hover.png"
PressedImage="/com.example.Views;component/Resources/Icons/Buttons/btnCloseXS_hover.png"
DisabledImage="/com.example.Views;component/Resources/Icons/Buttons/btnCloseXS_passive.png"
/>
<Label DockPanel.Dock="Left" FontSize="12" Content="{Binding Content, FallbackValue=Tagname n/a}" VerticalAlignment="Center"/>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
答案 1 :(得分:0)
我制作了一个自定义形状,可以渲染出你想要的箭头。
我使用了Rectangle
类中的一些代码。
至于造型的第一个和最后一个元素。您需要某种AttachedBehavior
根据项目索引调整某些属性。
using System;
using System.Windows.Shapes;
using System.Windows;
using System.Windows.Media;
namespace CustomShapes
{
public class SquaredArrow : Shape
{
protected Rect _rect = Rect.Empty;
#region TipOffset
/// <summary>
/// TipOffset Dependency Property
/// </summary>
public static readonly DependencyProperty TipOffsetProperty =
DependencyProperty.Register("TipOffset", typeof(double), typeof(SquaredArrow),
new FrameworkPropertyMetadata((double)10, FrameworkPropertyMetadataOptions.AffectsRender));
/// <summary>
/// Gets or sets the TipOffset property. This dependency property
/// indicates ....
/// </summary>
[System.ComponentModel.Category("SquaredArrow")]
public double TipOffset
{
get { return (double)GetValue(TipOffsetProperty); }
set { SetValue(TipOffsetProperty, value); }
}
#endregion
public SquaredArrow()
{
Rectangle r = new Rectangle();
r.Measure(new Size(100, 100));
r.Arrange(new Rect(0, 0, 100, 100));
}
static SquaredArrow()
{
StretchProperty.OverrideMetadata(typeof(SquaredArrow), new FrameworkPropertyMetadata(Stretch.Fill));
}
protected override Geometry DefiningGeometry
{
get { return CreateShape(); }
}
/// <summary>
/// Return the transformation applied to the geometry before rendering
/// </summary>
public override Transform GeometryTransform
{
get
{
return Transform.Identity;
}
}
/// <summary>
/// This is where the arrow shape is created.
/// </summary>
/// <returns></returns>
private Geometry CreateShape()
{
double width = _rect.Width;
double height = _rect.Height;
double borderOffset = GetStrokeThickness() / 2d;
PathGeometry g = new PathGeometry();
PathFigure figure = new PathFigure();
figure.IsClosed = true;
figure.StartPoint = new Point(borderOffset, borderOffset);
figure.Segments.Add(new LineSegment(new Point(width - TipOffset + borderOffset, borderOffset), true));
figure.Segments.Add(new LineSegment(new Point(width + borderOffset, height / 2d + borderOffset), true));
figure.Segments.Add(new LineSegment(new Point(width + borderOffset - TipOffset, height + borderOffset), true));
figure.Segments.Add(new LineSegment(new Point(borderOffset, height + borderOffset), true));
g.Figures.Add(figure);
return g;
}
/// <summary>
/// Updates DesiredSize of the Rectangle. Called by parent UIElement. This is the first pass of layout.
/// </summary>
/// <param name="constraint">Constraint size is an "upper limit" that Rectangle should not exceed.</param>
/// <returns>Rectangle's desired size.</returns>
protected override Size MeasureOverride(Size constraint)
{
if (Stretch == Stretch.UniformToFill)
{
double width = constraint.Width;
double height = constraint.Height;
if (Double.IsInfinity(width) && Double.IsInfinity(height))
{
return GetNaturalSize();
}
else if (Double.IsInfinity(width) || Double.IsInfinity(height))
{
width = Math.Min(width, height);
}
else
{
width = Math.Max(width, height);
}
return new Size(width, width);
}
return GetNaturalSize();
}
/// <summary>
/// Returns the final size of the shape and cachnes the bounds.
/// </summary>
protected override Size ArrangeOverride(Size finalSize)
{
// Since we do NOT want the RadiusX and RadiusY to change with the rendering transformation, we
// construct the rectangle to fit finalSize with the appropriate Stretch mode. The rendering
// transformation will thus be the identity.
double penThickness = GetStrokeThickness();
double margin = penThickness / 2;
_rect = new Rect(
margin, // X
margin, // Y
Math.Max(0, finalSize.Width - penThickness), // Width
Math.Max(0, finalSize.Height - penThickness)); // Height
switch (Stretch)
{
case Stretch.None:
// A 0 Rect.Width and Rect.Height rectangle
_rect.Width = _rect.Height = 0;
break;
case Stretch.Fill:
// The most common case: a rectangle that fills the box.
// _rect has already been initialized for that.
break;
case Stretch.Uniform:
// The maximal square that fits in the final box
if (_rect.Width > _rect.Height)
{
_rect.Width = _rect.Height;
}
else // _rect.Width <= _rect.Height
{
_rect.Height = _rect.Width;
}
break;
case Stretch.UniformToFill:
// The minimal square that fills the final box
if (_rect.Width < _rect.Height)
{
_rect.Width = _rect.Height;
}
else // _rect.Width >= _rect.Height
{
_rect.Height = _rect.Width;
}
break;
}
return finalSize;
}
/// <summary>
/// Get the natural size of the geometry that defines this shape
/// </summary>
protected Size GetNaturalSize()
{
double strokeThickness = GetStrokeThickness();
return new Size(strokeThickness, strokeThickness);
}
protected double GetStrokeThickness()
{
return this.StrokeThickness;
}
/// <summary>
/// Render callback.
/// </summary>
protected override void OnRender(DrawingContext drawingContext)
{
Pen pen = new Pen(Stroke, GetStrokeThickness());
drawingContext.DrawGeometry(Fill, pen, DefiningGeometry);
}
}
}