2016-03-14 46 views
1

我目前有一個DataGrid,它通過ItemSource綁定到DataTable。我希望能夠將一個CellTemplate(MyTemplate)應用於DataGrid中某個類型的所有列(MyType)。將CellTemplate分配給C#/ WPF中動態生成的DataGridTemplateColumn

由於DataTable具有動態數量的列,我不能禁用AutoGenerateColumns並手動在WPF定義DataGridTemplateColumns

這是我DataTable在WPF:

<DataGrid HeadersVisibility="Column" VerticalScrollBarVisibility="Visible" CanUserAddRows="False" 
IsSynchronizedWithCurrentItem="False" FontSize="12" BorderThickness="0,1,0,0" RenderTransformOrigin="0.5,0.5" 
ItemsSource="{Binding MyDataTable}" AutoGenerateColumns="True" AutoGeneratingColumn="GeneratingColumnEvent"/> 

DataTemplate我要分配在UserControl's資源字典的定義(和工作在一個明確使用時定義DataGridTemplateColumn)。

<UserControl.Resources> 
    <ResourceDictionary> 
    <ResourceDictionary.MergedDictionaries> 
     <SharedResourceDictionary Source="{Resources Directory}/MyTemplates.xaml"/> 
    </ResourceDictionary.MergedDictionaries> 
    <FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/> 
    </ResourceDictionary> 
</UserControl.Resources> 

AutoGenerateColumn事件的定義是這樣的:

private void GeneratingColumnEvent(object sender, DataGridAutoGeneratingColumnEventArgs e) 
     { 
      if (e.PropertyType == typeof (MyType)) 
      { 
       var newCol = new DataGridCandidateTemplateColumn 
       { 
        CellTemplate = (DataTemplate) FindResource("MyTemplate"), 
        ColumnName = e.PropertyName, 
       }; 
       e.Column = newCol; 
       e.Column.Header = e.PropertyName; 
      } 
     } 

有了這樣定義的自定義DataGridCandidateTemplateColumn類:

class DataGridCandidateTemplateColumn : DataGridTemplateColumn 
    { 
     public string ColumnName { get; set; } 

     protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) 
     { 
      // The DataGridTemplateColumn uses ContentPresenter with your DataTemplate. 
      ContentPresenter cp = (ContentPresenter)base.GenerateElement(cell, dataItem); 
      // Reset the Binding to the specific column. The default binding is to the DataRowView. 
      if (cp != null) 
       BindingOperations.SetBinding(cp, ContentPresenter.ContentProperty, new Binding(this.ColumnName)); 
      return cp; 
     } 
    } 

如果我不嘗試應用模板,該列使用toString表示MyType。如果我像上面那樣應用模板,則列的單元格中不顯示任何內容。我錯過了什麼?

+0

請縮小你的問題並添加一些清晰度:您是否禁用了AutoGenerateColumns?最好的問候, –

+0

@AlexBell對不起,我正在編輯代碼示例以包含相關部分,並沒有注意到問題在這個過程中混亂了。爲了更加清晰,我編輯了粗體字。 – Typer525

回答

0

回答我的問題。我很抱歉,因爲我的解決方案不適合每個人。

我必須使用動態列數的原因是因爲列數是3 + 5n,其中n是包含在我的數據表中的數據類別數。

我能夠在某種程度上使人們有可能利用的數據(下文)對我來說,禁用AutoGenerateColumns和定義列作爲另一個事件的一部分(使用循環來生成5n類別)。通過能夠定義每一列,我能夠分配我的模板而不依賴於DataGridAutoGeneratingColumnEventArgs來確定正確的模板。


代替我的數據網格結合到DataTable其中I預處理我的數據具有3 + 5n列,我代替與自定義類包裹數據的5n部分。我還將每行包裝在一個類中,並使數據網格使用這些類的列表作爲它的ItemSource

這使我可以創建列作爲數據網格初始化過程的一部分。當它來定義DataGrid的5n部分列,我用這樣的轉換器:

列定義:

private void GenerateColumnEvent(object sender, EventArgs e) 
{ 
    var table = sender as DataGrid; 
    var context = table.DataContext 

    //Regular column definitions 

    foreach(var category in context.CategoryIDList) 
    { 
     var binding = new Binding("CategoryWrapper") 
     { 
      Converter = new FindCategoryProperty(), 
       ConverterParameter = new Tuple<categoryID, string>(category, "Property1") 
     }; 
     var column = new DataGridTextColumn 
     { 
      Binding = binding, 
      //Other column defining things (templates, headers, etc) 
     }; 
     table.Columns.Add(column); 

     //More column definitions 
    } 
} 

轉換器定義:

class FindCategoryProperty: IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value != null && parameter != null) 
     { 
      var categoryList = (IList<CategoryClass>) value; 
      var categoryStringTuple = (Tuple<categoryID, string>) parameter; 
      var categoryID = categoryStringTuple.Item1; 
      var child = categoryList.FirstOrDefault(c => c.CategoryID == categoryID); 
      if (child != null) 
      { 
       switch (categoryStringTuple.Item2) 
        { 
         case "Property1": 
          return child.getProperty1(); 
         case "Property2": 
          return child.getProperty2(); 
         //etc 
         default: 
          return ""; 
        } 
      } 
     } 
     return ""; 
    } 

    //Left the ConvertBack unimplemented 
} 
0

這是有點不清楚你到底想通過使用該TemplateColumn實現。在情況下,它僅僅用於格式化,那麼你可以添加資源字典文件,並引用它在你的Windows XAML,像下面的例子:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:sys="clr-namespace:System;assembly=mscorlib"> 
.... 

     <Setter Property="Margin" Value="0,0,0,3" /> 
     <Setter Property="BorderThickness" Value="0" /> 
     <Setter Property="FontSize" Value="{StaticResource somevalue}" /> 
     <Setter Property="GridLinesVisibility" Value="All"/> 
     <Setter Property="HorizontalGridLinesBrush" Value="{StaticResource Somevalue}" /> 
     <Setter Property="VerticalGridLinesBrush" Value="{StaticResource SomeValue}" /> 
     <Setter Property="Background" Value="Transparent" /> 
     <Setter Property="Foreground" Value="Transparent" /> 
     <Setter Property="VerticalAlignment" Value="Stretch" /> 
     <Setter Property="VerticalContentAlignment" Value="Stretch" /> 
     <Setter Property="HorizontalAlignment" Value="Stretch" /> 
     <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 

    <Style TargetType="DataGridColumnHeader"> 
     <Setter Property="Background" Value="{StaticResource ColumnHeaderBackgroundColor}"/> 
     <Setter Property="Foreground" Value="{StaticResource ColumnHeaderForegroundColor}"/> 
     <Setter Property="BorderBrush" Value="{StaticResource ColorBorderColumnHeader}" /> 
     <Setter Property="BorderThickness" Value="1,0,0,0"/> 
     <Setter Property="Margin" Value="0,0,5,0"/> 
     <Setter Property="Padding" Value="6,6,10,6"/> 
     <Setter Property="Cursor" Value="Hand"/> 
    </Style> 

    <Style TargetType="DataGridRowHeader"> 
     <Setter Property="Visibility" Value="Collapsed"/> 
     <Setter Property="Width" Value="0"/> 
    </Style> 

    <Style TargetType="DataGridRow"> 
     <Setter Property="Foreground" Value="{StaticResource GridFontColor}" /> 
     <Setter Property="Background" Value="Transparent" /> 
     <Setter Property="VerticalAlignment" Value="Center"/> 
     <Style.Triggers> 
      <Trigger Property="DataGridRow.IsSelected" Value="True"> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 

    <Style TargetType="DataGridCell"> 
     <Setter Property="Padding" Value="4,4,2,4"/> 
     <Setter Property="Margin" Value="0"/> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type DataGridCell}"> 
        <Border Padding="{TemplateBinding Padding}" 
            BorderBrush="{TemplateBinding BorderBrush}" 
            BorderThickness="{TemplateBinding BorderThickness}" 
            Background="{TemplateBinding Background}" 
            SnapsToDevicePixels="True"> 
         <ContentPresenter SnapsToDevicePixels="True"/> 
        </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 

否則,使用GeneratingColumnEvent並設置Columns的個人屬性,如widthString格式等

private void GeneratingColumnEvent(object sender, DataGridAutoGeneratingColumnEventArgs e) 
{ 
    try 
    { 
     //Modify Columns names in Header, and apply proper String Format if needed 
     // Collapse the ID column 
     if (e.Column.Header.ToString() == "ID") 
     { e.Column.Visibility = Visibility.Collapsed; } 

     // Item 
     else if (e.Column.Header.ToString() == "Item") 
     { e.Column.Width = new DataGridLength(4.5, DataGridLengthUnitType.Star); } 

     // Price 
     if (e.Column.Header.ToString() == "Price") 
     { 
      e.Column.Header = "Px"; 
      (e.Column as DataGridTextColumn).Binding.StringFormat = "C2"; 
      e.Column.Width = new DataGridLength(1.7, DataGridLengthUnitType.Star); 
     } 
    } 
    catch { } 
}