C# 动态生成列mvvm
我尝试创建一个动态生成列的ListView。我使用mvvm模式。 我如何实现这一点? 在这里,我只有静态列C# 动态生成列mvvm,c#,wpf,mvvm,binding,C#,Wpf,Mvvm,Binding,我尝试创建一个动态生成列的ListView。我使用mvvm模式。 我如何实现这一点? 在这里,我只有静态列 <ListView ItemsSource="{Binding ProblemProducts}" Grid.Row="1" Grid.RowSpan="4" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="4"> <ListView
<ListView ItemsSource="{Binding ProblemProducts}"
Grid.Row="1" Grid.RowSpan="4" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="4">
<ListView.View>
<GridView>
<GridViewColumn Header="Spisujący" DisplayMemberBinding="{Binding _spisujacy}" Width="auto"/>
<GridViewColumn Header="Miejsce składowania" DisplayMemberBinding="{Binding MiejsceSkladowania}" Width="auto"/>
<GridViewColumn Header="Typ spisu" DisplayMemberBinding="{Binding _typSpisu}" Width="auto"/>
<GridViewColumn Header="Kod" DisplayMemberBinding="{Binding Kod}" width="auto"/>
</GridView>
</ListView.View>
</ListView>
您可以使用converter动态创建带有适当列的
GridView
。下面是一个工作示例:
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"
xmlns:WpfApplication1="clr-namespace:WpfApplication1"
mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="189" d:DesignWidth="312" Width="300" Height="300">
<Window.Resources>
<WpfApplication1:ConfigToDynamicGridViewConverter x:Key="ConfigToDynamicGridViewConverter" />
</Window.Resources>
<ListView ItemsSource="{Binding Products}" View="{Binding ColumnConfig, Converter={StaticResource ConfigToDynamicGridViewConverter}}"/>
</Window>
谢谢谢尔盖,给了我一个精彩的回答 我使用它的形式略有不同,因为我需要添加具有非文本数据类型的列 因此,下面对Sergei答案的修改允许您对数据值使用ContentControl包装。然后,将根据为每个单元格中的值定义的数据模板呈现它们 如果使用ContentControlDataField而不是TextDataField(最初为DataField),则将包装该列:
公共类ConfigToDynamicGridViewConverter:IValueConverter{
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性){
var config=列配置的值;
如果(配置!=null){
var grdiView=new GridView();
foreach(config.Columns中的var列){
bool cc=!string.IsNullOrEmpty(column.ContentControlDataField);
var binding=新绑定(cc?column.ContentControlDataField:column.TextDataField);
如果(cc){
var template=新数据模板();
var fact=newframeworkelementfactory(typeof(ContentControl));
事实.设置绑定(ContentControl.ContentProperty,绑定);
template.VisualTree=事实;
添加(新的GridViewColumn{Header=column.Header,CellTemplate=template});
}否则
添加(新的GridViewColumn{Header=column.Header,DisplayMemberBinding=binding});
}
返回grdiView;
}
不做任何事;
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性){
抛出新的NotSupportedException();
}
}
公共类ColumnConfig{
公共IEnumerable列{get;set;}
}
公共类专栏{
公共字符串头{get;set;}
公共字符串TextDataField{get;set;}
公共字符串ContentControlDataField{get;set;}
}
+100如果可以的话。很好,我已经制作了一个实现此功能的示例(还添加了动态添加列的排序),并将其以另一个理论+100的速度推送到GitHub。我真不敢相信我花了这么长时间才发现如何做到这一点,而且它比其他实现要干净得多。我知道已经好几年了,但我该如何使用这种方法将上下文菜单添加到视图中,或将上下文菜单添加到每个列中?您的代码似乎就是我所需要的,因为我需要一个checkboxcolumn,但是我真的不明白该在Column.ContentControlDataField中放什么才能做我需要的事情,你能帮我吗?谢谢你的代码-我尝试过使用它。您知道为什么在运行时对ColumnConfig所做的更改不会刷新视图吗?我将列更改为ObservableCollection[编辑:我认为它现在可以工作了,我的ViewModel上缺少了一些OnProperty更改]
using System.Collections.Generic;
using System.Windows;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
public class ViewModel
{
public ColumnConfig ColumnConfig { get; set; }
public IEnumerable<Product> Products { get; set; }
public ViewModel()
{
Products = new List<Product> { new Product { Name = "Some product", Attributes = "Very cool product" }, new Product { Name = "Other product", Attributes = "Not so cool one" } };
ColumnConfig = new ColumnConfig { Columns = new List<Column> { new Column { Header = "Name", DataField = "Name" }, new Column { Header = "Attributes", DataField = "Attributes" } } };
}
}
public class ColumnConfig
{
public IEnumerable<Column> Columns { get; set; }
}
public class Column
{
public string Header { get; set; }
public string DataField { get; set; }
}
public class Product
{
public string Name { get; set; }
public string Attributes { get; set; }
}
}
using System;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApplication1
{
public class ConfigToDynamicGridViewConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var config = value as ColumnConfig;
if (config != null)
{
var grdiView = new GridView();
foreach (var column in config.Columns)
{
var binding = new Binding(column.DataField);
grdiView.Columns.Add(new GridViewColumn {Header = column.Header, DisplayMemberBinding = binding});
}
return grdiView;
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
public class ConfigToDynamicGridViewConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
var config = value as ColumnConfig;
if (config != null) {
var grdiView = new GridView();
foreach (var column in config.Columns) {
bool cc = !string.IsNullOrEmpty(column.ContentControlDataField);
var binding = new Binding(cc ? column.ContentControlDataField : column.TextDataField);
if (cc) {
var template = new DataTemplate();
var fact = new FrameworkElementFactory(typeof(ContentControl));
fact.SetBinding(ContentControl.ContentProperty, binding);
template.VisualTree = fact;
grdiView.Columns.Add(new GridViewColumn {Header = column.Header, CellTemplate = template});
} else
grdiView.Columns.Add(new GridViewColumn {Header = column.Header, DisplayMemberBinding = binding});
}
return grdiView;
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotSupportedException();
}
}
public class ColumnConfig {
public IEnumerable<Column> Columns { get; set; }
}
public class Column {
public string Header { get; set; }
public string TextDataField { get; set; }
public string ContentControlDataField { get; set; }
}