WPF报表自定义通用可筛选列头-WPF特工队内部资料

由于项目需要制作一个可通用的报表多行标题,且可实现各种类型的内容显示,包括文本、输入框、下拉框、多选框等(自定的显示内容可自行扩展),并支持参数绑定转换,效果如下:

  

  

  

  源码结构

ColumnItem类:对列的宽度,对象方式,显示类型,绑定名称,converter资源进行设置

    /// <summary>
    /// 描述 <see cref="ColumnItem"/> 动态列项目,用于在后台构建多列标题绑定项
    /// </summary>
    [Serializable]
    public sealed class ColumnItem : NotifyPropertyChangedBase, ICloneable
    {
        /// <summary>
        /// 实例化 <see cref="ColumnItem"/> 类新实例,一般用于顶级标题栏
        /// </summary>
        /// <param name="name">默认列名</param>
        public ColumnItem(String name)
            : this(name, "")
        {
        }

        /// <summary>
        /// 实例化 <see cref="ColumnItem"/> 类新实例
        /// </summary>
        /// <param name="name">默认列名</param>
        /// <param name="bindingName">绑定名称</param>
        public ColumnItem(String name, String bindingName)
            : this(name, bindingName, "", "", HorizontalAlignment.Left, 80)
        {
        }

        /// <summary>
        /// 实例化 <see cref="ColumnItem"/> 类新实例
        /// </summary>
        /// <param name="name">默认列名</param>
        /// <param name="bindingName">绑定名称</param>
        /// <param name="converterResourceKey">绑定的资源键(传递此资源时,要在资源中声明)</param>
        /// <param name="stringFormat">字符串格式</param>
        /// <param name="alignment">对齐方式</param>
        /// <param name="width">列宽</param>
        /// <param name="visibility">是否显示</param>
        public ColumnItem(String name, String bindingName, String converterResourceKey, String stringFormat, HorizontalAlignment alignment, int width, Visibility visibility)
            : this(name, "", bindingName, converterResourceKey, stringFormat, alignment, width, visibility, ColumnType.TextBlock)
        {

        }

        /// <summary>
        /// 实例化 <see cref="ColumnItem"/> 类新实例
        /// </summary>
        /// <param name="name">默认列名</param>
        /// <param name="bindingName">绑定名称</param>
        /// <param name="converterResourceKey">绑定的资源键(传递此资源时,要在资源中声明)</param>
        /// <param name="stringFormat">字符串格式</param>
        /// <param name="alignment">对齐方式</param>
        /// <param name="width">列宽</param>
        public ColumnItem(String name, String bindingName, String converterResourceKey, String stringFormat, HorizontalAlignment alignment, int width)
            : this(name, "", bindingName, converterResourceKey, stringFormat, alignment, width, Visibility.Visible, ColumnType.TextBlock)
        {

        }

        /// <summary>
        /// 实例化 <see cref="ColumnItem"/> 类新实例
        /// </summary>
        /// <param name="name">默认列名</param>
        /// <param name="extendName">扩展列名</param>
        /// <param name="bindingName">绑定名称</param>
        /// <param name="converterResourceKey">绑定的资源键(传递此资源时,要在资源中声明)</param>
        /// <param name="stringFormat">字符串格式</param>
        /// <param name="alignment">对齐方式</param>
        /// <param name="width">列宽</param>
        public ColumnItem(String name, String extendName, String bindingName, String converterResourceKey, String stringFormat, HorizontalAlignment alignment, int width)
       : this(name, extendName, bindingName, converterResourceKey, stringFormat, alignment, width, Visibility.Visible, ColumnType.TextBlock)
        {

        }

        /// <summary>
        /// 实例化 <see cref="ColumnItem"/> 类新实例
        /// </summary>
        /// <param name="name">默认列名</param>
        /// <param name="bindingName">绑定名称</param>
        /// <param name="converterResourceKey">绑定的资源键(传递此资源时,要在资源中声明)</param>
        /// <param name="stringFormat">字符串格式</param>
        /// <param name="alignment">对齐方式</param>
        /// <param name="width">列宽</param>
        /// <param name="columnType">数据模板内容类型</param>
        public ColumnItem(String name, String bindingName, String converterResourceKey, String stringFormat, HorizontalAlignment alignment, int width, ColumnType columnType)
            : this(name, "", bindingName, converterResourceKey, stringFormat, alignment, width, Visibility.Visible, columnType)
        {

        }
        /// <summary>
        /// 实例化 <see cref="ColumnItem"/> 类新实例
        /// </summary>
        /// <param name="name">默认列名</param>
        /// <param name="extendName">扩展列名</param>
        /// <param name="bindingName">绑定名称</param>
        /// <param name="converterResourceKey">绑定的资源键(传递此资源时,要在资源中声明)</param>
        /// <param name="stringFormat">字符串格式</param>
        /// <param name="alignment">对齐方式</param>
        /// <param name="width">列宽</param>
        /// <param name="columnType">数据模板内容类型</param>
        public ColumnItem(String name, String extendName, String bindingName, String converterResourceKey, String stringFormat, HorizontalAlignment alignment, int width, Visibility visibility)
            : this(name, extendName, bindingName, converterResourceKey, stringFormat, alignment, width, visibility, ColumnType.TextBlock)
        {

        }

        /// <summary>
        /// 实例化 <see cref="ColumnItem"/> 类新实例
        /// </summary>
        /// <param name="name">默认列名</param>
        /// <param name="extendName">扩展列名</param>
        /// <param name="bindingName">绑定名称</param>
        /// <param name="converterResourceKey">绑定的资源键(传递此资源时,要在资源中声明)</param>
        /// <param name="stringFormat">字符串格式</param>
        /// <param name="alignment">对齐方式</param>
        /// <param name="width">列宽</param>
        /// <param name="columnType">数据模板内容类型</param>
        public ColumnItem(String name, String extendName, String bindingName, String converterResourceKey, String stringFormat, HorizontalAlignment alignment, int width, ColumnType columnType)
            : this(name, extendName, bindingName, converterResourceKey, stringFormat, alignment, width, Visibility.Visible, columnType)
        {

        }

        /// <summary>
        /// 实例化 <see cref="ColumnItem"/> 类新实例
        /// </summary>
        /// <param name="name">默认列名</param>
        /// <param name="extendName">扩展列名</param>
        /// <param name="bindingName">绑定名称</param>
        /// <param name="converterResourceKey">绑定的资源键(传递此资源时,要在资源中声明)</param>
        /// <param name="stringFormat">字符串格式</param>
        /// <param name="alignment">对齐方式</param>
        /// <param name="width">列宽</param>
        /// <param name="visibility">是否显示</param>
        /// <param name="columnType">数据模板内容类型</param>
        public ColumnItem(String name, String extendName, String bindingName, String converterResourceKey, String stringFormat, HorizontalAlignment alignment, int width, Visibility visibility, ColumnType columnType)
        {
            this.ID = Guid.NewGuid();
            if (String.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException("titleName", "标题不能为 null 或 空白字符串。");
            }
            this.Name = name;
            this.ExtendName = extendName;
            this.BindingName = (String.IsNullOrWhiteSpace(bindingName)) ? "simple" : bindingName;
            this.ConverterResourceKey = converterResourceKey;
            this.StringFormat = stringFormat;
            this.Alignment = alignment;
            this.Width = width;
            this.Visibility = visibility;
            this.Type = columnType;
            this.Columns = new ColumnItemCollection(this);  //初始化
            this.Level = 0; //默认
            this.TextWrapping = System.Windows.TextWrapping.NoWrap;
        }

        private Int32 mWidth;
        private Visibility mVisibility;
        private HorizontalAlignment mAlignment;

        public Guid ID { get; private set; }

        /// <summary>
        /// 列宽
        /// </summary>
        public Int32 Width
        {
            get { return mWidth; }
            set { mWidth = value; OnPropertyChanged("Width"); }
        }

        /// <summary>
        /// 列显示
        /// </summary>
        public Visibility Visibility
        {
            get { return mVisibility; }
            set { mVisibility = value; OnPropertyChanged("Visibility"); }
        }

        /// <summary>
        /// 获取或设置水平对齐方式
        /// </summary>
        public HorizontalAlignment Alignment
        {
            get { return mAlignment; }
            set { mAlignment = value; OnPropertyChanged("Alignment"); }
        }

        /// <summary>
        /// 默认列名
        /// </summary>
        public String Name { get; private set; }

        /// <summary>
        /// 扩展列名
        /// </summary>
        public String ExtendName { get; set; }

        /// <summary>
        /// 绑定名称
        /// </summary>
        public String BindingName { get; set; }

        /// <summary>
        /// 获取或设置转换资源键
        /// </summary>
        public String ConverterResourceKey { get; set; }

        /// <summary>
        /// 获取或设置字符串格式
        /// </summary>
        public String StringFormat { get; set; }

        /// <summary>
        /// 控件类型
        /// </summary>
        public ColumnType Type { get; set; }

        /// <summary>
        /// 获取或设置是否自动换行(默认为 NoWrap)
        /// </summary>
        public TextWrapping TextWrapping { get; set; }

        public ColumnComboBox ColumnComboBox { get; set; }

        /// <summary>
        /// 获取列集合
        /// </summary>
        public ColumnItemCollection Columns { get; private set; }

        /// <summary>
        /// 获取级别
        /// </summary>
        public int Level { get; internal set; }

        /// <summary>
        /// 获取父级
        /// </summary>
        public ColumnItem Parent { get; internal set; }

        /// <summary>
        /// 获取子级深度
        /// </summary>
        /// <returns></returns>
        public int ChildLevelDepth()
        {
            if (this.Columns.Count > 0)
            {
                return this.CalcLevelDepth(true) - this.Level;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// 计算获取级别深度
        /// </summary>
        /// <param name="child">计算子级</param>
        /// <returns></returns>
        private int CalcLevelDepth(bool child)
        {
            if (this.Columns.Count > 0)
            {
                int level = this.Columns.Max(c => c.CalcLevelDepth(child));
                if (child)
                {
                    return level;
                }
                else
                {
                    return level - this.Level;
                }
            }
            else
            {
                return this.Level;
            }
        }

        /// <summary>
        /// 获取当前列的所有最后子集的总数
        /// </summary>
        /// <returns></returns>
        public int LastLevelColumnCount()
        {
            int value = 0;
            if (this.Columns.Count > 0)
            {
                value += this.Columns.Sum(c => c.LastLevelColumnCount());
            }
            else
            {
                value = 1;
            }
            return value;
        }

        /// <summary>
        /// 合计总宽度
        /// </summary>
        /// <returns></returns>
        public int TotalGroupWidth()
        {
            int value;
            if (this.Columns.Count > 0)
            {
                value = this.Columns.Sum(c => c.TotalGroupWidth());
            }
            else
            {
                value = this.Width;
            }
            return value;
        }

        /// <summary>
        /// 验证(必须设置绑定值)
        /// </summary>
        internal void CreateVerify()
        {
            if (this.Columns.Count == 0)
            {
                if (String.IsNullOrWhiteSpace(this.BindingName))
                {
                    throw new ArgumentNullException(String.Format("{0} 为末级时,绑定路径 BindingPath 为 null 或空白字符串。", this.Name));
                }
            }
        }

        public void SetColumnComboBox(ColumnComboBox columnComboBox)
        {
            this.ColumnComboBox = columnComboBox;
        }

        #region ICloneable ColumnItem 对象深度复制
        public object Clone()
        {
            ColumnItem item = (ColumnItem)this.MemberwiseClone();
            item.Parent = null;
            item.Name = this.Name;
            item.ExtendName = this.ExtendName;
            item.Columns = new ColumnItemCollection(item);
            foreach (var o in this.Columns)
            {
                var _o = (ColumnItem)o.Clone();
                _o.Parent = null;
                item.Columns.Add(_o);
            }
            return item;
        }
        private void OnClone(ColumnItemCollection collection, ColumnItemCollection collection2)
        {
            foreach (var item in collection2)
            {
                var _o = (ColumnItem)item.Clone();
                if (item.Columns.Count > 0)
                {
                    OnClone(item.Columns, item.Columns);
                }
                collection.Add(_o);
            }
        }

        #endregion
    }
    [Serializable]
    public class ColumnComboBox : NotifyPropertyChangedBase
    {
        public ColumnComboBox(String comboBoxBindName)
            : this(comboBoxBindName, "", "", "")
        {

        }
        public ColumnComboBox(String comboBoxBindName, String selectedItemBindName)
            : this(comboBoxBindName, selectedItemBindName, "", "")
        {

        }
        public ColumnComboBox(String comboBoxBindName, String selectedItemBindName, String selectedValuePath, String displayMemberPath)
        {
            this.mComboBoxBindName = comboBoxBindName;
            this.mSelectedItemBindName = selectedItemBindName;
            this.mSelectedValuePath = selectedValuePath;
            this.mDisplayMemberPath = displayMemberPath;
        }

        private String mSelectedItemBindName;
        private String mComboBoxBindName;
        private String mSelectedValuePath = "";
        private String mDisplayMemberPath = "";
        private ObservableCollection<string> itemSource;  //

        /// <summary>
        /// 绑定资源
        /// </summary>
        public String ComboBoxBindName
        {
            get
            {
                return mComboBoxBindName;
            }

            set
            {
                mComboBoxBindName = value;
            }
        }

        /// <summary>
        /// 选中值
        /// </summary>
        public string SelectedValuePath
        {
            get
            {
                return mSelectedValuePath;
            }

            set
            {
                mSelectedValuePath = value;
            }
        }

        /// <summary>
        /// 显示值
        /// </summary>
        public string DisplayMemberPath
        {
            get
            {
                return mDisplayMemberPath;
            }

            set
            {
                mDisplayMemberPath = value;
            }
        }

        public string SelectedItemBindName
        {
            get
            {
                return mSelectedItemBindName;
            }

            set
            {
                mSelectedItemBindName = value;
            }
        }
    }

报表内容中需要其他类型时,扩展IDataGridDataTemplateService接口

    /// <summary>
    /// <see cref="DataGrid"/>控件数据模板<see cref="DataTemplate"/>构建服务,
    /// 根据<see cref="DataTemplate"/>的内容多样性构建不同的显示控件,主要针对单一控件显示
    /// </summary>
    public interface IDataGridDataTemplateService
    {
        /// <summary>
        /// 动态构内容绑定模板
        /// </summary>
        /// <param name="column">自定义列信息</param>
        /// <param name="bindingParameter">是否参数转换</param>
        /// <param name="gridColum">绑定的子列索引 </param>
        /// <returns></returns>
        String CreateCellXaml(ColumnItem column, bool bindingParameter, int? gridColum);
    }

DataGridTemplateColumnHelper核心类,组织动态的列标题以及绑定列,可在下载源码参考。

    /// <summary>
    /// 自定义模板列构建帮助类
    /// </summary>
    internal static class DataGridTemplateColumnHelper
    {
        /// <summary>
        /// 设置标题Grid列宽度,组织出一个复杂的标题格式
        /// </summary>
        /// <param name="sbStr">标题字符串</param>
        /// <param name="column">列</param>
        /// <param name="index">列索引,用于控制标题内容显示的边线</param>
        private static void SetColumnDefinition(StringBuilder sbStr, ColumnItem column, ref int index)
        {
            if (column.Columns.Count > 0)
            {
                foreach (var item in column.Columns)
                {
                    SetColumnDefinition(sbStr, item, ref index);
                }
            }
            else  //默认包含一列
            {
                if (index > 0) //当index>0时,添加一个右侧的Rectangle矩形图形边线位置,默认是左侧和右侧是不绘制边线
                {
                    sbStr.AppendLine("<ColumnDefinition Width=\"1\" />");
                }
                //添加一个标题的显示内容列,并设置固定宽度
                sbStr.AppendLine(String.Format("<ColumnDefinition Width=\"{0}*\"/>", column.Width));
                index++;
            }
        }

        /// <summary>
        /// 设置标题内容
        /// </summary>
        /// <param name="sbStr"></param>
        /// <param name="column">当前列</param>
        /// <param name="totalcolumnCount">总列数</param>
        /// <param name="colIndex">内容索引列</param>
        private static void SetContentPresenter(StringBuilder sbStr, ColumnItem column, int totalcolumnCount, ref int colIndex)
        {
            //计算出当前列所占的Grid的ColumnDefinition数目
            int columnOffset = column.LastLevelColumnCount() * 2 - 1;
            //计算当前列在整个标题中的标题行深度
            int LevelDepth = column.Parent.ChildLevelDepth();
            //用于控制绘制标题内容下面显示下线,以及当前显示标题的Grid.RowSpan
            int rowOffset;  //一般情况默认为1
            if (column.Columns.Count == 0)//
            {
                rowOffset = LevelDepth * 2 - 1;
            }
            else
            {
                rowOffset = 1; //
            }
            //计算出当前标题在第几个RowDefinition画内容下边线
            int lineRow = (column.Level * 2 + 1) + (rowOffset - 1);
            //计算出当前标题在第几个ColumnDefinition画内容右边线
            int lineColumn = (colIndex + 1) + (columnOffset - 1);
            //画标题,并设置当前标题在Grid中的定位
            sbStr.AppendLine(
                CreateDataGridTemplateColumnHeaderContent(
                    String.IsNullOrWhiteSpace(column.ExtendName) ? column.Name : column.ExtendName,  //标题显示内容
                    column.Level * 2,  //所属行,标题内容显示的Grid.Row
                    rowOffset,  //标题内容显示的Grid.RowSpan
                    colIndex,  //标题内容显示的Grid.Column列
                    columnOffset //标题内容显示的Grid.ColumnSpan
                ));
            //存在子级,时添加下线
            if (column.Columns.Count > 0)
            {
                sbStr.AppendLine(String.Format("<Rectangle Fill=\"#FFC9CACA\" VerticalAlignment=\"Stretch\" Height=\"1\" Grid.Row=\"{0}\" Grid.Column=\"{1}\" Grid.RowSpan=\"{2}\" Grid.ColumnSpan=\"{3}\" />", lineRow, colIndex, 1, columnOffset));
            }
            //标题右侧下线
            if (lineColumn < (totalcolumnCount * 2 - 1))
            {
                sbStr.AppendLine(String.Format("<Rectangle Fill=\"#FFC9CACA\" VerticalAlignment=\"Stretch\" Width=\"1\" Visibility=\"Visible\" Grid.Row=\"{0}\" Grid.Column=\"{1}\" Grid.RowSpan=\"{2}\" Grid.ColumnSpan=\"{3}\" />", column.Level * 2, lineColumn, rowOffset, 1));
            }
            //存在子级,先从子级起画
            if (column.Columns.Count > 0)
            {
                foreach (var item in column.Columns)
                {
                    SetContentPresenter(sbStr, item, totalcolumnCount, ref colIndex);
                }
            }
            else
            {
                colIndex += 2; //含分隔线
            }
        }

        /// <summary>
        /// 设置单元格绑定
        /// </summary>
        /// <param name="sbStr"></param>
        /// <param name="column"></param>
        /// <param name="bindingParameter"></param>
        /// <param name="index"></param>
        private static void SetCellBinding(StringBuilder sbStr, ColumnItem column, bool bindingParameter, ref int index)
        {
            if (column.Columns.Count > 0)
            {
                foreach (var item in column.Columns)
                {
                    SetCellBinding(sbStr, item, bindingParameter, ref index);
                }
            }
            else
            {
                if (index > 0)
                {
                    sbStr.AppendLine(String.Format("<Rectangle Fill=\"#FFC9CACA\" VerticalAlignment=\"Stretch\" Grid.Column=\"{0}\"/>", index));
                    index++;
                }
                //构建指定类型的项绑定
                IDataGridDataTemplateFactory templateFactory = ServiceFactory.GetService<IDataGridDataTemplateFactory>();
                IDataGridDataTemplateService templateService = templateFactory.GetService(column.Type);
                sbStr.AppendLine(templateService.CreateCellXaml(column, bindingParameter, index));
                index++;
            }
        }

        /// <summary>
        /// 设置单元格列宽
        /// </summary>
        /// <param name="sbStr"></param>
        /// <param name="column"></param>
        /// <param name="index"></param>
        private static void SetCellColumnDefinition(StringBuilder sbStr, ColumnItem column, ref int index)
        {
            if (column.Columns.Count > 0)
            {
                foreach (var item in column.Columns)
                {
                    SetCellColumnDefinition(sbStr, item, ref index);
                }
            }
            else
            {
                if (index > 0)
                {
                    sbStr.AppendLine("<ColumnDefinition Width=\"1\" />");
                }
                sbStr.AppendLine(String.Format("<ColumnDefinition Width=\"{0}*\"/>", column.Width));
                index++;
            }
        }

        /// <summary>
        /// 创建组列
        /// </summary>
        /// <param name="column">列</param>
        /// <param name="bindingParameter">是否是参数</param>
        /// <returns></returns>
        public static DataGridTemplateColumn CreateTemplateGroupColumn(ColumnItem column, bool bindingParameter)
        {
            var templateColumn = new DataGridTemplateColumn();
            //当前列包含的子级深度
            int LevelDepth = column.ChildLevelDepth();
            //获取当前列子级的总列数
            int totalcolumnCount = column.LastLevelColumnCount();    //
            //设置当前列的宽度
            templateColumn.Width = new DataGridLength(column.TotalGroupWidth() + LevelDepth);
            //构建HeaderStyle以及CellTemplate模板
            //动态构建标题样式 DataGridTemplateColumn.HeaderStyle
            #region 构建多行标题
            var sbHeaderStr = new StringBuilder();
            sbHeaderStr.AppendLine("<Grid.RowDefinitions>");
            for (int i = 0; i <= LevelDepth; i++)
            {
                if (i > 0)
                {
                    sbHeaderStr.AppendLine("<RowDefinition Height=\"1\" />");  //构建分割线,
                }
                if (i < LevelDepth)
                {
                    sbHeaderStr.AppendLine("<RowDefinition Height=\"25\" />");  //内容区域
                }
                else
                {
                    sbHeaderStr.AppendLine("<RowDefinition Height=\"*\" MinHeight=\"25\"/>"); //内容区域
                }
            }
            sbHeaderStr.AppendLine("</Grid.RowDefinitions>");
            sbHeaderStr.AppendLine("<Grid.ColumnDefinitions>");
            int index = 0;
            foreach (var item in column.Columns)
            {
                SetColumnDefinition(sbHeaderStr, item, ref index);
            }
            sbHeaderStr.AppendLine("</Grid.ColumnDefinitions>");

            int columnOffset = totalcolumnCount * 2 - 1;

            sbHeaderStr.AppendLine(CreateDataGridTemplateColumnHeaderContent(String.IsNullOrWhiteSpace(column.ExtendName) ? column.Name : column.ExtendName, -1, -1, -1, columnOffset));

            sbHeaderStr.AppendLine(String.Format("<Rectangle Fill=\"#FFC9CACA\" VerticalAlignment=\"Stretch\" Height=\"1\" Grid.Row=\"1\" Grid.ColumnSpan=\"{0}\" />", columnOffset));

            index = 0;
            foreach (var item in column.Columns)
            {
                SetContentPresenter(sbHeaderStr, item, totalcolumnCount, ref index);
            }
            var headerStyleStr = HeaderStyleString();
            headerStyleStr = headerStyleStr.Replace("{#content#}", sbHeaderStr.ToString());
            templateColumn.HeaderStyle = (Style)XamlReader.Parse(headerStyleStr);
            #endregion
            //动态构建绑定DataTemplate DataGridTemplateColumn.CellTemplate
            #region 构建多行标题数据绑定模板
            var sbCellTempStr = new StringBuilder();
            sbCellTempStr.AppendLine("<Grid.ColumnDefinitions>");
            index = 0;
            foreach (var item in column.Columns)
            {
                SetCellColumnDefinition(sbCellTempStr, item, ref index);
            }
            sbCellTempStr.AppendLine("</Grid.ColumnDefinitions>");
            index = 0;
            foreach (var item in column.Columns)
            {
                SetCellBinding(sbCellTempStr, item, bindingParameter, ref index);
            }
            var cellTemplateStr = CellDataTemplateString();
            cellTemplateStr = cellTemplateStr.Replace("{#content#}", sbCellTempStr.ToString());
            templateColumn.CellTemplate = (DataTemplate)XamlReader.Parse(cellTemplateStr);
            #endregion
            return templateColumn;
        }

        /// <summary>
        /// 动态构建标题模板
        /// </summary>
        /// <param name="sbStr">目标结果</param>
        /// <param name="title">标题名称</param>
        /// <param name="row">所属Grid行Grid.Row</param>
        /// <param name="rowSpan">所属合并行Grid.RowSpan</param>
        /// <param name="column">所属Grid列Grid.Column</param>
        /// <param name="columnSpan">所属合并列Grid.ColumnSpan</param>
        private static String CreateDataGridTemplateColumnHeaderContent(String title, int row, int rowSpan, int column, int columnSpan)
        {
            StringBuilder sbStr = new StringBuilder();
            sbStr.AppendLine("<ContentPresenter VerticalAlignment=\"Center\" HorizontalAlignment=\"Center\"");
            if (row > 0)
            {
                sbStr.AppendFormat(" Grid.Row=\"{0}\"", row);
            }
            if (rowSpan > 0)
            {
                sbStr.AppendFormat(" Grid.RowSpan=\"{0}\"", rowSpan);
            }
            if (column > 0)
            {
                sbStr.AppendFormat(" Grid.Column=\"{0}\"", column);
            }
            if (columnSpan > 0)
            {
                sbStr.AppendFormat(" Grid.ColumnSpan=\"{0}\"", columnSpan);
            }
            sbStr.Append(">");
            sbStr.AppendLine("<ContentPresenter.Content>");
            sbStr.AppendLine(String.Format("<TextBlock Text=\"{0}\" TextAlignment=\"Center\" TextWrapping=\"Wrap\" />", title));
            sbStr.AppendLine("</ContentPresenter.Content>");
            sbStr.AppendLine("</ContentPresenter>");
            return sbStr.ToString();
        }

        /// <summary>
        /// 创建单列
        /// </summary>
        /// <param name="column"></param>
        /// <param name="bindingParameter"></param>
        /// <returns></returns>
        public static DataGridTemplateColumn CreateTemplateSingleColumn(ColumnItem column, bool bindingParameter)
        {
            if (column == null)
            {
                throw new ArgumentNullException("column");
            }
            if (String.IsNullOrWhiteSpace(column.BindingName))
            {
                throw new ArgumentNullException("column.BindingName", "末级列的绑定名称不能为 null 或空白字符串。");
            }
            //创建DataGrid的列
            var templateColumn = new DataGridTemplateColumn();
            //设置列的宽度
            templateColumn.Width = new DataGridLength(column.Width);
            //构建模板字符串
            var sbStr = new StringBuilder();
            //根据模板创建标题
            sbStr.AppendLine(CreateDataGridTemplateColumnHeaderContent(String.IsNullOrWhiteSpace(column.ExtendName) ? column.Name : column.ExtendName, -1, -1, -1, -1));
            //动态构建标题样式 DataGridTemplateColumn.HeaderStyle
            #region DataGridTemplateColumn.HeaderStyle
            var headerStyleStr = HeaderStyleString();
            headerStyleStr = headerStyleStr.Replace("{#content#}", sbStr.ToString());
            templateColumn.HeaderStyle = (Style)XamlReader.Parse(headerStyleStr);
            sbStr.Clear();
            #endregion
            //动态构建绑定DataTemplate DataGridTemplateColumn.CellTemplate
            #region DataGridTemplateColumn.CellTemplate
            //构建绑定模板
            IDataGridDataTemplateFactory templateFactory = ServiceFactory.GetService<IDataGridDataTemplateFactory>();
            IDataGridDataTemplateService templateService = templateFactory.GetService(column.Type);
            sbStr.AppendLine(templateService.CreateCellXaml(column, bindingParameter, null));
            String cellTemplateStr = CellDataTemplateString();
            cellTemplateStr = cellTemplateStr.Replace("{#content#}", sbStr.ToString());
            templateColumn.CellTemplate = (DataTemplate)XamlReader.Parse(cellTemplateStr);
            #endregion
            return templateColumn;
        }

        #region 本地资源模板处理

        private static object lockObj = new object();
        private static String _HeaderStyleString = null;  //
        private static String _CellDataTemplateString = null;//

        /// <summary>
        /// 获取标题样式
        /// </summary>
        /// <returns></returns>
        public static String HeaderStyleString()
        {
            lock (lockObj)
            {
                if (_HeaderStyleString == null)
                {
                    _HeaderStyleString = GetResourceXamlString("HeaderStyle.xaml");
                }
                return _HeaderStyleString;
            }
        }

        /// <summary>
        /// 获取单元格模板字符串
        /// </summary>
        /// <returns></returns>
        public static String CellDataTemplateString()
        {
            lock (lockObj)
            {
                if (_CellDataTemplateString == null)
                {
                    _CellDataTemplateString = GetResourceXamlString("CellDataTemplate.xaml");
                }
                return _CellDataTemplateString;
            }
        }

        /// <summary>
        /// 获取资源Xaml字符串
        /// </summary>
        /// <param name="fileName">文件名称</param>
        /// <returns></returns>
        private static String GetResourceXamlString(String fileName)
        {
            var res = Application.GetResourceStream(new Uri(String.Format("pack://application:,,,/TGP.DataGridDemo;component/Template/{0}", fileName), UriKind.RelativeOrAbsolute));
            using (var sr = new StreamReader(res.Stream))
            {
                return sr.ReadToEnd();
            }
        }

        #endregion
    }

  源码下载

  

时间: 2024-10-13 20:52:54

WPF报表自定义通用可筛选列头-WPF特工队内部资料的相关文章

WPF管理系统自定义分页控件 - WPF特工队内部资料

原文:WPF管理系统自定义分页控件 - WPF特工队内部资料 最近做一个演示的管理系统项目,需要用到分页控件,在网上找了很多,依然找到与UI模版匹配的,最后干脆自己写一个. 分页控件分析: 1.分页控件分简单显示和复杂显示两种: 2.包含上一页.下一页以及页码明细逻辑处理: 3.页码总数小于7时显示默认显示,大于7时切换复杂显示: 4.页码数.索引.总条数计算等: 先来一张效果图: 啥也不说了直接上代码 MISPager.xaml部分 <ResourceDictionary xmlns="

WPF (DataGridColumnHeader)实现自义定列头样式 并绑定数据

原文:WPF (DataGridColumnHeader)实现自义定列头样式 并绑定数据 实现功能是这样的 自定义列头 样式 样式里的 数据来源于后台绑定 这篇就说头样式 和头样式数据绑定 思路 1)实现功能的时候 首先想的是编辑列头样式 选择使用DataGridTextColumn 编辑 DataGridColumnHeader 样式 样式很简单 就布局好了 这段结束 2)动态列 没有要求换肤 所以就没有完全使用MVVM 直接写后台循环   到这里数据有了 List<string> LS =

交叉报表列头排序时遇到的oracle问题—oracle ORA-12704:字符集不匹配、varchar2转化为nvarchar2字符缺失、case when else后的字符类型要一致

在做交叉报表列头的排序时,遇到这三个问题,下面具体来说一下. 设计的数据库的表结构如图1所示: 图1 要处出来student_name_,s.grade_,s.subject_name_,这三个属性,当时我是这样写的sql语句: select  s.student_name_, s.grade_,  s.subject_name_, case  s.subject_name_ when  '语文' then 'A语文' when  '数学' then 'B数学' when  '英语' then 

WPF DataGrid DataGridTemplateColumn 列头checkbox如何在代码中取消选择

0 登录进行投票 <DataGrid Name="DG">                <DataGrid.Columns>                    <DataGridTemplateColumn Width="70">                        <DataGridTemplateColumn.HeaderTemplate>                            &l

WPF DataGrid自定义样式

WPF DataGrid自定义样式 微软的WPF DataGrid中有很多的属性和样式,你可以调整,以寻找合适的(如果你是一名设计师).下面,找到我的小抄造型的网格.它不是100%全面,但它可以让你走得很远,有一些非常有用的技巧和陷阱. 在DataGrid中的最高水平,你可以改变的外观和感觉,通过设置一些: Property Type Values Default AlternatingRowBackground Brush Any Brush Null Background Brush Any

Asp.net中动态控制RDLC报表 自定义RDLC

转载自: http://dlwang2002.cnblogs.com/archive/2006/05/27/410499.html 在asp.net程序中,可以选择使用水晶报表,功能确实强大.但是web版的水晶报表好像存在版权的问题.如果所作报表不是复杂的一塌糊涂的话,可以使用微软自带的Rdlc报表.已经有老兄做出了不少诠释:http://www.cnblogs.com/waxdoll/更多资料可以在这里找到:http://www.gotreportviewer.com/Rdlc优点:1:Rdl

水晶报表的三种筛选方法

目录: 一.解决方案一:报表数据访问使用推模型 二.解决方案二:记录选定公式运行时自定义 三.解决方案三:将参数合并到记录选定公式 ---------------------------------- 解决方案一: 报表数据访问使用推模型 需要开发人员编写代码以连接到数据库,执行 SQL 命令以创建与报表中的字段匹配的记录集或数据集,并且将该对象传递给报表.该方法使您可以将连接共享置入应用程序中,并在 Crystal Reports 收到数据之前先将数据筛选出来. ---------------

WPF:设置DataGrid中DataGridColumn列的普通样式和编辑样式

WPF:设置DataGrid中DataGridColumn列的普通样式和编辑样式 时间:2012-02-01 20:28来源:博客园 作者:刘圆圆 点击:1570次 0:DataGridColumn类型的继承树 DataGridColumn的派生类: 一般情况下DataGridBoundColumn和DataGridComboBoxColumn足以满足多数列的样式,如果需要自定义列样式,则可以使用DataGridTemplateColumn类型. 在设置列编辑样式之前,我们先创建一个简单的Dat

gridcontrol的列头右键菜单问题

Dev控件GridControl设置了一个右键菜单 this.gridControl1.ContextMenu = contextMenu2; 而GridControl在运行排序的时候,即 gridview1->OptionsCustomization->AllowSort设为true时,控件自带一个英文的右键菜单如下 这样当点击表列头时,就会出现下面的两个右键菜单重叠问题. 这样当点击表列头时,就会出现下面的两个右键菜单重叠问题. 解决办法: privatevoid gridView1_Mo