WPF---ListView添加窗格线

来源:互联网 发布:怎样成为淘宝卖家 编辑:程序博客网 时间:2024/05/16 18:51

要想直接在WPF中给ListView加上横竖线条,是一件很费劲的事情,不过我们可以通过其他的办法,来绕过去,具体是什么办法呢,就看下面的步骤吧!

1. 建立一个WPF程序

2. 添加一个类文件,命名为GridLineDecorator.cs,写入如下内容

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Markup;using System.Windows.Media;using System.Windows.Threading;namespace ListViewWithLines{    [ContentProperty("Target")]    public class GridLineDecorator : FrameworkElement    {        private ListView _target;        private DrawingVisual _gridLinesVisual = new DrawingVisual();        private GridViewHeaderRowPresenter _headerRowPresenter = null;        public GridLineDecorator()        {            this.AddVisualChild(_gridLinesVisual);            this.AddHandler(ScrollViewer.ScrollChangedEvent, new RoutedEventHandler(OnScrollChanged));        }        #region GridLineBrush        /// <summary>        /// GridLineBrush Dependency Property        /// </summary>        public static readonly DependencyProperty GridLineBrushProperty =            DependencyProperty.Register("GridLineBrush", typeof(Brush), typeof(GridLineDecorator),                new FrameworkPropertyMetadata(Brushes.LightGray,                    new PropertyChangedCallback(OnGridLineBrushChanged)));        /// <summary>        /// Gets or sets the GridLineBrush property.  This dependency property         /// indicates ....        /// </summary>        public Brush GridLineBrush        {            get { return (Brush)GetValue(GridLineBrushProperty); }            set { SetValue(GridLineBrushProperty, value); }        }        /// <summary>        /// Handles changes to the GridLineBrush property.        /// </summary>        private static void OnGridLineBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)        {            ((GridLineDecorator)d).OnGridLineBrushChanged(e);        }        /// <summary>        /// Provides derived classes an opportunity to handle changes to the GridLineBrush property.        /// </summary>        protected virtual void OnGridLineBrushChanged(DependencyPropertyChangedEventArgs e)        {            DrawGridLines();        }        #endregion        #region Target        public ListView Target        {            get { return _target; }            set            {                if (_target != value)                {                    if (_target != null) Detach();                    RemoveVisualChild(_target);                    RemoveLogicalChild(_target);                    _target = value;                    AddVisualChild(_target);                    AddLogicalChild(_target);                    if (_target != null) Attach();                    InvalidateMeasure();                }            }        }        private void GetGridViewHeaderPresenter()        {            if (Target == null)            {                _headerRowPresenter = null;                return;            }            _headerRowPresenter = Target.GetDesendentChild<GridViewHeaderRowPresenter>();        }        #endregion        #region DrawGridLines        private void DrawGridLines()        {            if (Target == null) return;            if (_headerRowPresenter == null) return;            var itemCount = Target.Items.Count;            if (itemCount == 0) return;            var gridView = Target.View as GridView;            if (gridView == null) return;            // 获取drawingContext            var drawingContext = _gridLinesVisual.RenderOpen();            var startPoint = new Point(0, 0);            // 为了对齐到像素的计算参数,否则就会看到有些线是模糊的            var dpiFactor = this.GetDpiFactor();            var pen = new Pen(this.GridLineBrush, 1 * dpiFactor);            var halfPenWidth = pen.Thickness / 2;            var guidelines = new GuidelineSet();            // 计算表头的偏移量和大小            var headerOffset = _headerRowPresenter.TranslatePoint(startPoint, this);            var headerSize = _headerRowPresenter.RenderSize;            var headerBottomY = headerOffset.Y + headerSize.Height;            // 计算ScrollViewer的可视区域大小            var item0 = _target.ItemContainerGenerator.ContainerFromIndex(0);            if (item0 == null) return;            var scrollViewer = item0.GetAncestor<ScrollViewer>();            if (scrollViewer == null) return;            var contentElement = scrollViewer.Content as UIElement;            var maxLineX = scrollViewer.ViewportWidth;            var maxLineY = headerBottomY + contentElement.RenderSize.Height;            var vLineY = 0.0;            // 画横线            for (int i = 0; i < itemCount; i++)            {                var item = Target.ItemContainerGenerator.ContainerFromIndex(i) as ListViewItem;                if (item != null)                {                    var renderSize = item.RenderSize;                    var offset = item.TranslatePoint(startPoint, this);                    var hLineX1 = offset.X;                    var hLineX2 = offset.X + renderSize.Width;                    var hLineY = offset.Y + renderSize.Height;                    vLineY = hLineY;                    // 小于视图起始位置的不绘制                    if (hLineY <= headerBottomY) continue;                    // 大于视图结束位置之后的不绘制                    if (hLineY > maxLineY) break;                    // 如果大于横向宽度,取横向宽度                    if (hLineX2 > maxLineX) hLineX2 = maxLineX;                    // 加入参考线,对齐到像素                    guidelines.GuidelinesY.Add(hLineY + halfPenWidth);                    drawingContext.PushGuidelineSet(guidelines);                    drawingContext.DrawLine(pen, new Point(hLineX1, hLineY), new Point(hLineX2, hLineY));                    drawingContext.Pop();                }            }            // 画竖线            var columns = gridView.Columns;            var vLineX = headerOffset.X;            if (vLineY > maxLineY) vLineY = maxLineY;            foreach (var column in columns)            {                var columnWidth = column.GetColumnWidth();                vLineX += columnWidth;                if (vLineX > maxLineX) break;                // 加入参考线,对齐到像素                guidelines.GuidelinesX.Add(vLineX + halfPenWidth);                drawingContext.PushGuidelineSet(guidelines);                drawingContext.DrawLine(pen, new Point(vLineX, headerBottomY), new Point(vLineX, vLineY));                drawingContext.Pop();            }            drawingContext.Close();        }        #endregion        #region Overrides to show Target and grid lines        protected override int VisualChildrenCount        {            get { return Target == null ? 1 : 2; }        }        protected override System.Collections.IEnumerator LogicalChildren        {            get { yield return Target; }        }        protected override Visual GetVisualChild(int index)        {            if (index == 0) return _target;            if (index == 1) return _gridLinesVisual;            throw new IndexOutOfRangeException(string.Format("Index of visual child '{0}' is out of range", index));        }        protected override Size MeasureOverride(Size availableSize)        {            if (Target != null)            {                Target.Measure(availableSize);                return Target.DesiredSize;            }            return base.MeasureOverride(availableSize);        }        protected override Size ArrangeOverride(Size finalSize)        {            if (Target != null)                Target.Arrange(new Rect(new Point(0, 0), finalSize));            return base.ArrangeOverride(finalSize);        }        #endregion        #region Handle Events        private void Attach()        {            _target.Loaded += OnTargetLoaded;            _target.Unloaded += OnTargetUnloaded;            _target.SizeChanged += OnTargetSizeChanged;        }        private void Detach()        {            _target.Loaded -= OnTargetLoaded;            _target.Unloaded -= OnTargetUnloaded;            _target.SizeChanged -= OnTargetSizeChanged;        }        private void OnTargetLoaded(object sender, RoutedEventArgs e)        {            if (_headerRowPresenter == null)                GetGridViewHeaderPresenter();            DrawGridLines();        }        private void OnTargetUnloaded(object sender, RoutedEventArgs e)        {            DrawGridLines();        }        private void OnTargetSizeChanged(object sender, SizeChangedEventArgs e)        {            DrawGridLines();        }        private void OnScrollChanged(object sender, RoutedEventArgs e)        {            DrawGridLines();        }        #endregion    }}

3.     添加一个类文件,命名为GridViewColumnHelper.cs,写入如下内容
using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Text;using System.Windows.Controls;namespace ListViewWithLines{    internal static class GridViewColumnHelper    {        private static PropertyInfo DesiredWidthProperty =            typeof(GridViewColumn).GetProperty("DesiredWidth", BindingFlags.NonPublic | BindingFlags.Instance);        public static double GetColumnWidth(this GridViewColumn column)        {            return (double.IsNaN(column.Width)) ? (double)DesiredWidthProperty.GetValue(column, null) : column.Width;        }    }}

4.     添加一个类文件,命名为VisualService.cs,写入如下内容
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows.Media;using System.Windows;namespace ListViewWithLines{    public static class VisualService    {        public static double GetDpiFactor(this Visual target)        {            var source = PresentationSource.FromVisual(target);            return source == null ? 1.0 : 1 / source.CompositionTarget.TransformToDevice.M11;        }        public static T GetAncestor<T>(this DependencyObject target)            where T : DependencyObject        {                        var parent = VisualTreeHelper.GetParent(target);            if (parent is T)                return (T)parent;            if (parent != null)                return parent.GetAncestor<T>();            return null;        }        public static T GetDesendentChild<T>(this DependencyObject target)            where T : DependencyObject        {            var childCount = VisualTreeHelper.GetChildrenCount(target);            if (childCount == 0) return null;            for (int i = 0; i < childCount; i++)            {                var current = VisualTreeHelper.GetChild(target, i);                if (current is T)                    return (T)current;                var desendent = current.GetDesendentChild<T>();                if (desendent != null)                    return desendent;            }            return null;        }    }}

5.    在界面主XAML文件中,加入以下内容
<Windowxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Class="TreeViewDesign.MainWindow"xmlns:l="clr-namespace:ListViewWithLines"x:Name="Window"Title="开发测试工具"Width="900" Height="600" Background="White" WindowState="Maximized">              <Grid>                 <l:GridLineDecorator GridLineBrush="{Binding ElementName=cb_GridLineBrush, Path=SelectedItem.Content}">                        <ListView Background="White" FocusVisualStyle="{x:Null}" Name="FileInfo">                                                        <ListView.View>                                <GridView>                                    <GridViewColumn Header="工程路径" Width="600" DisplayMemberBinding="{Binding XPath=@PATH}"/>                                    <GridViewColumn Header="修改日期" Width="200" DisplayMemberBinding="{Binding XPath=@MODIFY}"/>                                                                </GridView>                            </ListView.View>                                                <ListView.ContextMenu>                                <ContextMenu Name="ContextMenu">                                    <MenuItem Header="创建工程" />                                    <MenuItem Header="添加工程" />                                    <MenuItem Header="打开工程" />                                    <MenuItem Header="删除工程" />                                                                                        </ContextMenu>                            </ListView.ContextMenu>                                                                        </ListView>                                        </l:GridLineDecorator>                    </Grid></window>

6.    在界面主XAML文件对应的cs文件的构造函数中,加入以下内容

public MainWindow(){   this.InitializeComponent();   // 在此点下面插入创建对象所需的代码。   string xmlpath = Directory.GetCurrentDirectory() + "\\context.xml";            XmlDocument xml = new XmlDocument();            xml.Load(xmlpath);            XmlDataProvider xdp = new XmlDataProvider();            xdp.Document = xml;            xdp.XPath = @"/Context/URInfo";            this.FileInfo.DataContext = xdp;            this.FileInfo.SetBinding(ComboBox.ItemsSourceProperty, new Binding());}

7.      自己建立一个xml文件,里面填上相应的数据(有几列就写几列)

8.      编译WPF程序,大功告成了!


原创粉丝点击