动态生成列 mvvm

Posted

技术标签:

【中文标题】动态生成列 mvvm【英文标题】:Dynamic generate column mvvm 【发布时间】:2012-07-01 17:58:56 【问题描述】:

我尝试制作一个动态生成列的 ListView。我使用 mvvm 模式。 我怎样才能实现这个? 在这一刻,我只有静态列。

<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" />
                </GridView>
            </ListView.View>
        </ListView>

【问题讨论】:

【参考方案1】:

您可以使用转换器动态创建带有适当列的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>

MainWindow.xaml.cs

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; 
    

ConfigToDynamicGridViewConverter.cs

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 gridView = new GridView();
                foreach (var column in config.Columns)
                
                    var binding = new Binding(column.DataField);
                    gridView.Columns.Add(new GridViewColumn Header = column.Header, DisplayMemberBinding = binding);
                
                return gridView;
            
            return Binding.DoNothing;
        

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        
            throw new NotSupportedException();
        
    

【讨论】:

如果我也可以的话,+100。太好了,我编写了一个示例来实现这一点(并且还添加了对动态添加的列的排序)并将其推送到 GitHub github.com/9swampy/DynamicPropertyPropertiesListGridViewExample 我的另一个理论+100。我不敢相信我花了这么长时间才找到如何做到这一点,而且它比其他实现要干净得多。 我知道这已经有好几年了,但是如何使用这种方法将上下文菜单添加到视图或每列的上下文菜单?【参考方案2】:

感谢 Sergei,提供了一个了不起的答案。

我以稍微不同的形式使用它,因为我需要添加非文本数据类型的列。

因此,对 Sergei 答案的以下修改允许您在数据值上使用 ContentControl 包装器。然后将根据为每个单元格中的值定义的 DataTemplates 呈现它们。

如果使用 ContentControlDataField 而不是 TextDataField(最初是 DataField),则该列将被换行:

    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; 

【讨论】:

您的代码似乎是我需要的,因为我需要一个复选框列,但我真的不明白要在 Column.ContentControlDataField 中放入什么才能完成我需要的操作,您能帮帮我吗? 感谢您的代码 - 我尝试使用它。您是否知道为什么在运行时更改 ColumnConfig 不会刷新视图?我将 Columns 更改为 ObservableCollection [编辑:认为它现在可以工作,我的 ViewModel 上缺少一些 OnPropertyChanges]

以上是关于动态生成列 mvvm的主要内容,如果未能解决你的问题,请参考以下文章

WPF Datagrid 动态生成列 并绑定数据

WPF MvvM DataGrid 动态列

动态竖列生成button

easyUi动态生成datagrid列

将列动态添加到数据网格或使用列表中的特定列生成数据网格

elementUI的table动态生成列