使用WPF和Xaml,我已经定义了一个包含几列的数据网格。 其中一列我希望显示为CheckBoxColumn(在celss中的复选框)或TextColumn(仅在单元格中的文本),具体取决于我的应用程序的特定状态,可由用户随意切换。
假设我的初始列类型是TextColumn, 我相信我可以通过创建CheckBoxColumn类型的新实例,为其提供一些样式和设置器,然后保存对原始文本列的引用来实现此目的。然后,我会将dataGrid.Column [x]列重新分配给un-toggle事件中保存的引用。
我想知道是否有一种方法可以简单地从CheckBoxColumn开始,然后在" text"上以某种方式更改Column的样式。切换事件,以便将数据呈现为文本(" True"或" False"),即使它是CheckBoxColumn。这样我就没有创建新的Column实例并保存/恢复原始实例。
有什么想法吗?
编辑: 这是代码,演示了我对DataGrid Column类型的转换所要做的事情。我不想做的是保存旧列,然后在切换时换新。请参阅方法UpdateForTextMode。这里的最终目标是能够抓取原始文本中的整行并将它们作为新的整行或电子表格粘贴回网格中。如果没有某种方法可以动态切换视觉渲染而不必在后面的代码中交换整个列实例,我会感到惊讶。 我查看了列模板,但我不知道如何根据我的应用状态更改显示模板。我认为它们主要用于编辑/非编辑视图。在我的情况下,文本和非文本模式都应允许编辑,无论您是单击复选框还是键入单词" True"。
的App.xaml
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="{x:Type DataGridCell}" x:Key="DataGridCenterCellStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type DataGridColumnHeader}" x:Key="CustomDataGridCenterHeader">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold"/>
</Style>
<Style x:Key="ColumnHeaderGripperStyle" TargetType="{x:Type Thumb}">
<Setter Property="Width" Value="8" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Cursor"
Value="SizeWE" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Style and template for the DataGridColumnHeader.-->
<Style TargetType="{x:Type DataGridColumnHeader}" x:Key="DataGridColumnHeader">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Border x:Name="columnHeaderBorder" BorderThickness="1" Padding="3,0,3,0">
<Border.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="{DynamicResource BorderLightColor}" Offset="0" />
<GradientStop Color="{DynamicResource BorderDarkColor}" Offset="1" />
</LinearGradientBrush>
</Border.BorderBrush>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="{DynamicResource ControlLightColor}" Offset="0" />
<GradientStop Color="{DynamicResource ControlMediumColor}" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource ColumnHeaderGripperStyle}" />
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource ColumnHeaderGripperStyle}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="{DynamicResource ControlLightColor}"
Offset="0" />
<GradientStop Color="{DynamicResource ControlMediumColor}"
Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
App.xaml.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private static App instance = null;
public static App GetInstance()
{
return instance;
}
public App()
{
instance = this;
}
}
}
DataViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
namespace WpfApplication1
{
public class Data
{
string name = null;
public string Name
{
get { return name; }
set { name = value; }
}
bool reserved = false;
public bool Reserved
{
get { return reserved; }
set { reserved = value; }
}
public Data(string name, bool isReserved)
{
this.name = name;
reserved = isReserved;
}
}
public class DataViewModel
{
private List<Data> datas = null;
private ObservableCollection<DataViewModel> rows = null;
public Data Data { get; set; }
public DataViewModel(List<Data> datas, ObservableCollection<DataViewModel> rows, Data data)
{
this.datas = datas;
this.rows = rows;
Data = data;
}
public DataViewModel(List<Data> datas, ObservableCollection<DataViewModel> rows)
{
this.datas = datas;
this.rows = rows;
Data = null;
}
public void ConvertLastRow()
{
if (Data == null)
{
Data = new Data("", false);
datas.Add(Data);
rows.Add(new DataViewModel(datas, rows));
}
}
public int ID
{
get { return rows.IndexOf(this); }
}
public string Name
{
get
{
if (Data == null)
return string.Empty;
return Data.Name;
}
set
{
ConvertLastRow();
Data.Name = value;
}
}
public bool Reserved
{
get
{
if (Data == null)
return false;
return Data.Reserved;
}
set
{
ConvertLastRow();
Data.Reserved = value;
}
}
}
}
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="130"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="90"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="1" Content="Enable Text Mode" />
<CheckBox Grid.Column="1" Grid.Row="1" x:Name="textModeCheckBox" Checked="ToggleTextMode" Unchecked="ToggleTextMode"/>
<DataGrid Grid.Column="1" Grid.Row="2" x:Name="fooGrid" ItemsSource="{Binding Rows}" AutoGenerateColumns="False" CanUserResizeRows="False" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<DataGrid.Columns >
<DataGridTextColumn x:Name ="indexColumn" Binding="{Binding Path=ID}" Width="*" Header="Index" IsReadOnly="True"/>
<DataGridTextColumn x:Name ="nameColumn" Binding="{Binding Path=Name}" Width="*" Header="Name"/>
<DataGridTextColumn x:Name="reservedColumn" Binding="{Binding Path=Reserved}" Width="*" Header="Reserved"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MainWindow.xaml.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 System.Collections.ObjectModel;
using System.Windows.Controls.Primitives;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private List<Data> datas = null;
private ObservableCollection<DataViewModel> rows = new ObservableCollection<DataViewModel>();
private bool textMode = false;
private DataGridColumn savedReservedColumn = null;
public bool TextMode
{
get { return textMode; }
set { textMode = value; }
}
public ObservableCollection<DataViewModel> Rows
{
get { return rows; }
set { rows = value; }
}
public MainWindow()
{
InitializeComponent();
this.datas = new List<Data>();
datas.Add(new Data("foo1", false));
datas.Add(new Data("foo2", true));
this.DataContext = this;
savedReservedColumn = reservedColumn;
UpdateRows();
UpdateForTextMode();
}
public static void UpdateRows(ContentControl userControl)
{
(userControl as MainWindow).UpdateRows();
}
private void UpdateRows(List<Data> datas)
{
rows.Clear();
this.datas = datas;
if (this.datas == null)
return;
foreach (Data data in datas)
{
rows.Add(new DataViewModel(datas, rows, data));
}
rows.Add(new DataViewModel(datas, rows));
}
private void UpdateRows()
{
UpdateRows(datas);
}
public void UpdateForTextMode()
{
// If not text mode
if (!textMode)
{
//Convert textColumn to a CheckBoxColumn
DataGridColumn t = InitCheckBoxCell(savedReservedColumn as DataGridTextColumn);
fooGrid.Columns[2] = t;
}
// If text mode
else if (fooGrid.Columns[2] != savedReservedColumn)
{
// Put Hashed from XAML
fooGrid.Columns[2] = savedReservedColumn as DataGridTextColumn;
}
}
public static DataGridColumn InitCheckBoxCell(DataGridTextColumn originalColumn)
{
// Create the Column
DataGridCheckBoxColumn templateColumn = new DataGridCheckBoxColumn();
// Create a header style and set it in the column
templateColumn.CellStyle = new Style(typeof(DataGridCell));
MouseButtonEventHandler handler = PreviewMouseLeftButtonDownDataGridCell;
SetStyleSetterEvent(templateColumn.CellStyle, ContentControl.PreviewMouseLeftButtonDownEvent, handler);
SetterBaseCollection defaultSetters = (App.GetInstance().Resources["DataGridCenterCellStyle"] as Style).Setters;
foreach (Setter setter in defaultSetters)
SetStyleSetterProperty(templateColumn.CellStyle, setter.Property, setter.Value);
// Create the header
templateColumn.Binding = originalColumn.Binding;
templateColumn.Header = originalColumn.Header;
templateColumn.Width = originalColumn.Width;
templateColumn.HeaderStyle = MergeStyles(App.GetInstance().Resources["DataGridColumnHeader"] as Style, templateColumn.HeaderStyle, typeof(DataGridColumnHeader));
templateColumn.HeaderStyle = MergeStyles(App.GetInstance().Resources["CustomDataGridCenterHeader"] as Style, templateColumn.HeaderStyle, typeof(DataGridColumnHeader));
return templateColumn;
}
public static void PreviewMouseLeftButtonDownDataGridCell(object sender, MouseButtonEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
{
if (!cell.IsFocused)
{
cell.Focus();
}
DataGrid dataGrid = FindParent<DataGrid>(cell);
if (dataGrid != null)
{
if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
{
if (!cell.IsSelected)
cell.IsSelected = true;
}
else
{
DataGridRow row = FindParent<DataGridRow>(cell);
if (row != null && !row.IsSelected)
{
row.IsSelected = true;
}
}
}
}
}
public static T FindParent<T>(UIElement element) where T : UIElement
{
UIElement parent = element;
while (parent != null)
{
T correctlyTyped = parent as T;
if (correctlyTyped != null)
{
return correctlyTyped;
}
parent = VisualTreeHelper.GetParent(parent) as UIElement;
}
return null;
}
public static Style MergeStyles(Style srcStyle, Style dstStyle, Type type)
{
// If no header style was created in the XAML
if (dstStyle == null)
// Create a header style and set it in the column
dstStyle = new Style(type);
SetterBaseCollection defaultSetters = srcStyle.Setters;
foreach (Setter setter in defaultSetters)
{
SetStyleSetterProperty(dstStyle, setter.Property, setter.Value);
}
return dstStyle;
}
public static void SetStyleSetterProperty(Style style, DependencyProperty property, object value)
{
// Iterate through all the configured header styles
bool found = false;
foreach (SetterBase setterBase in style.Setters)
{
if (setterBase is Setter)
{
Setter setter = (setterBase as Setter);
if (setter.Property.Name.Equals(property.Name))
{
setter.Value = value;
found = true;
}
}
}
if (!found)
style.Setters.Add(new Setter(property, value));
}
public static void SetStyleSetterEvent(Style style, RoutedEvent routedEvent, MouseButtonEventHandler handler)
{
// Iterate through all the configured header styles
bool found = false;
foreach (SetterBase setterBase in style.Setters)
{
if (setterBase is EventSetter)
{
EventSetter eventSetter = (setterBase as EventSetter);
if (eventSetter.Event.Equals(routedEvent))
{
eventSetter.Handler = handler;
}
}
}
if (!found)
style.Setters.Add(new EventSetter(routedEvent, (Delegate)handler));
}
private void ToggleTextMode(object sender, RoutedEventArgs e)
{
textMode = !textMode;
UpdateRows();
UpdateForTextMode();
}
}
}