2014-09-03 14 views
5

DataSource ile DataTable içeren DataGrid'im var. Sütun sayısı zaman zaman farklıdır. Bir sütunun DataType'ı A sınıfıysa Hücre içeriğinin görünümünü özelleştirmek için bir DataTemplate kullanmak istiyorum. DataTable tüm sütunlar oluşturulur, böyleceWPF DataGrid - DataTemplate DataTemplate içinde DataTable hücresine VeriTemplate

Ben DataGrid üzerinde

AutoGenerateColumns="True" 

belirledik. VeriTürü tipi DataTemplate şöyle görünür bir

private void DataGrid_AutoGeneratingColumn(object sender, system.Windows.Controls.DataGridAutoGeneratingColumnEventArgs e) 
{ 
    if (e.PropertyType == typeof(A)) 
    { 
     e.Column = new DataGridTemplateColumn 
     { 
      CellTemplate = (DataTemplate)Resources["ATemplate"], 
      Header = e.Column.Header, 
      HeaderTemplate = e.Column.HeaderTemplate, 
      HeaderStringFormat = e.Column.HeaderStringFormat 
     }; 
    } 
} 

arasında ise

Bir DataGridTemplateColumn ile DataGridColumn değiştirin.

<DataTemplate x:Key="ATemplate"> 
    <RadioButton Content="{Binding Name}" GroupName="{Binding GroupName}" IsChecked="{Binding IsSelected}" /> 
</DataTemplate> 

radiobuton gösterilir ama

BindingExpression path error: 'IsSelected' property not found on 'object' ''DataRowView' 

Sınıf A gibi, tüm özellikler için bağlama hataları almak i sağa DataTemplate databind nasıl bu

public class A 
{ 
    public string Name { get; set; } 
    public string GroupName { get; set; } 
    public bool IsSelected { get; set; } 
} 

benziyor hücre ve özellik?

hiçbir şans ile de bu çözüm denedi

düzenle (ben çok iyi olurdu DataGrid_AutoGeneratingColumn kullanmak gerekmez olduğu bir MVVM çözümü varsa). Sınıfa nasıl işleneceğini bilmediğinde, her zamanki gibi hücrede yalnızca sınıf adı gösterilir.

<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Items}"> 
    <DataGrid.Resources> 
     <DataTemplate DataType="{x:Type viewModel:A}"> 
     <RadioButton Content="{Binding Path=Name}" GroupName="{Binding Path=GroupName}" IsChecked="{Binding Path=IsSelected}" /> 
     </DataTemplate> 
    </DataGrid.Resources> 
</DataGrid> 
+0

Evet üzgünüm, kötü ... bu işe yaramaz. – Sheridan

cevap

8

Şablondaki bağlamalar, DataContext, DataTow DataTowView olduğundan çalışmaz.

Bir çözüm (tip A) istediğiniz nesneye DataContext'i ayarlamak için şablonu değiştirmek için, daha sonra tüm bağlamaları (Ad, GroupName, IsSelected) çalışacak olan. Bunu yapmak için dönüştürücü yapmanız ve şablonunuzu kullanmanız gerekir.

Şablondaki DataContext, dönüştürücüye aktarılan DataGridCell atalarına bağlıdır. Hücreden DataContext'i (DataRowView) alabiliriz ve hücrenin sütununu alabiliriz. Biz DataGrid_AutoGeneratingColumn sütunu yaptığınızda, e.PropertyName için sütunun SortMemberPath (datatable içinde sütunun adını) ayarlayın. Dönüştürücüde, DataRowView.Row içindeki nesneyi SortMemberPath dizinini kullanarak ararız. Bunu şablon için DataContext olarak döndürüyoruz. İşte

Ben birden çok örneği ile çalıştığını göstermek için veri tablosuna her sınıfın iki sütun eklenen bir sınıf A ve sınıf B ile uygulamasıdır.

enter image description here

MainWindow.xaml:

<Window x:Class="WpfApplication17.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:viewModel="clr-namespace:WpfApplication17" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <viewModel:DataRowViewConverter x:Key="drvc" /> 
     <DataTemplate x:Key="ATemplate"> 
      <RadioButton DataContext="{Binding RelativeSource={RelativeSource AncestorType=DataGridCell}, Converter={StaticResource drvc}}" Content="{Binding Path=Name}" GroupName="{Binding Path=GroupName}" IsChecked="{Binding Path=IsSelected}" /> 
     </DataTemplate> 
     <DataTemplate x:Key="BTemplate"> 
      <CheckBox DataContext="{Binding RelativeSource={RelativeSource AncestorType=DataGridCell}, Converter={StaticResource drvc}}" Content="{Binding Path=FullName}" IsChecked="{Binding Path=IsChecked}" /> 
     </DataTemplate> 
    </Window.Resources> 
    <Grid> 
     <DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Items}" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" CanUserAddRows="False"> 
     </DataGrid> 
    </Grid> 
</Window> 

MainWindow.xaml.cs:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace WpfApplication17 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public System.Data.DataTable Items { get; set; } 

     public MainWindow() 
     { 
      InitializeComponent(); 

      System.Data.DataTable dt = new System.Data.DataTable(); 
      dt.Columns.Add("StringColumn", typeof(string)); 
      dt.Columns.Add("IntColumn", typeof(int)); 
      dt.Columns.Add("AColumn1", typeof(A)); 
      dt.Columns.Add("AColumn2", typeof(A)); 
      dt.Columns.Add("BColumn1", typeof(B)); 
      dt.Columns.Add("BColumn2", typeof(B)); 

      dt.Rows.Add(
       "TestString", 
       123, 
       new A() { Name = "A1", GroupName = "GroupName", IsSelected = true }, 
       new A() { Name = "A2", GroupName = "GroupName", IsSelected = false }, 
       new B() { FullName = "B1", IsChecked=true }, 
       new B() { FullName = "B2", IsChecked=false } 
      ); 

      Items = dt; 
      this.DataContext = this; 
     } 

     private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) 
     { 
      DataTemplate dt = null; 
      if (e.PropertyType == typeof(A)) 
       dt = (DataTemplate)Resources["ATemplate"]; 
      else if (e.PropertyType == typeof(B)) 
       dt = (DataTemplate)Resources["BTemplate"]; 

      if (dt != null) 
      { 
       DataGridTemplateColumn c = new DataGridTemplateColumn() 
       { 
        CellTemplate = dt, 
        Header = e.Column.Header, 
        HeaderTemplate = e.Column.HeaderTemplate, 
        HeaderStringFormat = e.Column.HeaderStringFormat, 
        SortMemberPath = e.PropertyName // this is used to index into the DataRowView so it MUST be the property's name (for this implementation anyways) 
       }; 
       e.Column = c; 
      } 
     } 
    } 

    public class A 
    { 
     public string Name { get; set; } 
     public string GroupName { get; set; } 
     public bool IsSelected { get; set; } 
    } 

    public class B 
    { 
     public string FullName { get; set; } 
     public bool IsChecked { get; set; } 
    } 

    public class DataRowViewConverter : IValueConverter 
    { 
     #region IValueConverter Members 

     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      DataGridCell cell = value as DataGridCell; 
      if (cell == null) 
       return null; 

      System.Data.DataRowView drv = cell.DataContext as System.Data.DataRowView; 
      if (drv == null) 
       return null; 

      return drv.Row[cell.Column.SortMemberPath]; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      throw new NotImplementedException(); 
     } 

     #endregion 
    } 
} 
+2

Yazdığınız her şeyi denedim ama DataTemplate'de DataContext bağlaması. Çok teşekkürler soooo! – AxdorphCoder

+0

DataGridCell'e bağlamanın bellek sızıntılarına (statik PropertyChangedTracker nedeniyle) neden olacağını düşünüyorum. INotifyPropertyChanged kaynağına bağlanma bir sızıntıya neden olur. – ThumbGen

+0

C# dilinde programlı olarak DataTemplate oluşturma hakkında nasıl giderim? – mpsyp