2013-03-21 1 views
11

wpf (mvvm 패턴)로 제품을 개발 중입니다. 나는 좋은 결과를 얻지 못해 일주일 이상을 보냈다. 당신이 할 수있는 경우 Pls 날 도와 ... 사용자의 사용자 정의 (사용자가 열을 선택합니다)에 따라 시나리오가 있는데, 나는 데이터 집합에 데이터 집합을 표시해야합니다. 현재 메신저는 ObservableCollection을 DataGrid의 itemsource에 속성 집합으로 바인딩합니다. 이렇게하면 고정 된 열 크기로 제한됩니다. 주 : n 개의 열 이름은 사용자가 선택할 수 있도록 나열됩니다. "datagrid.columns.add()"를 사용하면 코드 뒤에 쉽게 코드를 작성할 수 있습니다. 어느 누구도이 시나리오에서 나를 도울 수 있습니까?mvvm 패턴의 wpf DataGrid에서 동적 열을 가져올 수 있습니까?

내 XAML :

<my:DataGrid AutoGenerateColumns="False" Margin="357,121.723,82,41" Name="dataGrid3" c:DataGridExtension.Columns="{Binding ColumnCollection}" /> 

이 내 명령 클래스

:

public static class DataGridExtension 
{ 
    public static ObservableCollection<DataGridColumn> GetColumns(DependencyObject obj) 
    { 
     return (ObservableCollection<DataGridColumn>)obj.GetValue(ColumnsProperty); 
    } 

    public static void SetColumns(DependencyObject obj, ObservableCollection<DataGridColumn> value) 
    { 
     obj.SetValue(ColumnsProperty, value); 
    } 

    public static readonly DependencyProperty ColumnsProperty = 
     DependencyProperty.RegisterAttached("Columns", typeof(ObservableCollection<DataGridColumn>),typeof(DataGridExtension), 
     new UIPropertyMetadata (new ObservableCollection<DataGridColumn>(), OnDataGridColumnsPropertyChanged)); 

    private static void OnDataGridColumnsPropertyChanged(DependencyObject d, 
      DependencyPropertyChangedEventArgs e) 
    { 
     if (d.GetType() == typeof(DataGrid)) 
     { 
      DataGrid myGrid = d as DataGrid; 

      ObservableCollection<DataGridColumn> Columns = (ObservableCollection<DataGridColumn>)e.NewValue; 

      if (Columns != null) 
      { 
       myGrid.Columns.Clear(); 

       if (Columns != null && Columns.Count > 0) 
       { 
        foreach (DataGridColumn dataGridColumn in Columns) 
        { 
         myGrid.Columns.Add(dataGridColumn); 
        } 
       } 


       Columns.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs args) 
       { 
        if (args.NewItems != null) 
        { 
         //foreach (DataGridColumn column in args.NewItems.Cast<DataGridColumn>()) 
         //{ 
         // myGrid.Columns.Add(column); 
         //} 
        } 

        if (args.OldItems != null) 
        { 

         //foreach (DataGridColumn column in args.OldItems.Cast<DataGridColumn>()) 
         //{ 
         // myGrid.Columns.Remove(column); 
         //} 
        } 
       }; 

      } 
     } 
    } 
} 

와 뷰 모델에서 내 재산 : 당신의 노력 남자의 대한

private ObservableCollection<DataGridColumn> _columnCollection = new ObservableCollection<DataGridColumn>(); 
public ObservableCollection<DataGridColumn> ColumnCollection 
{ 
    get 
    { 
     return this._columnCollection; 
    } 
    set 
    { 
     _columnCollection = value; 
     base.OnPropertyChanged("ColumnCollection"); 
     //Error 
     //base.OnPropertyChanged<ObservableCollection<DataGridColumn>>(() => this.ColumnCollection); 
    } 
} 
+4

mvvm은 코드 숨김을 사용하도록 제한하지 않습니다. – blindmeis

+0

Crude way - 모든 열을 미리 생성하고 사용자가 선택하지 않은 것을 숨 깁니다. –

+0

blindmeis, 내가 말했듯이, mvvm이 codebehind를 제한하지 않는다고 말하면, 나의 TL은 ... –

답변

8

감사가 ... 마침내 내가 발견 솔루션 ....

여기에 그 .. 내 명령 파일에서 (전체의 WPF MVVM)

: 내 뷰 모델에

<my:DataGrid AutoGenerateColumns="False" Margin="357,121.723,82,41" Name="dataGrid3" ItemsSource="{Binding Path=Datatable}" c:DataGridColumnsBehavior.BindableColumns="{Binding ColumnCollection}" /> 

그리고 마침내 :

private ObservableCollection<DataGridColumn> _columnCollection = new ObservableCollection<DataGridColumn>(); 
     public ObservableCollection<DataGridColumn> ColumnCollection 
     { 
      get 
      { 
       return this._columnCollection; 
      } 
      set 
      { 
       _columnCollection = value; 
       base.OnPropertyChanged("ColumnCollection"); 
       //Error 
       //base.OnPropertyChanged<ObservableCollection<DataGridColumn>>(() => this.ColumnCollection); 
      } 
     } 
     private DataTable _datatable = new DataTable(); 
     public DataTable Datatable 
     { 
      get 
      { 
       return _datatable; 
      } 
      set 
      { 
       if (_datatable != value) 
       { 
        _datatable = value; 
       } 
       base.OnPropertyChanged("Datatable"); 
      } 
     } 

내 XAML에서

public class DataGridColumnsBehavior 
    { 
     public static readonly DependencyProperty BindableColumnsProperty = 
      DependencyProperty.RegisterAttached("BindableColumns", 
               typeof(ObservableCollection<DataGridColumn>), 
               typeof(DataGridColumnsBehavior), 
               new UIPropertyMetadata(null, BindableColumnsPropertyChanged)); 
     private static void BindableColumnsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
     { 
      DataGrid dataGrid = source as DataGrid; 
      ObservableCollection<DataGridColumn> columns = e.NewValue as ObservableCollection<DataGridColumn>; 
      dataGrid.Columns.Clear(); 
      if (columns == null) 
      { 
       return; 
      } 
      foreach (DataGridColumn column in columns) 
      { 
       dataGrid.Columns.Add(column); 
      } 
      columns.CollectionChanged += (sender, e2) => 
      { 
       NotifyCollectionChangedEventArgs ne = e2 as NotifyCollectionChangedEventArgs; 
       if (ne.Action == NotifyCollectionChangedAction.Reset) 
       { 
        dataGrid.Columns.Clear(); 
        if (ne.NewItems != null) 
        { 
         foreach (DataGridColumn column in ne.NewItems) 
         { 
          dataGrid.Columns.Add(column); 
         } 
        } 
       } 
       else if (ne.Action == NotifyCollectionChangedAction.Add) 
       { 
        if (ne.NewItems != null) 
        { 
         foreach (DataGridColumn column in ne.NewItems) 
         { 
          dataGrid.Columns.Add(column); 
         } 
        } 
       } 
       else if (ne.Action == NotifyCollectionChangedAction.Move) 
       { 
        dataGrid.Columns.Move(ne.OldStartingIndex, ne.NewStartingIndex); 
       } 
       else if (ne.Action == NotifyCollectionChangedAction.Remove) 
       { 
        if (ne.OldItems != null) 
        { 
         foreach (DataGridColumn column in ne.OldItems) 
         { 
          dataGrid.Columns.Remove(column); 
         } 
        } 
       } 
       else if (ne.Action == NotifyCollectionChangedAction.Replace) 
       { 
        dataGrid.Columns[ne.NewStartingIndex] = ne.NewItems[0] as DataGridColumn; 
       } 
      }; 
     } 
     public static void SetBindableColumns(DependencyObject element, ObservableCollection<DataGridColumn> value) 
     { 
      element.SetValue(BindableColumnsProperty, value); 
     } 
     public static ObservableCollection<DataGridColumn> GetBindableColumns(DependencyObject element) 
     { 
      return (ObservableCollection<DataGridColumn>)element.GetValue(BindableColumnsProperty); 
     } 
    } 

내 생성자 :

public MainViewModel() 
     { 
Datatable.Columns.Add("Name",typeof(string)); 
      Datatable.Columns.Add("Color", typeof(string)); 
      Datatable.Columns.Add("Phone", typeof(string)); 
      Datatable.Rows.Add("Vinoth", "#00FF00", "456345654"); 
      Datatable.Rows.Add("lkjasdgl", "Blue", "45654"); 
      Datatable.Rows.Add("Vinoth", "#FF0000", "456456"); 
System.Windows.Data.Binding bindings = new System.Windows.Data.Binding("Name"); 
      System.Windows.Data.Binding bindings1 = new System.Windows.Data.Binding("Phone"); 
      System.Windows.Data.Binding bindings2 = new System.Windows.Data.Binding("Color"); 
      DataGridTextColumn s = new DataGridTextColumn(); 
      s.Header = "Name"; 
      s.Binding = bindings; 
      DataGridTextColumn s1 = new DataGridTextColumn(); 
      s1.Header = "Phone"; 
      s1.Binding = bindings1; 
      DataGridTextColumn s2 = new DataGridTextColumn(); 
      s2.Header = "Color"; 
      s2.Binding = bindings2; 

      FrameworkElementFactory textblock = new FrameworkElementFactory(typeof(TextBlock)); 
      textblock.Name = "text"; 
      System.Windows.Data.Binding prodID = new System.Windows.Data.Binding("Name"); 
      System.Windows.Data.Binding color = new System.Windows.Data.Binding("Color"); 
      textblock.SetBinding(TextBlock.TextProperty, prodID); 
      textblock.SetValue(TextBlock.TextWrappingProperty, TextWrapping.Wrap); 
      //textblock.SetValue(TextBlock.BackgroundProperty, color); 
      textblock.SetValue(TextBlock.NameProperty, "textblock"); 
      //FrameworkElementFactory border = new FrameworkElementFactory(typeof(Border)); 
      //border.SetValue(Border.NameProperty, "border"); 
      //border.AppendChild(textblock); 
      DataTrigger t = new DataTrigger(); 
      t.Binding = new System.Windows.Data.Binding { Path = new PropertyPath("Name"), Converter = new EnableConverter(), ConverterParameter ="Phone" }; 
      t.Value = 1; 
      t.Setters.Add(new Setter(TextBlock.BackgroundProperty, Brushes.LightGreen, textblock.Name)); 
      t.Setters.Add(new Setter(TextBlock.ToolTipProperty, bindings, textblock.Name)); 
      DataTrigger t1 = new DataTrigger(); 
      t1.Binding = new System.Windows.Data.Binding { Path = new PropertyPath("Name"), Converter = new EnableConverter(), ConverterParameter = "Phone" }; 
      t1.Value = 2; 
      t1.Setters.Add(new Setter(TextBlock.BackgroundProperty, Brushes.LightYellow, textblock.Name)); 
      t1.Setters.Add(new Setter(TextBlock.ToolTipProperty, bindings, textblock.Name)); 

      DataTemplate d = new DataTemplate(); 
      d.VisualTree = textblock; 
      d.Triggers.Add(t); 
      d.Triggers.Add(t1); 

      DataGridTemplateColumn s3 = new DataGridTemplateColumn(); 
      s3.Header = "Name 1"; 
      s3.CellTemplate = d; 
      s3.Width = 140; 

      ColumnCollection.Add(s); 
      ColumnCollection.Add(s1); 
      ColumnCollection.Add(s2); 
      ColumnCollection.Add(s3); 
    } 
+3

ViewModel의 System.Windows.Controls에서 "DataGridColumn"을 사용할 때이 순수 MVVM 접근 방식은 어떻습니까? –

3

이전 예제 (답변) 이벤트를 CollectionChanged 구독 및 구독 취소 기능으로 확장하고 싶습니다.

행동 (System.Windows.Interactivity에 대한 참조를 추가) :

public class ColumnsBindingBehaviour : Behavior<DataGrid> 
{ 
    public ObservableCollection<DataGridColumn> Columns 
    { 
     get { return (ObservableCollection<DataGridColumn>) base.GetValue(ColumnsProperty); } 
     set { base.SetValue(ColumnsProperty, value); } 
    } 

    public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register("Columns", 
     typeof(ObservableCollection<DataGridColumn>), typeof(ColumnsBindingBehaviour), 
      new PropertyMetadata(OnDataGridColumnsPropertyChanged)); 

    private static void OnDataGridColumnsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
    { 
     var context = source as ColumnsBindingBehaviour; 

     var oldItems = e.OldValue as ObservableCollection<DataGridColumn>; 

     if (oldItems != null) 
     { 
      foreach (var one in oldItems) 
       context._datagridColumns.Remove(one); 

      oldItems.CollectionChanged -= context.collectionChanged; 
     } 

     var newItems = e.NewValue as ObservableCollection<DataGridColumn>; 

     if (newItems != null) 
     { 
      foreach (var one in newItems) 
       context._datagridColumns.Add(one); 

      newItems.CollectionChanged += context.collectionChanged; 
     } 
    } 

    private ObservableCollection<DataGridColumn> _datagridColumns; 

    protected override void OnAttached() 
    { 
     base.OnAttached(); 

     this._datagridColumns = AssociatedObject.Columns; 
    } 


    private void collectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     switch (e.Action) 
     { 
      case NotifyCollectionChangedAction.Add: 
       if (e.NewItems != null) 
        foreach (DataGridColumn one in e.NewItems) 
         _datagridColumns.Add(one); 
       break; 

      case NotifyCollectionChangedAction.Remove: 
       if (e.OldItems != null) 
        foreach (DataGridColumn one in e.OldItems) 
         _datagridColumns.Remove(one); 
       break; 

      case NotifyCollectionChangedAction.Move: 
       _datagridColumns.Move(e.OldStartingIndex, e.NewStartingIndex); 
       break; 

      case NotifyCollectionChangedAction.Reset: 
       _datagridColumns.Clear(); 
       if (e.NewItems != null) 
        foreach (DataGridColumn one in e.NewItems) 
         _datagridColumns.Add(one); 
       break; 
     } 
    } 
} 

보기 :

<Window x:Class="WpfApplication1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

    xmlns:loc="clr-namespace:WpfApplication1" 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    Title="MainWindow" Height="350" Width="525"> 
<Grid> 
    <DataGrid x:Name="_dataGrid"> 
     <DataGrid.Columns> 
      <DataGridTextColumn Header="Test" /> 
     </DataGrid.Columns> 
     <i:Interaction.Behaviors> 
      <loc:ColumnsBindingBehaviour Columns="{Binding DataGridColumns}"/>   
     </i:Interaction.Behaviors> 
    </DataGrid> 
</Grid> 

뷰 모델 :

관련 문제