给WPF中的DataGrid控件添加右键菜单(ContextMenu),以便用户可以显示或者隐藏DataGrid中的列,并且下次运行时依然保持上次关闭时的列的布局
历经了半个月的时间,终于做出了一个可以实现如题功能的自定义DataGrid控件(也就是个UserControl)。不过由于这个控件有点依赖与我们项目中的其他东西,所以我把之前做的一个类天拿出来和大家分享一下,这个类是那个控件的核心,控件也就是在这个类的基础上包了层XAML代码,加了些我们项目中特有的东西而已。我觉得这个东西对于我这毕业还不到一年的菜鸟来说还是有一些难度的。
下面贴出代码,我觉得我在代码里面写的注释挺详细,文章中就不再多说了。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Data; using System.Xml; using System.Windows.Controls; using System.Windows; namespace TincyhoHelper { /// <summary> /// 声明全局变量,一个string型,作为文件名,一个DataGrid型,即指定的DataGrid /// 实例化时将指定的DataGrid和文件名作为参数传入该类。 /// 载入页面时,先加载右键菜单。再从XML文件读取配置信息,这里必须加System.IO.File.Exist()条件判断文件是否存在 /// 关闭页面时将配置信息写入XML文件 /// </summary> public class ColumnHelper { string filename; XmlDocument xmlDoc = new XmlDocument(); DataGrid dgPerson; /// <summary> /// 用指定的DataGrid和文件名初始化ColumnHelper类的新实例 /// </summary> /// <param name="dgPerson"></param> public ColumnHelper(DataGrid dgPerson, string filename) { // TODO: Complete member initialization this.dgPerson = dgPerson; this.filename = filename; } /// <summary> /// 添加右键菜单中的CheckBox /// </summary> /// <param name="content">CheckBox显示的名字</param> /// <param name="source">绑定的列名</param> public void addCheckbox() { ContextMenu cm = new ContextMenu(); for (int i = 0; i < dgPerson.Columns.Count; i++) { CheckBox cb = new CheckBox(); cb.Content = dgPerson.Columns[i].Header.ToString(); bindColumnAndCheckbox(dgPerson.Columns[i], cb); cm.Items.Add(cb); } dgPerson.ContextMenu = cm; } /// <summary> /// 将DataGrid中的列的Visibility属性和CheckBox的IsCheck属性绑定 /// </summary> /// <param name="column">绑定的列名</param> /// <param name="checkbox">显示的CheckBox</param> public void bindColumnAndCheckbox(object column, CheckBox checkbox) { Binding binding = new Binding("Visibility"); binding.Source = column; binding.Converter = new MyConverter(); // 设定Converter checkbox.SetBinding(CheckBox.IsCheckedProperty, binding); } /// <summary> /// 读取XML文件中的配置信息 /// </summary> /// <param name="filename">XML文件路径</param> public void readXML() { try { xmlDoc.Load(filename); XmlNodeList list = xmlDoc.GetElementsByTagName("*"); XmlElement element; for (int i = 1; i < list.Count; i++) { element = (XmlElement)list.Item(i); string str = element.InnerText.ToString(); dgPerson.Columns[i - 1].Visibility = (Visibility)Enum.Parse(typeof(Visibility), str, true); } } catch (Exception ex) { throw ex; } } /// <summary> /// 将配置信息写入XML文件中 /// </summary> /// <param name="filename">XML文件路径</param> public void writeXML() { try { XmlNode xmlNode = xmlDoc.CreateNode(XmlNodeType.XmlDeclaration, "", ""); XmlNode myNode = xmlDoc.CreateNode(XmlNodeType.Element, "appSetting", ""); if (!System.IO.File.Exists(filename)) { xmlDoc.AppendChild(xmlNode); xmlDoc.AppendChild(myNode); for (int i = 0; i < dgPerson.Columns.Count; i++) { string strRoot = dgPerson.Columns[i].Header.ToString(); string strText = dgPerson.Columns[i].Visibility.ToString(); XmlElement xmlelem = xmlDoc.CreateElement("", strRoot, ""); xmlelem.InnerText = strText; myNode.AppendChild(xmlelem); } xmlDoc.Save(filename); } else { xmlDoc.Load(filename); XmlNodeList list = xmlDoc.GetElementsByTagName("*"); XmlElement element; for (int i = 1; i < list.Count; i++) { element = (XmlElement)list.Item(i); element.InnerText = dgPerson.Columns[i - 1].Visibility.ToString(); } xmlDoc.Save(filename); } } catch (Exception ex) { throw ex; } } } /// <summary> /// 转换器。功能:使CheckBox的IsChecked属性和DataGrid控件中的列的Visibility属性可以关联。 /// </summary> [ValueConversion(typeof(Enum), typeof(bool?))] public class MyConverter : IValueConverter { /// <summary> /// 将DataGrid列的Visibility属性转换为bool型,方便CheckBox的IsChecked属性赋值 /// </summary> /// <param name="value"></param> /// <param name="targetType"></param> /// <param name="parameter"></param> /// <param name="culture"></param> /// <returns></returns> public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { string str = System.Convert.ToString(value); if (str.Equals("Visible")) return true; else return false; } /// <summary> /// 将CheckBox的IsChecked属性的bool值转换成Visibility属性,方便DataGrid列属性赋值 /// </summary> /// <param name="value"></param> /// <param name="targetType"></param> /// <param name="parameter"></param> /// <param name="culture"></param> /// <returns></returns> public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { bool b = System.Convert.ToBoolean(value); if (b.Equals(true)) { return (Visibility)Enum.Parse(typeof(Visibility), "Visible", true); } else return (Visibility)Enum.Parse(typeof(Visibility), "Hidden", true); } } }
在使用的时候,只要实例化一下这个类就可以了(这里记得要把需要该功能的DataGrid作为参数传入,由于我这里使用的是XML文件来保存用户的自定义列布局,所以还要将保存
XML的文件名也作为参数传入)。在页面加载时读取XML文件里的信息,以此判断哪些列显示,哪些列不显示。第一次运行时这个XML文件肯定不存在,所以要加上判断条件,不存
在就不管了(第一次运行肯定所有列都要显示出来),以后运行的话文件肯定已经存在了,这是再进行读取XML操作就好。页面关闭的时候调用写入XML的方法。 最终的运行效果
就是当在DataGrid控件上点击右键的时候,弹出和DataGrid中的列一一对应的CheckBox,并且CheckBox的IsChecked属性和DataGrid列的Visibility属性已经绑定。
截图如下: