【发布时间】:2011-06-07 13:24:48
【问题描述】:
我的DataGrid 有一组默认显示的列,但我还想让用户选择/取消选择在他们的应用程序上显示的列。在 WPF 中是否有相对简单的方法来做到这一点?
DataGrid 绑定到 DataTable。
注意:如果上述功能过于复杂,我可以通过RadioButton 解决方案使用简单的“默认列/所有列”。
【问题讨论】:
标签: c# wpf wpf-controls wpfdatagrid
我的DataGrid 有一组默认显示的列,但我还想让用户选择/取消选择在他们的应用程序上显示的列。在 WPF 中是否有相对简单的方法来做到这一点?
DataGrid 绑定到 DataTable。
注意:如果上述功能过于复杂,我可以通过RadioButton 解决方案使用简单的“默认列/所有列”。
【问题讨论】:
标签: c# wpf wpf-controls wpfdatagrid
简短的回答是,将每列的 Visibility 属性绑定到您可以设置的布尔标志(通过 CheckBox 或其他机制),并使用 BooleanToVisibilityConverter 使列可见 当标志未设置时折叠。
挖掘这个similar question,尤其是this answer!他的博客文章列出了我理想的解决方案。 :)
【讨论】:
将DataGrid.Columns 与DataTemplate 绑定到ItemsControl,其中包含CheckBox 用于可见性切换,除了VisbilityToBoolConverter 之外不需要任何代码:
<Window
...
DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}" Loaded="Window_Loaded">
<Window.Resources>
<local:VisibilityToBoolConverter x:Key="VisibilityToBoolConv"/>
</Window.Resources>
<StackPanel Orientation="Vertical">
<DataGrid ItemsSource="{Binding Data}" Name="DGrid"/>
<ItemsControl ItemsSource="{Binding ElementName=DGrid, Path=Columns}" Grid.IsSharedSizeScope="True" Margin="5">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Header}" Margin="5"/>
<CheckBox Grid.Column="1" IsChecked="{Binding Visibility, Converter={StaticResource VisibilityToBoolConv}}" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Window>
注意:我有一个TextBlock,它假定 Column-Header 是一个字符串,如果不是这样,可能需要调整。
可见性转换器:
[ValueConversion(typeof(Visibility), typeof(bool))]
public class VisibilityToBoolConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility vis = (Visibility)value;
switch (vis)
{
case Visibility.Collapsed:
return false;
case Visibility.Hidden:
return false;
case Visibility.Visible:
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if ((bool)value) return Visibility.Visible;
else return Visibility.Collapsed;
}
#endregion
}
【讨论】:
我更喜欢扩展 DataGrid 类并添加此功能。
public class DataGridEx : DataGrid
{
public DataGridEx() : base()
{
// Create event for right click on headers
var style = new Style { TargetType = typeof(DataGridColumnHeader) };
var eventSetter = new EventSetter(MouseRightButtonDownEvent, new MouseButtonEventHandler(HeaderClick));
style.Setters.Add(eventSetter);
ColumnHeaderStyle = style;
}
private void HeaderClick(object sender, MouseButtonEventArgs e)
{
ContextMenu menu = new ContextMenu();
// Fill context menu with column names and checkboxes
var visibleColumns = this.Columns.Where(c => c.Visibility == Visibility.Visible).Count();
foreach (var column in this.Columns)
{
var menuItem = new MenuItem
{
Header = column.Header.ToString(),
IsChecked = column.Visibility == Visibility.Visible,
IsCheckable = true,
// Don't allow user to hide all columns
IsEnabled = visibleColumns > 1 || column.Visibility != Visibility.Visible
};
// Bind events
menuItem.Checked += (object a, RoutedEventArgs ea)
=> column.Visibility = Visibility.Visible;
menuItem.Unchecked += (object b, RoutedEventArgs eb)
=> column.Visibility = Visibility.Collapsed;
menu.Items.Add(menuItem);
}
// Open it
menu.IsOpen = true;
}
}
现在你可以使用这个控件代替原来的DataGrid:
<dg:DataGridEx ItemsSource="{Binding OfflineData, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False">
<dg:DataGridEx.Columns>
<DataGridTextColumn Binding="{Binding PortID}" Header="ID" Width="50" Visibility="Collapsed"/>
<DataGridTextColumn Binding="{Binding SwitchIP}" Header="Switch IP" Width="100" Visibility="Visible"/>
<DataGridTextColumn Binding="{Binding Port}" Header="Port" Width="50" Visibility="Visible"/>
</dg:DataGridEx.Columns>
</dg:DataGridEx>
现在用户可以右键单击列标题以打开带有复选框的菜单:
【讨论】: