Breadcrumb style with WPF-ListView

前端 未结 2 603
小蘑菇
小蘑菇 2020-12-13 07:16

I want to create a simple breadcrumb bar with ListView. Following a simple wireframe screenshot what I would like to archive in the future:

2条回答
  •  萌比男神i
    2020-12-13 08:01

    I made a custom shape that renders the arrow that you want. I used some code from the Rectangle class.

    As for the part of styling the first and last elements. You will need some sort of AttachedBehavior that adjusts some property based on the item index.

    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
    
            /// 
            /// TipOffset Dependency Property
            /// 
            public static readonly DependencyProperty TipOffsetProperty =
                DependencyProperty.Register("TipOffset", typeof(double), typeof(SquaredArrow),
                    new FrameworkPropertyMetadata((double)10, FrameworkPropertyMetadataOptions.AffectsRender));
    
            /// 
            /// Gets or sets the TipOffset property.  This dependency property 
            /// indicates ....
            /// 
            [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(); }
            }
    
            /// 
            /// Return the transformation applied to the geometry before rendering
            ///  
            public override Transform GeometryTransform
            {
                get
                {
                    return Transform.Identity;
                }
            }
    
            /// 
            /// This is where the arrow shape is created.
            /// 
            /// 
            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;
            }
    
            /// 
            /// Updates DesiredSize of the Rectangle.  Called by parent UIElement.  This is the first pass of layout. 
            /// 
            /// Constraint size is an "upper limit" that Rectangle should not exceed.
            /// Rectangle's desired size.
            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();
            }
    
            /// 
            /// Returns the final size of the shape and cachnes the bounds. 
            /// 
            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;
            }
    
            ///  
            /// Get the natural size of the geometry that defines this shape
            ///  
            protected Size GetNaturalSize()
            {
                double strokeThickness = GetStrokeThickness();
                return new Size(strokeThickness, strokeThickness);
            }
    
            protected double GetStrokeThickness()
            {
                return this.StrokeThickness;
            }
    
            ///  
            /// Render callback.
            ///  
            protected override void OnRender(DrawingContext drawingContext)
            {
                Pen pen = new Pen(Stroke, GetStrokeThickness());
    
                drawingContext.DrawGeometry(Fill, pen, DefiningGeometry);
            }
        }
    }
    

提交回复
热议问题