2
votes

First of all, I am not that familiar with WPF and Databinding at all, but I searched the web for a solution and didn't come up with one.

I have custom Content control that should be displayed in a Datagrid-Cell. Since I have no source-code for the control, I can't modify it to work around my issues.

The Datagrid contains (at least) 2 columns, one is the rows name, the other should be the custom control. To get the work done, I created a custom CustomDataGridColumn for the custom control programmatically, while defining the first column and the base datagrid in XAML

XAML (unneccessary stuff removed):

       <sdk:DataGrid Grid.Row="1" Name="dg" CanUserReorderColumns="False"
                     CanUserSortColumns="False" AutoGenerateColumns="False"
                     FrozenColumnCount="1" VerticalScrollBarVisibility="Auto" 
           HorizontalScrollBarVisibility="Auto"   
           HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
           VirtualizingStackPanel.VirtualizationMode="Standard" >
           <sdk:DataGrid.Columns>
               <sdk:DataGridTemplateColumn Header="Model" IsReadOnly="True">
                   <sdk:DataGridTemplateColumn.CellTemplate>
                       <DataTemplate>
                           <TextBlock Text="{Binding Model}"
                       </DataTemplate>
                   </sdk:DataGridTemplateColumn.CellTemplate>
               </sdk:DataGridTemplateColumn>
           </sdk:DataGrid.Columns>
       </sdk:DataGrid>

CustomDataGridColumn:

public class CustomDataGridColumn : DataGridColumn
{
    int col { get; set; }
    public CustomDataGridColumn (int pCol, string header)
        : base()
    {
        col = pCol;
        IsReadOnly = true;
        Header = header;

    }

    protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
    {
        //since editing cells is prohibited we return the editing element right back
        return editingElement;
    }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        //since editing cells is prohibited we return the editing cell right back
        return cell;
    }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        TableRowObject element = dataItem as TableRowObject;
        if (element == null )
        {
            return cell;
        }

        return element.customControls[col];
    }
}

And the TableRowObject I use in a 'ObservableObjectCollection' as dg.itemSource:

public class TableRowObject
{
    public string Model { get; set; }
    public CustomComponent[] customComponents { get; set; }
}

That works pretty fine, unless you scroll through the datagrid: as soon as virtualization hits, the customControl in a row doesn't fit the model column (in fact, the last cell that was scrolled out of the viewport gets reused without modification). the GenerateElement method of the column is called, while debugging, but as it seems with the wrong element.

What I tried:

  • Disabling Virtualization with VirtualizationStackPanel.VirtualizationMode="Standard VirtualizingStackPanel.IsVirtualizing="False" in the XAML throws a XAML parse exception due to IsVirtualizing is readonly (?!)
  • Using a Scrollviewer around the Datagrid to disable virtualization, works fine, but I loose the frozencolumncount of the datagrid
  • I tried to use a binding for the custom column that should have displayed the same string as in the first column - still the virtualization problem, looked like the following snippet:

    Binding b = new Binding("Model"); binding source = element; TextBlock tb = new TextBlock(); tb.setBinding(TextBlock.textProperty, b);

After that, I assume that I make some mistakes with either my custom columns GenerateElement or at least the binding. In addition, if I'll have to go with bindings, I will need an empty container that the custom control could be bound to?

Would be glad to get any help either for disabling virtualization (without losing the frozen column) or advice on how to bind the custom control to the column.

Thanks in advance

1

1 Answers

0
votes

Seems like the Silverlight DataGrid does not offer the possibility to set another ItemsPanelTemplate (like the Listbox does).

But I wonder why you do the "custom cell handling" in your own Column implementation. You can add TemplateColumns to the DataGrid's Columns collection dynamically/programatically. So when you would write this xaml:

<Resources>
    <DataTemplate x:Key="CustomTemplate">
        <CustomContentControl Content="{Binding Path=FooDetails}"/>
    </DataTemplate>
</Resources>

<sdk:DataGrid.Columns>
    <sdk:DataGridTemplateColumn Header="Foo"
              IsReadOnly="True"
              CellTemplate="{StaticResource CustomTemplate}"/>
</sdk:DataGrid.Columns>

You can instead write your code-behind like this:

private void AddColumn()
{
    var colDef = new DataGridTemplateColumn(){Header = "Foo", IsReadOnly = True};
    colDef.CellTemplate = (DataTemplate) this.Resources["CustomTemplate"];
    myGrid.Columns.Add( colDef );
}