Converting a customized "DataGridBoundColumn" solution to syncfusion

I'm trying to figure out the equivalent of this custom column for SyncFusion datagrid column:

public class CustomBoundColumn : DataGridBoundColumn

{

public string TemplateName { get; set; }

protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)

{

var binding = new Binding(((Binding)Binding).Path.Path) { Source = dataItem };

var content = new ContentControl { ContentTemplate = (DataTemplate)cell.FindResource(TemplateName) };

content.SetBinding(ContentControl.ContentProperty, binding);

return content;

}

protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)

{

return GenerateElement(cell, dataItem);

}

}


Here's an example of how it's used:


        private void GatherTableColumns(ObservableCollection groupedCollection)

        {

            var objectA = groupedCollection.First()

                .Properties

                .Select((x, i) => new { x.Name, Index = i })

                .ToArray();

 

            foreach (var property in objectA)

            {

                var binding = new System.Windows.Data.Binding(string.Format("Properties[{0}]", property.Index));

 

                if (property.Name == "Name")

                {

                    DataGrid.Columns.Add(new CustomBoundColumn()

                    {

                        Header = property.Name,

                        Binding = binding,

                        TemplateName = "TemplateA"

                    });

                }

 

                else

                {

                    DataGrid.Columns.Add(new CustomBoundColumn()

                    {

                        Header = property.Name,

                        Binding = binding,

                        TemplateName = "TemplateB"

                    });

                }

            }

        }



7 Replies

SJ Sathiyathanam Jeyakumar Syncfusion Team August 7, 2018 12:40 PM UTC

Hi Read, 
 
Thank you for contacting Syncfusion support. 
 
We have analyzed your query. We suspect that you have tried to load the different controls in the column. In SfDataGrid we already have the GridTemplateColumn options, to load the different controls in display and editing. 
 
In the below sample we have bind the Indexer Properties to the GridTemplateColumn. 
<syncfusion:SfDataGrid x:Name="sfdatagrid" 
                                AutoGenerateColumns="False" 
                                ItemsSource="{Binding OrdersDetails}" 
                                AllowEditing="True" 
                                ShowRowHeader="True"> 
    <syncfusion:SfDataGrid.Columns> 
 
        <syncfusion:GridTextColumn HeaderText="Shippers.CompanyName" 
                                            MappingName="ShippersInfo[0].CompanyName" 
                                            UseBindingValue="True" /> 
        <syncfusion:GridTemplateColumn 
                             MappingName="ShippersInfo[0].ShipperID"      syncfusion:FocusManagerHelper.WantsKeyInput= "True" 
                              UseBindingValue="True"> 
            <syncfusion:GridTemplateColumn.CellTemplate> 
                <DataTemplate > 
                    <TextBlock Name="NameTextBlock" Text="{Binding ShippersInfo[0].ShipperID}" /> 
                </DataTemplate> 
            </syncfusion:GridTemplateColumn.CellTemplate> 
            <syncfusion:GridTemplateColumn.EditTemplate> 
                <DataTemplate > 
                    <TextBox Name="NameTextBlock" Text="{Binding ShippersInfo[0].ShipperID}"/> 
                </DataTemplate> 
            </syncfusion:GridTemplateColumn.EditTemplate> 
                 
 
        </syncfusion:GridTemplateColumn> 
                                                 
 
 
    </syncfusion:SfDataGrid.Columns> 
</syncfusion:SfDataGrid> 
 
 
 
You can download the sample from the below location. 
 
Please refer the below links to get details about GridTemplateColumn. 
 
 
If the above provided details are differed from your requirement, please share the exact requirement to us it will help us to provide the better solutions to you. 
 
 
Regards, 
Sathiyathanam 



RE Read August 8, 2018 06:04 PM UTC

I've attached a simplified sample of the issue.
It shows a collection of generic properties that are not created until runtime. In this scenario, I'm trying to map to the "GenericCellValue" property. Maybe it's a simple coding error, but when I map to the index & property as shown above it seems to bind to the entire object instead of the individual property.
Thanks so much for the help!

Attachment: SyncfusionWpf_ObsCol_d50eb284.zip


DY Deivaselvan Y Syncfusion Team August 9, 2018 08:50 AM UTC

Hi Read,

On analyzing further with your sample, we have found that you have specified the MappingName as Properties[0].GenericCellValue instead of DProperties[0].GenericCellValue. Also, in the XAML you have bind only the GenericCellValue as Path instead of what you have specified in the MappingName. This is the cause of irrelevant result.

We have highlighted the changes which we have done in the given sample and please find that from below. 
XAML: 
 
<Window.Resources> 
            <DataTemplate x:Key="NameTemplate"> 
                <TextBlock Name="DrawingNameTextBlock" Text="{Binding Path=CountryName}" Background="Blue"/> 
            </DataTemplate> 
 
        <DataTemplate x:Key="NameTemplate2"> 
            <StackPanel> 
                <TextBlock Name="DrawingNameTextBlock" Text="{Binding Path=DProperties[0].GenericCellValue}" Background="Blue"/> 
            </StackPanel> 
        </DataTemplate> 
        <DataTemplate x:Key="NameTemplate3"> 
            <StackPanel> 
                <TextBlock Name="DrawingNameTextBlock1" Text="{Binding Path=DProperties[1].GenericCellValue}" Background="Blue"/> 
            </StackPanel> 
        </DataTemplate> 
    </Window.Resources> 
 
C#: 
var binding = new System.Windows.Data.Binding(string.Format("DProperties[{0}]", country.Index)); 
                string columnPropertyIndexBinding = (string.Format("DProperties[{0}]", country.Index)); 
                string genericCellValue = (string.Format("DProperties[{0}].GenericCellValue", country.Index)); 
                int fIndex = country.Index; 
 
                if (country.GenericColumnHeader == "CountryName") 
                { 
 
                    var templateColumn = new GridTemplateColumn() 
                    { 
                        HeaderText = country.GenericColumnHeader, 
                        MappingName = columnPropertyIndexBinding, 
                        UseBindingValue = true 
                    }; 
                    templateColumn.CellTemplate = Resources["NameTemplate"] as DataTemplate; 
                    templateColumn.UseBindingValue = true; 
                    CountryDataGrid.Columns.Add(templateColumn); 
                } 
 
                else if(country.Index == 0) 
                { 
                    var templateColumn = new GridTemplateColumn() 
                    { 
                        HeaderText = country.GenericColumnHeader, 
                        MappingName = genericCellValue, 
                        UseBindingValue = true 
                    }; 
                    templateColumn.UseBindingValue = true; 
                    templateColumn.CellTemplate = Resources["NameTemplate2"] as DataTemplate; 
                    CountryDataGrid.Columns.Add(templateColumn); 
                } 
                else if(country.Index == 1) 
                { 
                    var templateColumn = new GridTemplateColumn() 
                    { 
                        HeaderText = country.GenericColumnHeader, 
                        MappingName = genericCellValue, 
                        UseBindingValue = true 
                    }; 
                    templateColumn.UseBindingValue = true; 
                    templateColumn.CellTemplate = Resources["NameTemplate3"] as DataTemplate; 
                    CountryDataGrid.Columns.Add(templateColumn); 
                } 

Please find the modified sample from the below link.

Sample link:
http://www.syncfusion.com/downloads/support/forum/139102/ze/SyncfusionWpf_ObsCol1109904637.zip

Please let us know if you have any other questions.

Regards,
Deivaselvan 



RE Read August 9, 2018 10:45 AM UTC

Thanks Deivaselvan,
The problem is that I will not know the number of columns or rows since they are created at runtime. So I need a generic datatemplate.
The way I solved this before syncfusion was by customizing a datatemplate in code... overriding the FrameworkElement (see CustomBoundColumn at the top of my post) so I don't have to identify them in XAML and the same datatemplate could be used for infinite number of columns.
I just cannot figure out how to do this by customizing the GridTemplateColumn to achieve the same type of generic template.


DY Deivaselvan Y Syncfusion Team August 9, 2018 05:40 PM UTC

Hi Read,

We have modified the given sample by creating the DataTemplate in code behind using FrameworkElementFactory and it is used as the CellTemplate of TemplateColumn. Please find the changes from below. 
private void BuildDataGridColumnTypesFromObsCollectionOfCountryData(ObservableCollection<CountryData> groupedCollection) 
{ 
    foreach (var country in groupedCollection.First() 
        .DProperties 
        .Select((x, i) => new { x.GenericColumnHeader, x.GenericCellValue, Index = i })  
        .ToArray())  
    { 
        var binding = new System.Windows.Data.Binding(string.Format("DProperties[{0}]", country.Index)); 
        string columnPropertyIndexBinding = (string.Format("DProperties[{0}]", country.Index)); 
        string genericCellValue = (string.Format("DProperties[{0}].GenericCellValue", country.Index)); 
        int fIndex = country.Index; 
 
        if (country.GenericColumnHeader == "CountryName") 
        { 
 
            var templateColumn = new GridTemplateColumn() 
            { 
                HeaderText = country.GenericColumnHeader, 
                MappingName = columnPropertyIndexBinding, 
                UseBindingValue = true 
            }; 
            templateColumn.CellTemplate = Resources["NameTemplate"] as DataTemplate; 
            templateColumn.UseBindingValue = true; 
            CountryDataGrid.Columns.Add(templateColumn); 
        } 
 
        else 
        { 
            var templateColumn = new GridTemplateColumn() 
            { 
                HeaderText = country.GenericColumnHeader, 
                MappingName = genericCellValue, 
                UseBindingValue = true 
            }; 
            templateColumn.UseBindingValue = true; 
            var factory = new FrameworkElementFactory(typeof(TextBlock)); 
            factory.SetBinding(TextBlock.TextProperty, new Binding(genericCellValue)); 
            factory.SetValue(TextBlock.BackgroundProperty, System.Windows.Media.Brushes.Blue); 
            templateColumn.CellTemplate = new DataTemplate { VisualTree = factory }; 
            CountryDataGrid.Columns.Add(templateColumn); 
        } 
    } 
 
} 
Please find the modified sample for the same from the below link and let us know if this helps you.

Sample link:
http://www.syncfusion.com/downloads/support/forum/139102/ze/SyncfusionWpf_ObsCol-2050564780.zip

Regards,
Deivaselvan 



RE Read August 12, 2018 03:23 PM UTC

This will work great. I was initially looking to create a customized class off a SF column base class (allowing me to reuse my original XAML datatemplates) but this helps a lot as a code behind solution which I've been able to accomplish the same things with.
Thanks again!!!


DY Deivaselvan Y Syncfusion Team August 13, 2018 10:34 AM UTC

Hi Read,

We are glad to know that the provided solution met your requirement. Please let us know if you need any other assistance.

Regards,
Deivaselvan  


Loader.
Up arrow icon