2012-06-30 20 views
12

Intento hacer un ListView con generación dinámica de columna. Yo uso mvvm patern. ¿Cómo puedo implementar esto? En este momemt tengo solo columnas estáticas.Dynamic generate column 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> 

Respuesta

41

Puede crear GridView con las columnas adecuadas de forma dinámica mediante el convertidor. Ejemplo A continuación se trabaja:

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(); 
     } 
    } 
} 
+4

loco, te mereces 100 para esta respuesta ... – Thomas

+0

100 si yo también podría. Tan bueno que he inventado un ejemplo para implementar esto (y también agregué la ordenación de las columnas agregadas dinámicamente) y lo envié a GitHub en https://github.com/9swampy/DynamicPropertyPropertiesListGridViewExample – 9swampy

+0

Otro teórico +100 de mi parte. No puedo creer que me haya llevado tanto tiempo encontrar cómo hacerlo, y es mucho más limpio que otras implementaciones. – Grim

0

Gracias Sergei, por una respuesta maravillosa.

Lo usé en una forma ligeramente diferente, ya que necesitaba agregar columnas con tipos de datos que no sean de texto.

Así que la siguiente modificación a la respuesta de Sergei le permite tener envoltorios ContentControl en los valores de los datos. Luego se representarán de acuerdo con las plantillas de datos definidas para los valores en cada celda.

La columna se envolverá si ContentControlDataField se utiliza en lugar de TextDataField (originalmente 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; } 
}