This is a migrated thread and some comments may be shown as answers.

[Solved] Replacing the GridViewCellBase.ContentTemplate breaks cell editing

2 Answers 162 Views
GridView
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Aaron Jackson
Top achievements
Rank 1
Aaron Jackson asked on 22 Jun 2011, 10:30 PM
I have a RadGridView in Silverlight bound to a dynamic DataTable.    My goal is to have a single complex object per column in the table and have the rows of the table bound to the properties of the object.   I have built a DataTable where each cell for a given column will contain a refrence to the same object.  Then I used the RowLoaded event to apply a custom ContentTemplate to the cell that binds to the correct property based on the row.  I also found that the cell DataContext was the DynamicObject for the entire row, so I am also changing the DataContext of the cell to the object I want to bind to.  All of this works fine until I try to edit the cell.  The cell goes into edit mode, but the cell contents cannot be modified and then the cell never exists edit mode (see viewcells.jpg for before edit and editcells.jpg after edit). 

Here is the RowLoaded event that I am using to replace the Cell.ContentTemplate.  The templates are resources in the XAML.
private void RadGridView_RowLoaded(object sender, Telerik.Windows.Controls.GridView.RowLoadedEventArgs e)
{
    if (e.Row.DataContext is DynamicObject)
    {
        var cellObject = (e.Row.DataContext as DynamicObject);
        var rowName = cellObject.GetVal<String>("Description").AlphaOnly();
 
        if (cellObject != null)
        {
            foreach (var cell in e.Row.Cells)
            {
                var column = (cell.Column as GridViewDataColumn);
                if (column != null && column.DataType == typeof(SelfSelectedYear))
                {
                    cell.DataContext = cellObject.GetVal<SelfSelectedYear>(column.UniqueName);
                    cell.ContentTemplate = this.Resources[rowName + "CellTemplate"] as DataTemplate;
                }
            }
        }
    }
}

2 Answers, 1 is accepted

Sort by
0
Accepted
Vlad
Telerik team
answered on 23 Jun 2011, 06:58 AM
Hi,

 Looking at your code most probably you want to use our CellTempalteSelector

All the best,
Vlad
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Aaron Jackson
Top achievements
Rank 1
answered on 24 Jun 2011, 02:51 PM
Using the CellTemplateSelector was just what I needed.

I ended up writing a DataTemplateSelector that will choose which template to use based on the value of one of the properties on a DynamicObject.  The template is selected by comparing the value of the ConditionalValuePropertyName to the Value on the ConditionalDataTemplate.  One of the complexities of a DynamicObject is that I don't know the name of the column at design time, so I also built a template builder that generates a dynamic template at run time.

Here is how the DynamicValueDataTemplateSelector is used in the XAML.

<controls:DynamicCellDataTemplateBuilder x:Key="SelfselectedYearCellDataTemplateBuilder" />
<controls:DynamicEditCellDataTemplateBuilder x:Key="SelfselectedYearEditCellDataTemplateBuilder" />
 
<controls:DynamicValueDataTemplateSelector x:Key="SelfSelectedYearCellTemplateSelector" ConditionalValuePropertyName="Description">
    <controls:DynamicValueDataTemplateSelector.ConditionalTemplates>
        <controls:ConditionalDataTemplate Value="Baseline" BindingPropertyName="Baseline" TemplateBuilder="{StaticResource SelfselectedYearCellDataTemplateBuilder}"/>
        <controls:ConditionalDataTemplate Value="Adjust Baseline" BindingPropertyName="BaselineAdjustment"  TemplateBuilder="{StaticResource SelfselectedYearCellDataTemplateBuilder}"/>
        <controls:ConditionalDataTemplate Value="Percentage Adjustment" BindingPropertyName="PercentageAdjustment" TemplateBuilder="{StaticResource SelfselectedYearCellDataTemplateBuilder}"/>
        <controls:ConditionalDataTemplate Value="One Time Expense" BindingPropertyName="OneTimeExpense" TemplateBuilder="{StaticResource SelfselectedYearCellDataTemplateBuilder}"/>
        <controls:ConditionalDataTemplate Value="Total" BindingPropertyName="Total" TemplateBuilder="{StaticResource SelfselectedYearCellDataTemplateBuilder}"/>
    </controls:DynamicValueDataTemplateSelector.ConditionalTemplates>
</controls:DynamicValueDataTemplateSelector>

I only wanted this selector used for specific columns, so I used the AutoGeneratingColumn event on the RadGridView to set the selector for the columns that needed it.

private void RadGridView_AutoGeneratingColumn(object sender, Telerik.Windows.Controls.GridViewAutoGeneratingColumnEventArgs e)
{
    var column = e.Column as GridViewDataColumn;
 
    if (column.DataType == typeof(SelfSelectedYear))
    {
        column.CellTemplateSelector = this.Resources["SelfSelectedYearCellTemplateSelector"] as DataTemplateSelector;
        column.CellEditTemplateSelector = this.Resources["SelfSelectedYearEditCellTemplateSelector"] as DataTemplateSelector;
    }
}


Here is the code for the DynamicValueDataTemplateSelector and the DataTemplate builder.
public class DynamicValueDataTemplateSelector : DataTemplateSelector
    {
        public DynamicValueDataTemplateSelector()
        {
            ConditionalTemplates = new List<ConditionalDataTemplate>();
        }
 
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if (item is DynamicObject && container is GridViewCell)
            {
                var conditionalValue = GetConditionalValue(ConditionalValuePropertyName, item as DynamicObject);
                var conditionalTemplate = ConditionalTemplates.Where(t => t.Value == conditionalValue).SingleOrDefault();
                if (conditionalTemplate != null)
                {
                    var cell = container as GridViewCell;
                    var column = cell.Column as GridViewDataColumn;
                    if (column != null)
                    {
                        return conditionalTemplate.TemplateBuilder.CreateDateTemplate(column.UniqueName, conditionalTemplate.BindingPropertyName);
                    }
                }
            }
            return base.SelectTemplate(item, container);
        }
 
        /// <summary>
        /// Gets or sets the name of the conditional value. The conditional value property name is
        /// compared against the ConditionalDataTemplate.Value to determine which DataTemplate to use.
        /// </summary>
        /// <value>
        /// The name of the conditional property name value.  The property name must be for a property
        /// of type System.String.
        /// </value>
        public string ConditionalValuePropertyName { get; set; }
        public List<ConditionalDataTemplate> ConditionalTemplates { get; set; }
 
        private string GetConditionalValue(string propertyName, DynamicObject dynamicObj)
        {
            var conditionalValue = dynamicObj.GetVal<Object>(ConditionalValuePropertyName);
 
            if (!(conditionalValue is System.String))
                throw new ArgumentException("ConditionalValuePropertyName does not refer to a property of type System.String");
 
            return (conditionalValue as System.String);
        }
    }
 
    public class ConditionalDataTemplate
    {
        public string Value { get; set; }
        public IDynamicDataTemplateBuilder TemplateBuilder { get; set; }
        public string BindingPropertyName { get; set; }
    }
 
    public class DynamicCellDataTemplateBuilder : IDynamicDataTemplateBuilder
    {
        public DataTemplate CreateDateTemplate(string columnName, string propertyName)
        {
            StringBuilder t = new StringBuilder();
            t.Append("<DataTemplate xmlns=\"http://schemas.microsoft.com/client/2007\">");
            t.AppendFormat("<TextBlock Text=\"{{Binding {0}.{1},StringFormat=\\{{0:C0\\}}}}\" />", columnName, propertyName);
            t.Append("</DataTemplate>");
            return (DataTemplate)XamlReader.Load(t.ToString());
        }
    }
 
    public interface IDynamicDataTemplateBuilder
    {
        DataTemplate CreateDateTemplate(string columnName, string propertyName);
    }

Tags
GridView
Asked by
Aaron Jackson
Top achievements
Rank 1
Answers by
Vlad
Telerik team
Aaron Jackson
Top achievements
Rank 1
Share this question
or