Вопрос по c#, wpf, mvvm, binding – Динамический генерировать столбец mvvm

13

Я пытаюсь сделать 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>

Ваш Ответ

2   ответа
0

Спасибо Сергей, за чудесный ответ.

Я использовал его в несколько иной форме, поскольку мне нужно было добавить столбцы с нетекстовыми типами данных.

Таким образом, следующая модификация ответа Сергея позволяет использовать обертки ContentControl для значений данных. Затем они будут отображаться в соответствии с шаблонами данных, определенными для значений в каждой ячейке.

Столбец будет перенесен, если используется 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; }
}
кажется, ваш код мне нужен, потому что мне нужен столбец checkbox, но я не совсем понимаю, что поместить в Column.ContentControlDataField, чтобы делать то, что мне нужно, можете ли вы мне помочь?
47

Вы можете создатьGridView с соответствующими столбцами динамически с помощью конвертера. Вот рабочий пример:

App screen shot

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 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();
        }
    }
}
Еще один теоретический +100 от меня. Я не могу поверить, что мне понадобилось так много времени, чтобы найти, как это сделать, и это намного чище, чем другие реализации.
Сумасшедший, вы заслуживаете +100 за этот ответ ...
+100, если бы я тоже мог. Настолько хорошо, что я создал пример, реализующий это (а также добавив сортировку динамически добавляемых столбцов) и перенес его в GitHub по адресуgithub.com/9swampy/DynamicPropertyPropertiesListGridViewExample

Похожие вопросы