使用WPF-ListView的面包屑样式

时间:2011-04-20 08:14:00

标签: wpf xaml listview styles

我想用ListView创建一个简单的痕迹导轨栏。按照简单的线框截图,我希望将来存档:

This is what I am looking for

现在,我已经创建了一些代码,主要使用DataTemplates来实现,实际上效果很好,但是我有一些我无法解决的视觉问题:

This is what I currently achieved

  • 主要问题涉及物品的不同宽度。箭头"的中心应拉伸,尾部和头部应固定宽度......
  • 另一个问题是第一个和最后一个项目的视觉风格

这是实际的代码:

<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>

2 个答案:

答案 0 :(得分:13)

现在我必须在短时间内找到答案,这是我目前的解决方案。此外,如果您不需要ListBox的“可选”功能,则可以使用ItemControl进行交换。

Current solution for the problem

这是代码。请注意,我已经注释掉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);
        }
    }
}