We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

Custom template column bindings

Having the following class, I can't figure out how to get the binding to work...


    class RowLockButtonColumn : GridTemplateColumn
    {
        private ImageSwitch SwitchButton;

        public RowLockButtonColumn()
        {
            CellTemplate = new DataTemplate(CreateContent);
        }

        private object CreateContent()
        {
            SwitchButton = new ImageSwitch();
            string lockedImagePath = ImageResourceExtension.BuildPath(Constants.GeneralNamespace,
                                                                      Constants.RootImagesFolder,
                                                                      "LockedRow.png");
            string unlockedImagePath = ImageResourceExtension.BuildPath(Constants.GeneralNamespace,
                                                                      Constants.RootImagesFolder,
                                                                      "UnlockedRow.png");


            SwitchButton.Image = ImageSource.FromResource(lockedImagePath, typeof(ImageResourceExtension));
            SwitchButton.SelectedImage = ImageSource.FromResource(unlockedImagePath, typeof(ImageResourceExtension));
            SwitchButton.BindingContext = BindingContext;
            SwitchButton.SetBinding(ImageSwitch.SelectedProperty, new Binding(MappingName, BindingMode.TwoWay));

            return SwitchButton;
        }

                    DataGrid.Columns.Add(new RowLockButtonColumn( { MappingName = "Editable", HeaderText = "" } );



7 Replies

LR Le rond-point August 18, 2016 01:15 AM UTC

Well, I changed my strategy, being in a major rush

Added this to the Xaml :


    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="RowLockColumn">
                <views:ImageSwitch Image="{extensions:ImageResource LockedRow.png}"
                                   ToggledImage="{extensions:ImageResource LockedRow.png}"
                                   IsToggled="{Binding Editable}"/>
            </DataTemplate>
        </ResourceDictionary>
    </ContentPage.Resources>
   


And then using it in C# by referencing the resource :

                    DataGrid.Columns.Add(new GridTemplateColumn { MappingName = "Editable", HeaderText = "", CellTemplate = Resources["RowLockColumn"] as DataTemplate} );



LR Le rond-point August 18, 2016 01:21 AM UTC

With that said, I'm still interested in the answer because I think I need to do some custom grid columns for editable vs. fixed columns.

Basically, the rows are lockable so there are possible mistakes/editing on those rows.


DS Divakar Subramaniam Syncfusion Team August 18, 2016 11:48 AM UTC

Hi Sylvain, 
 
Thank you for contacting Syncfusion Support. 
 
At present, we do not have support for custom grid columns. The columns in SfDataGrid are rendered based on their cell types which will not be available for your custom column which is why your first approach did not work. However, you can achieve your requirement by using the GridTemplateColumn like your second approach in which you have tried loading a custom view in the DataTemplate. 
 
For more details about performing editing using GridTemplateColumn, please refer the below KB link. 
 
 
Regards, 
Divakar. 



LR Le rond-point August 18, 2016 06:16 PM UTC

To complete my answer, for people needing more dynamic data templates, generated in code, you can do something along these lines :


        private View GetCellTemplateForCriteria(Criteria criteria)
        {
            StackLayout result = null;

            result = new StackLayout();
            Label valueLabel = new Label();
            View editControl;
            BindableProperty editValueProperty;

            valueLabel.SetBinding(Label.TextProperty,
                                  new Binding("Scores",
                                              BindingMode.OneWay,
                                              Application.Current.Resources["ScoresFacade"] as IValueConverter,
                                              criteria.ID));
            valueLabel.SetBinding(IsVisibleProperty,
                                  new Binding("Editable",
                                              BindingMode.OneWay,
                                              Application.Current.Resources["InvertBool"] as IValueConverter));

            switch (criteria.Type)
            {
                case CriteriaType.IntRange:
                {
                    editControl = new SegmentControl();
                    editValueProperty = SegmentControl.SelectedSegmentProperty;
                    break;
                }
                case CriteriaType.Text:
                {
                    editControl = new Entry();
                    editValueProperty = Entry.TextProperty;
                    break;
                }
                case CriteriaType.Number:
                {
                    editControl = new SegmentControl();
                    editValueProperty = SegmentControl.SelectedSegmentProperty;
                    break;
                }
                case CriteriaType.Time:
                {
                    editControl = new TimePicker();
                    editValueProperty = TimePicker.TimeProperty;
                    break;
                }
                default:
                {
                    editControl = new Entry();
                    editValueProperty = Entry.TextProperty;
                    break;
                }
            }

            editControl.SetBinding(editValueProperty, new Binding("Scores");
            editControl.SetBinding(IsVisibleProperty, new Binding("Editable", BindingMode.OneWay));

            result.Children.Add(valueLabel);
            result.Children.Add(editControl);

            return result;
        }


LR Le rond-point August 18, 2016 07:50 PM UTC

Well the previous solution does work for OneWay but I just can't figure out how to get it to work both ways.  Editing data in the grid is seriously painful....

So I have these generated columns :

                    foreach (Criteria criteria in criterias)
                    {
                        GridTemplateColumn newColumn = new GridTemplateColumn();

                        newColumn.MappingName = "Scores";
                        newColumn.DisplayBinding = new Binding("Scores",
                                                               BindingMode.TwoWay,
                                                               GetCellTemplateCriteriaConverter(criteria),
                                                               criteria.ID);
                        newColumn.HeaderText = criteria.Name;
                        newColumn.HeaderTemplate = headerCell;
                        newColumn.CellTemplate = new DataTemplate(() => GetCellTemplateForCriteria(criteria));
                        newColumn.Width = GetColumnWidthForCriteria(criteria);

                        DataGrid.Columns.Add(newColumn);
                    }

The template for each criteria goes as follows :


        private StackLayout GetCellTemplateForCriteria(Criteria criteria)
        {
            StackLayout result = GetSimplePropertyCellTemplate(criteria.Type,
                                                               "placeholder",
                                                               (int)criteria.MinValue,
                                                               (int)criteria.MaxValue,
                                                               (int)criteria.DefaultValue);

            foreach (View child in result.Children)
            {
                BindableProperty editValueProperty;

                if (child is Label)
                {
                    editValueProperty = Label.TextProperty;
                }
                else
                {
                    switch (criteria.Type)
                    {
                        case CriteriaType.IntRange:
                        case CriteriaType.Number:
                        {
                            editValueProperty = IntRangeSegmentControl.ValueProperty;
                            break;
                        }
                        case CriteriaType.Text:
                        {
                            editValueProperty = Entry.TextProperty;
                            break;
                        }
                        case CriteriaType.Time:
                        {
                            editValueProperty = TimePicker.TimeProperty;
                            break;
                        }
                        default:
                        {
                            editValueProperty = Entry.TextProperty;
                            break;
                        }
                    }
                }

                child.SetBinding(editValueProperty,
                                 new Binding("Scores",
                                             BindingMode.TwoWay,
                                             GetCellTemplateCriteriaConverter(criteria),
                                             criteria.ID));
            }

            return result;
        }

        private StackLayout GetSimplePropertyCellTemplate(CriteriaType cellType, string mappingName, int minRange = 0, int maxRange = 10, int defaultValue = 0)
        {
            StackLayout result = null;

            result = new StackLayout();
            Label valueLabel = new Label();
            View editControl;
            BindableProperty editValueProperty;

            valueLabel.VerticalOptions = LayoutOptions.CenterAndExpand;
            valueLabel.HorizontalOptions = LayoutOptions.CenterAndExpand;
            valueLabel.SetBinding(Label.TextProperty, new Binding(mappingName, BindingMode.OneWay));
            valueLabel.SetBinding(IsVisibleProperty,
                                  new Binding("Editable",
                                              BindingMode.OneWay,
                                              Application.Current.Resources["InvertBool"] as IValueConverter));

            switch (cellType)
            {
                case CriteriaType.IntRange:
                case CriteriaType.Number:
                {
                    editControl = new IntRangeSegmentControl(minRange, maxRange, defaultValue);
                    editValueProperty = IntRangeSegmentControl.ValueProperty;
                    break;
                }
                case CriteriaType.Text:
                {
                    editControl = new Entry();
                    editValueProperty = Entry.TextProperty;
                    break;
                }
                case CriteriaType.Time:
                {
                    editControl = new TimePicker();
                    editValueProperty = TimePicker.TimeProperty;
                    break;
                }
                default:
                {
                    editControl = new Entry();
                    editValueProperty = Entry.TextProperty;
                    break;
                }
            }

            editControl.VerticalOptions = LayoutOptions.CenterAndExpand;
            editControl.HorizontalOptions = LayoutOptions.CenterAndExpand;
            editControl.SetBinding(editValueProperty, new Binding(mappingName, BindingMode.TwoWay));
            editControl.SetBinding(HeightRequestProperty, new Binding("Editable", BindingMode.OneWay, new HeightInvisibleValueConverter()));

            result.VerticalOptions = LayoutOptions.CenterAndExpand;
            result.HorizontalOptions = LayoutOptions.CenterAndExpand;
            result.Children.Add(valueLabel);
            result.Children.Add(editControl);
            result.Margin = ColumnsHorizontalPadding;

            return result;
        }

        private IValueConverter GetCellTemplateCriteriaConverter(Criteria criteria)
        {
            string converterId = "StringScoresFacade";

            switch (criteria.Type)
            {
                case CriteriaType.IntRange:
                case CriteriaType.Number:
                {
                    converterId = "IntScoresFacade";
                    break;
                }
            }

            return Application.Current.Resources[converterId] as IValueConverter;
        }

My converter doesn't get called when I set the value in a control within the template...  Why?


LR Le rond-point August 18, 2016 08:44 PM UTC

Argh, damn me... my setter was marked private!  Well I hope this serves as a sample!


DS Divakar Subramaniam Syncfusion Team August 19, 2016 10:11 AM UTC

Hi Sylvain, 
 
Thanks for the update. 
 
We are happy to hear that your problem is resolved.  As you said, the implemented Converter will get called only when you have BindingMode as TwoWay and also when your underlying property associated with the column has public get and set accessors.  
 
Please let us know if you need any other assistance. 
 
Regards, 
Divakar. 


Loader.
Up arrow icon