https://github.com/xdqt/wpfdatagrid-filter-columnshow.git
ColumnHelper是给列头添加右键,动态设置列显示
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Xml;
namespace WpfApp.Helper
{
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);
}
//只给表头设置contextmenu
var columnHeadersPresenter = this.dgPerson.SafeFindDescendant<DataGridColumnHeadersPresenter>(ip => ip.Name == "PART_ColumnHeadersPresenter");
if (columnHeadersPresenter != null)
{
columnHeadersPresenter.ContextMenu = cm;
}
//for (int i = 0; i < dgPerson.Columns.Count; i++)
//{
// var tb = new TextBlock { Text = dgPerson.Columns[i] .Header.ToString()};
// tb.ContextMenu = cm;
// dgPerson.Columns[i].Header = tb;
//}
//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;
}
}
}
public static class Visual_ExtensionMethods
{
/// <summary>
/// Retrieves the first Descendant of the currren Visual in the VisualTree matching the given predicate
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="this">The current Visual.</param>
/// <param name="predicate">An optional predicate that the descendant have to satisfy.</param>
/// <returns></returns>
public static T SafeFindDescendant<T>(this Visual @this, Predicate<T> predicate = null) where T : Visual
{
T result = null;
if (@this == null)
{
return null;
}
// iterate on VisualTree children thanks to VisualTreeHelper
int childrenCount = VisualTreeHelper.GetChildrenCount(@this);
for (int i = 0; i < childrenCount; i++)
{
var currentChild = VisualTreeHelper.GetChild(@this, i);
var typedChild = currentChild as T;
if (typedChild == null)
{
// recursive search
result = ((Visual)currentChild).SafeFindDescendant<T>(predicate);
if (result != null)
{
break;
}
}
else
{
if (predicate == null || predicate(typedChild))
{
result = typedChild;
break;
}
}
}
return result;
}
}
/// <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);
}
}
}
usercontrol.xaml
<UserControl x:Class="WpfApp.UserControls.UserControls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:con="clr-namespace:WpfApp"
mc:Ignorable="d"
x:Name="main"
>
<UserControl.Resources>
<con:Visible x:Key="visible" />
<con:Images x:Key="image"/>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock Text="筛选: "/>
<TextBox Height="20" Width="100" x:Name="search" TextChanged="TextBox_TextChanged"/>
</StackPanel>
<DataGrid x:Name="test"
Margin="0,5"
PreviewMouseRightButtonDown="Test_PreviewMouseRightButtonDown"
Grid.Row="1"
CanUserAddRows="False"
SelectionMode="Single"
CanUserDeleteRows="False"
CanUserSortColumns="False"
CanUserReorderColumns ="True"
CanUserResizeColumns="True"
ItemsSource="{Binding datas}"
AutoGenerateColumns="False"
SelectedItem="{Binding Selected}">
<DataGrid.Columns>
<DataGridTextColumn Header="id" x:Name="id" Binding="{Binding ID}" Width="0.2*">
</DataGridTextColumn>
<DataGridTextColumn Header="age" x:Name="age" Binding="{Binding Age}" Width="0.2*">
</DataGridTextColumn>
<DataGridTextColumn Header="name" x:Name="name" Binding="{Binding Name}" Width="*">
</DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" >
<Setter Property="Height" Value="30" />
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex"
Value="0">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="合并账号" >
<MenuItem.Icon>
<StackPanel>
<Image Source="pack://application:,,,/ICON/icon.png"></Image>
</StackPanel>
</MenuItem.Icon>
<MenuItem Header="测试" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.SelectedItem,Converter={StaticResource visible}}">
</MenuItem>
<MenuItem Header="测试1" />
</MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</UserControl>
usercontrol.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WpfApp.Helper;
namespace WpfApp.UserControls
{
/// <summary>
/// UserControl.xaml 的交互逻辑
/// </summary>
public partial class UserControls : UserControl
{
public UserControls()
{
InitializeComponent();
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var cvs = CollectionViewSource.GetDefaultView(test.ItemsSource);
if (cvs != null && cvs.CanFilter)
{
cvs.Filter = OnFilterApplied;
}
}
private bool OnFilterApplied(object obj)
{
if (obj is Datas)
{
//文本加空格 为确定搜索
var text = search.Text.ToLower();
if (text.Length > 0 && text.Substring(text.Length - 1, 1) == " ")
{
text = text.TrimEnd();
return (obj as Datas).Name.ToLower().Equals(text); //车号
}
else
{
return (obj as Datas).Name.ToLower().Contains(text);
}
}
return false;
}
private void Test_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
Point Pmouser = e.GetPosition((ItemsControl)sender);
if (Pmouser.Y <= 30)
{
new ColumnHelper(this.test, "test.xml").addCheckbox();
return;
}
}
private void Test_Loaded(object sender, RoutedEventArgs e)
{
}
}
}
UserModels.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp
{
public class UserModels:INotifyPropertyChanged
{
public ObservableCollection<Datas> datas { get; set; }
public Datas Selected
{
set { selected = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Selected")); }
get { return selected; }
}
private Datas selected;
public UserModels()
{
datas = new ObservableCollection<Datas>()
{
new Datas{ID=1,Age=80,Name="dalian"},
new Datas{ID=2,Age=81,Name="dalian1"},
new Datas{ID=3,Age=82,Name="dalian2"},
new Datas{ID=4,Age=83,Name="dalian3"},
new Datas{ID=5,Age=84,Name="dalian4"},
};
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class Datas
{
public int ID { get; set; }
public int Age { get; set; }
public string Name { get; set; }
public override string ToString()
{
return this.Name;
}
}
}
ValueCon.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media.Imaging;
namespace WpfApp
{
public class Visible : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Datas dd = value as Datas;
if (dd is null)
{
return Visibility.Collapsed;
}
else
{
if (dd.Age >= 82)
{
return Visibility.Visible; ;
}
else
{
return Visibility.Collapsed;
}
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class Images : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Datas dd = value as Datas;
if (dd is null)
{
return null;
}
else
{
if (dd.Age >= 82)
{
string image = "ICON\\icon.png";
return new BitmapImage(new Uri($"pack://application:,,,/{image}"));
}
else
{
string image = "ICON\\icon.png";
return new BitmapImage(new Uri($"pack://application:,,,/{image}"));
}
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
mainwindow.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.tests.DataContext = new UserModels();
}
}
}