【问题标题】:Dynamic generate column mvvm动态生成列 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}" width="auto"/>
                </GridView>
            </ListView.View>
        </ListView>

【问题讨论】:

    标签: c# wpf mvvm binding


    【解决方案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]
    猜你喜欢
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 2018-01-19
    • 2021-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多