Cannot Get CellTemplate to Bind to Converted Value

3 posts, 1 answers
  1. Nick
    Nick avatar
    4 posts
    Member since:
    Mar 2012

    Posted 09 Jul 2012 Link to this post

    I am currently using a RadGridView to bind to a List of Row objects. Let's call them PersonRows. Each PersonRow has on it a collection of Tasks, which can have various states. It is my intention that each column in the RadGridView corresponds to a single element in the collection of tasks on each person. The list of tasks cannot be known at compile time, and is loaded from a database, therefore I have to construct the columns and perform the bindings at runtime. I am using a ValueConverter in order to accomplish the binding. First I construct the column, like so:

    foreach (Task task in this.PersonStatusListingViewModel.ConfiguredTasks)
    {
      Telerik.Windows.Controls.GridViewDataColumn taskColumn = new Telerik.Windows.Controls.GridViewDataColumn();
      taskColumn.UniqueName = task.ID.ToString();
      Binding binding = new Binding();
      binding.ConverterParameter = taskColumn.UniqueName;
      TaskValueConverter conv = new TaskValueConverter();
      binding.Converter = conv;
      taskColumn.DataMemberBinding = binding;
      taskColumn.CellTemplate = (DataTemplate)this.Resources["TaskTemplate"];
      taskColumn.Header = task.Description;
      PersonGrid.Columns.Add(taskColumn);
    }

    The ValueConverter:

    public class TaskValueConverter : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
          int? currentIndex = null;
          PersonViewModel person = (PersonViewModel)value;
          ObservableCollection<TaskViewModel> TaskVMs = person.TaskViewModels;
          for (int i = 0; i < TaskVMs.Count; i++)
          {
            if (TaskVMs[System.Convert.ToInt32(i)].taskID.ToString() == parameter)
              currentIndex = i;
          }
     
          if (currentIndex != null)
          {
            return TaskVMs[System.Convert.ToInt32(currentIndex)];
          }
          else
            return null;
        }
     
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
          throw new NotImplementedException();
        }
      }

    By overriding .ToString() on the individual tasks, I can confirm that the columns are each binding to the proper item in the Task collection on each person. The column binding itself seems to be working properly, and is not the problem. The problem comes with the DataTemplate I am adding to the column. The DataTemplate is nothing more than a series of controls to manipulate the task objects (in progress, complete, and so on). However, I can see while debugging that the DataTemplate is using the DataContext of the GridView itself (PersonRow), and not the actual binding on each column (specific Task object). For instance, the DataTemplate binding for "TaskStarted" will attempt to bind to "PersonRow.TaskStarted", but it needs to bind to "Task.TaskStarted." How can I set up the DataTemplate to correctly bind to the Task of each person?
  2. Answer
    Pavel Pavlov
    Admin
    Pavel Pavlov avatar
    2039 posts

    Posted 12 Jul 2012 Link to this post

    Hi Nick ,

    DataMember binding is used when RadGridView creates its default display and edit elements e.g. textboxes.
    When you define your own data template.  RadGridView does not know which element in the data template is the one to bind .  This means that when you use your own data template you need to set the binding explicitly for the control inside . For example - if you have a textbox inside  instead of :

    <DataTemplate>
    <TextBox />
    </DataTemplate>

    you should do :

    <DataTemplate>
    <TextBox Text={Binding MyProperty} />
    </DataTemplate>

    I understand that in your case this is not directly possible as you create columns and binding dynamically based on a collection of your person row object.

    In this case you can create and set the template from code behind using XamlReader.Load . This way you can build a string containing a valid XAML with the proper binding path and create a DataTemplate from it.

    Let me know in case you have troubles with this approach or need additional assistance.

    Regards,
    Pavel Pavlov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  3. Nick
    Nick avatar
    4 posts
    Member since:
    Mar 2012

    Posted 12 Jul 2012 Link to this post

    Thank you, after much trial and error I actually ended up doing exactly this. It's still good to know that my solution isn't entirely crazy though. With luck the answer can still assist others.
Back to Top