WPF动态改变GridViewColumn CellTemplate c#
WPF Dynamic change of GridViewColumn CellTemplate c#
我正在尝试学习有关 ListView 的一些知识,现在我正在解决这个问题:
我在后台代码中定义了一个列表视图。我想动态更改 gridviewcolumn celltemplate。例如通过使用复选框或按钮,或其他。有可能吗?
我的 ListView 的定义在这里:
lvUsers.ItemsSource = LoadListViewData();
GridView gridview = new GridView();
lvUsers.View = gridview;
DataTemplate templateCheck = new DataTemplate();
FrameworkElementFactory factoryContentControlCheck = new FrameworkElementFactory(typeof(VsCheckBox));
factoryContentControlCheck.SetValue(VsCheckBox.MarginProperty, new Thickness(0, 0, 0, 0));
DataTemplate templateBorder = new DataTemplate();
FrameworkElementFactory factoryContentControlBorder = new FrameworkElementFactory(typeof(Border));
factoryContentControlBorder.SetValue(Border.MarginProperty, new Thickness(0, 0, 10, 0));
factoryContentControlBorder.SetValue(Border.WidthProperty, Width = 10);
factoryContentControlBorder.SetValue(Border.HeightProperty, Height = 10);
factoryContentControlBorder.SetValue(Border.BackgroundProperty, Brushes.Red);
DataTemplate templateAge = new DataTemplate();
FrameworkElementFactory factoryContentControlAge = new FrameworkElementFactory(typeof(ContentControl));
factoryContentControlName.SetValue(ContentControl.MarginProperty, new Thickness(0, 0, 10, 0));
factoryContentControlAge.SetValue(ContentControl.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlAge.SetValue(ContentControl.HorizontalAlignmentProperty, HorizontalAlignment.Right);
factoryContentControlAge.SetBinding(ContentControl.ContentProperty, new Binding("Age"));
DataTemplate templateStack = new DataTemplate();
FrameworkElementFactory factoryContentControlStack = new FrameworkElementFactory(typeof(StackPanel));
factoryContentControlStack.SetValue(StackPanel.MarginProperty, new Thickness(10, 0, 0, 0));
factoryContentControlStack.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
factoryContentControlStack.SetValue(StackPanel.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlStack.AppendChild(factoryContentControlCheck);
factoryContentControlStack.AppendChild(factoryContentControlBorder);
templateStack.VisualTree = factoryContentControlStack;
DataTemplate templateStack1 = new DataTemplate();
FrameworkElementFactory factoryContentControlStack1 = new FrameworkElementFactory(typeof(StackPanel));
factoryContentControlStack1.SetValue(StackPanel.MarginProperty, new Thickness(10, 0, 0, 0));
factoryContentControlStack1.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
factoryContentControlStack1.SetValue(StackPanel.HorizontalAlignmentProperty, HorizontalAlignment.Right);
factoryContentControlStack1.SetValue(StackPanel.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlStack1.AppendChild(factoryContentControlAge);
templateStack1.VisualTree = factoryContentControlStack1;
GridViewColumn colStack = new GridViewColumn();
colStack.Header = "Stack";
colStack.CellTemplate = templateStack;
gridview.Columns.Add(colStack);
我想在运行时通过选中复选框或单击按钮将 colStack 的 CellTemplate 更改为 templateStack1。
感谢您的任何想法。
您可以使用 DataTrigger
动态更改列的 ContentTemplate
。这是一个使用 XAML:
的例子
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<CheckBox x:Name="TemplateChanger" Content="Change template"
IsChecked="{Binding IsChecked}"/>
<DataGrid x:Name="DataGrid" Grid.Row="1" AutoGenerateColumns="False"
ItemsSource="{Binding Items}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="My column" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Foo}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext.IsChecked, RelativeSource={RelativeSource AncestorType=DataGrid}}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="fsdfsdf"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
和代码隐藏文件:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using WpfApp.Annotations;
namespace WpfApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : INotifyPropertyChanged
{
private bool _isChecked;
public MainWindow()
{
InitializeComponent();
Items.Add(new Item {Foo = "Foo1"});
Items.Add(new Item {Foo = "Foo2"});
Items.Add(new Item {Foo = "Foo3"});
Items.Add(new Item {Foo = "Foo4"});
}
public bool IsChecked
{
get => _isChecked;
set
{
_isChecked = value;
OnPropertyChanged();
}
}
public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Item
{
public string Foo { get; set; }
}
}
结果是,每当您切换复选框的 IsChecked
属性 时,给定列的单元格内容模板也会发生变化。
编辑如何仅使用代码隐藏
为了完整起见,这里是如何仅使用代码隐藏实现此目的的方法:
var datagrid = new DataGrid {AutoGenerateColumns = false};
Grid.SetRow(datagrid,1);
RootGrid.Children.Add(datagrid);
var templateColumn = new DataGridTemplateColumn
{
Header = "My column",
IsReadOnly = true
};
var cellTemplate = new DataTemplate();
var factory = new FrameworkElementFactory(typeof(TextBlock));
factory.SetBinding(TextBlock.TextProperty, new Binding("Foo"));
var style = new Style(typeof(DataGridCell));
var trigger = new DataTrigger();
var triggerBinding = new Binding("DataContext.IsChecked")
{
RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGrid), 1)
};
trigger.Binding = triggerBinding;
trigger.Value = true;
var triggerSetter = new Setter {Property = ContentTemplateProperty};
var triggerTemplate = new DataTemplate();
var anotherFactory = new FrameworkElementFactory(typeof(TextBlock));
anotherFactory.SetValue(TextBlock.TextProperty,"lol");
triggerTemplate.VisualTree = anotherFactory;
triggerSetter.Value = triggerTemplate;
trigger.Setters.Add(triggerSetter);
style.Triggers.Add(trigger);
templateColumn.CellStyle = style;
cellTemplate.VisualTree = factory;
templateColumn.CellTemplate = cellTemplate;
datagrid.Columns.Add(templateColumn);
datagrid.ItemsSource = Items;
恕我直言,这种方式看起来有点乱,但决定权在您手中=)
我正在尝试学习有关 ListView 的一些知识,现在我正在解决这个问题:
我在后台代码中定义了一个列表视图。我想动态更改 gridviewcolumn celltemplate。例如通过使用复选框或按钮,或其他。有可能吗?
我的 ListView 的定义在这里:
lvUsers.ItemsSource = LoadListViewData();
GridView gridview = new GridView();
lvUsers.View = gridview;
DataTemplate templateCheck = new DataTemplate();
FrameworkElementFactory factoryContentControlCheck = new FrameworkElementFactory(typeof(VsCheckBox));
factoryContentControlCheck.SetValue(VsCheckBox.MarginProperty, new Thickness(0, 0, 0, 0));
DataTemplate templateBorder = new DataTemplate();
FrameworkElementFactory factoryContentControlBorder = new FrameworkElementFactory(typeof(Border));
factoryContentControlBorder.SetValue(Border.MarginProperty, new Thickness(0, 0, 10, 0));
factoryContentControlBorder.SetValue(Border.WidthProperty, Width = 10);
factoryContentControlBorder.SetValue(Border.HeightProperty, Height = 10);
factoryContentControlBorder.SetValue(Border.BackgroundProperty, Brushes.Red);
DataTemplate templateAge = new DataTemplate();
FrameworkElementFactory factoryContentControlAge = new FrameworkElementFactory(typeof(ContentControl));
factoryContentControlName.SetValue(ContentControl.MarginProperty, new Thickness(0, 0, 10, 0));
factoryContentControlAge.SetValue(ContentControl.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlAge.SetValue(ContentControl.HorizontalAlignmentProperty, HorizontalAlignment.Right);
factoryContentControlAge.SetBinding(ContentControl.ContentProperty, new Binding("Age"));
DataTemplate templateStack = new DataTemplate();
FrameworkElementFactory factoryContentControlStack = new FrameworkElementFactory(typeof(StackPanel));
factoryContentControlStack.SetValue(StackPanel.MarginProperty, new Thickness(10, 0, 0, 0));
factoryContentControlStack.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
factoryContentControlStack.SetValue(StackPanel.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlStack.AppendChild(factoryContentControlCheck);
factoryContentControlStack.AppendChild(factoryContentControlBorder);
templateStack.VisualTree = factoryContentControlStack;
DataTemplate templateStack1 = new DataTemplate();
FrameworkElementFactory factoryContentControlStack1 = new FrameworkElementFactory(typeof(StackPanel));
factoryContentControlStack1.SetValue(StackPanel.MarginProperty, new Thickness(10, 0, 0, 0));
factoryContentControlStack1.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
factoryContentControlStack1.SetValue(StackPanel.HorizontalAlignmentProperty, HorizontalAlignment.Right);
factoryContentControlStack1.SetValue(StackPanel.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlStack1.AppendChild(factoryContentControlAge);
templateStack1.VisualTree = factoryContentControlStack1;
GridViewColumn colStack = new GridViewColumn();
colStack.Header = "Stack";
colStack.CellTemplate = templateStack;
gridview.Columns.Add(colStack);
我想在运行时通过选中复选框或单击按钮将 colStack 的 CellTemplate 更改为 templateStack1。
感谢您的任何想法。
您可以使用 DataTrigger
动态更改列的 ContentTemplate
。这是一个使用 XAML:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<CheckBox x:Name="TemplateChanger" Content="Change template"
IsChecked="{Binding IsChecked}"/>
<DataGrid x:Name="DataGrid" Grid.Row="1" AutoGenerateColumns="False"
ItemsSource="{Binding Items}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="My column" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Foo}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext.IsChecked, RelativeSource={RelativeSource AncestorType=DataGrid}}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="fsdfsdf"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
和代码隐藏文件:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using WpfApp.Annotations;
namespace WpfApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : INotifyPropertyChanged
{
private bool _isChecked;
public MainWindow()
{
InitializeComponent();
Items.Add(new Item {Foo = "Foo1"});
Items.Add(new Item {Foo = "Foo2"});
Items.Add(new Item {Foo = "Foo3"});
Items.Add(new Item {Foo = "Foo4"});
}
public bool IsChecked
{
get => _isChecked;
set
{
_isChecked = value;
OnPropertyChanged();
}
}
public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Item
{
public string Foo { get; set; }
}
}
结果是,每当您切换复选框的 IsChecked
属性 时,给定列的单元格内容模板也会发生变化。
编辑如何仅使用代码隐藏
为了完整起见,这里是如何仅使用代码隐藏实现此目的的方法:
var datagrid = new DataGrid {AutoGenerateColumns = false};
Grid.SetRow(datagrid,1);
RootGrid.Children.Add(datagrid);
var templateColumn = new DataGridTemplateColumn
{
Header = "My column",
IsReadOnly = true
};
var cellTemplate = new DataTemplate();
var factory = new FrameworkElementFactory(typeof(TextBlock));
factory.SetBinding(TextBlock.TextProperty, new Binding("Foo"));
var style = new Style(typeof(DataGridCell));
var trigger = new DataTrigger();
var triggerBinding = new Binding("DataContext.IsChecked")
{
RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGrid), 1)
};
trigger.Binding = triggerBinding;
trigger.Value = true;
var triggerSetter = new Setter {Property = ContentTemplateProperty};
var triggerTemplate = new DataTemplate();
var anotherFactory = new FrameworkElementFactory(typeof(TextBlock));
anotherFactory.SetValue(TextBlock.TextProperty,"lol");
triggerTemplate.VisualTree = anotherFactory;
triggerSetter.Value = triggerTemplate;
trigger.Setters.Add(triggerSetter);
style.Triggers.Add(trigger);
templateColumn.CellStyle = style;
cellTemplate.VisualTree = factory;
templateColumn.CellTemplate = cellTemplate;
datagrid.Columns.Add(templateColumn);
datagrid.ItemsSource = Items;
恕我直言,这种方式看起来有点乱,但决定权在您手中=)