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

[Solved] Radbutton in a gridview cell with a dynamic cell template - how to bind ?

5 Answers 325 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.
scott
Top achievements
Rank 1
scott asked on 23 Aug 2010, 04:21 PM
Good morning and happy monday.  Here is a complete reproducer.  I have a grid with a random column name.  I create a run-time DataTemplate that I apply to the RadGrid cells.  The DataTemplate contains a RadButton.  How do I make this button call the cilck handler ?

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
  
using Telerik.Data;
using Telerik.Windows.Controls;
  
namespace DynamicDataTemplates
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            RadGridView gv = new RadGridView();
            gv.DataLoaded += new EventHandler<EventArgs>(gv_DataLoaded);
            gv.ItemsSource = GetData();
            LayoutRoot.Children.Add(gv);
        }
  
        private static void MoreButton_Click(object sender, ExecutedRoutedEventArgs args)
        {
            MessageBox.Show("Button got clicked");
        }
  
        // apply a dynamic data template to a dynamic column
        void gv_DataLoaded(object sender, EventArgs e)
        {
            RadGridView gv = sender as RadGridView;
            foreach (GridViewColumn col in gv.Columns)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("<DataTemplate ");
                sb.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
                sb.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
                sb.Append("xmlns:telerik='http://schemas.telerik.com/2008/xaml/presentation' ");
                sb.Append("xmlns:my='clr-namespace:DynamicDataTemplates;assembly=DynamicDataTemplates'>");
                sb.Append("<Grid> ");
                sb.Append("<Grid.Resources>");
                sb.Append("<my:StringConverter x:Key='aStringConverter'/>");
                sb.Append("</Grid.Resources> ");
                sb.Append("<StackPanel Orientation='Horizontal'> ");
                sb.Append("<TextBlock Text = '{Binding " + col.Header.ToString() + ", Converter={StaticResource aStringConverter}}' /> ");
                //
                //  *** QUESTION:  How do I bind this button to the MoreButton_Click handler ?
                //
                sb.Append("<telerik:RadButton Content='More...' /> ");
                sb.Append("</StackPanel> ");
                sb.Append("</Grid> ");
                sb.Append("</DataTemplate> ");
  
                string xaml = sb.ToString();
                DataTemplate template = XamlReader.Load(xaml) as DataTemplate;
                col.CellTemplate = template;
                col.Width = 250;
            }
        }
  
        // returns a data table - one column - column name is random and contains a really long string
        public DataTable GetData()
        {
            Random r = new Random((int)DateTime.Now.Second);
            List<string> colNames = new List<string>() 
                { "ColumnA", "ColumnB", "ColumnC", "ColumnD" };
            List<string> words = new List<string>() 
                { "apples ", "pears ", "oranges ", "bananas ", "grapefruit ", "grapes ", "mangos ", "tangerines " };
            DataTable dt = new DataTable();
  
            string colName = colNames[r.Next() % colNames.Count];
            dt.Columns.Add(new DataColumn() { ColumnName = colName, DataType = typeof(string) });
            for (int i = 0; i < 10; i++)
            {
                string s = "";
                for (int j = 0; j < 100; j++)
                    s += words[r.Next() % words.Count];
                DataRow dr = dt.NewRow();
                dr[colName] = s;
                dt.Rows.Add(dr);
            }
  
            return dt;
        }
    }
  
    // chop string for display in grid
    public class StringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((string)value).Substring(0, 30);
        }
  
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((string)value).ToLower();
        }
    }
      
}


XAML file is default:

<UserControl x:Class="DynamicDataTemplates.MainPage"
    xmlns:my='clr-namespace:DynamicDataTemplates'
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
      
    <Grid x:Name="LayoutRoot" Background="White">
          
   </Grid>
</UserControl>

5 Answers, 1 is accepted

Sort by
0
Milan
Telerik team
answered on 24 Aug 2010, 10:52 AM
Hi scott,

you can use the RowLoaded event to scan for all buttons when a particular row is loaded and subscribe to the Click event.

private void gridView_RowLoaded(object sender, RowLoadedEventArgs e)
{
    var row = e.Row as GridViewRow;
  
    if (row != null
    {
        // find all buttons of that row
        var buttons = row.ChildrenOfType<RadButton>();
  
        foreach (var button in buttons)
        {
            button.Click -= new RoutedEventHandler(button_Click);
            button.Click += new RoutedEventHandler(button_Click);
        }
    }
          
}

Still, I would not recommend using dynamic cell template because it would be very difficult to support. May I ask you what is the reason for having such template? There might be a better solution to your problem.

Greetings,
Milan
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
scott
Top achievements
Rank 1
answered on 24 Aug 2010, 04:56 PM
HI Milan.  I have a usercontrol based on a radgrid.  The data in the grid comes from dynamic queries built by the user.  Occasionally the users bring in fields that are very wide (eg, 4k+ worth of characters).  In those cases I want to truncate what gets seen in the grid and give them a button that allows them to view the wide data in a radwindow instead.

Because I have no way to know when this will happen, or what the name of the wide column will be until run-time, I'm using a dynamic template for the cell-with-a-button.

I was trying to bind the click handler from the template, but you can't use Click= in there.  You're supposed to use Command= but that seems like a lot of overhead.  I never thought about doing it in RowLoaded().  

I've included the complete code that does exactly what I want it to do -- if you can think of a better way to do it then please let me know.  Otherwise I think I'll post this as an example since it took me a week or more plus your help plus Yavor's help to make it work...

This is awesome - thank you.  What a great day in the neighborhood! 
Scott.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
  
using Telerik.Data;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.GridView;
  
namespace DynamicDataTemplates
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            RadGridView gv = new RadGridView();
            gv.DataLoaded += new EventHandler<EventArgs>(gv_DataLoaded);
            gv.RowLoaded += new EventHandler<Telerik.Windows.Controls.GridView.RowLoadedEventArgs>(gv_RowLoaded);
            gv.ItemsSource = GetData();
            LayoutRoot.Children.Add(gv);
        }
  
        void gv_RowLoaded(object sender, Telerik.Windows.Controls.GridView.RowLoadedEventArgs e)
        {
            var row = e.Row as GridViewRow;
            if (row != null)
            {
                var buttons = row.ChildrenOfType<RadButton>();
                foreach (var button in buttons)
                {
                    button.Click -= new RoutedEventHandler(MoreButton_Click);
                    button.Click += new RoutedEventHandler(MoreButton_Click);
                }
            }
        }
  
        private static void MoreButton_Click(object sender, RoutedEventArgs args)
        {
            RadButton b = sender as RadButton;
            string s = (string)b.Tag;
            MessageBox.Show("Button clicked: " + s);
        }
  
        // apply a dynamic data template to a dynamic column
        void gv_DataLoaded(object sender, EventArgs e)
        {
            RadGridView gv = sender as RadGridView;
            foreach (GridViewColumn col in gv.Columns)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("<DataTemplate ");
                sb.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
                sb.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
                sb.Append("xmlns:telerik='http://schemas.telerik.com/2008/xaml/presentation' ");
                sb.Append("xmlns:my='clr-namespace:DynamicDataTemplates;assembly=DynamicDataTemplates'>");
                sb.Append("<Grid> ");
                sb.Append("<Grid.Resources>");
                sb.Append("<my:StringConverter x:Key='aStringConverter'/>");
                sb.Append("</Grid.Resources> ");
                sb.Append("<StackPanel Orientation='Horizontal'> ");
                sb.Append("<TextBlock Text = '{Binding " + col.Header.ToString() + ", Converter={StaticResource aStringConverter}}' /> ");
                sb.Append("<telerik:RadButton Tag = '{Binding " + col.Header.ToString() + "}' Content='More...' Background='Wheat' CornerRadius='5' /> ");
                sb.Append("</StackPanel> ");
                sb.Append("</Grid> ");
                sb.Append("</DataTemplate> ");
  
                string xaml = sb.ToString();
                DataTemplate template = XamlReader.Load(xaml) as DataTemplate;
                col.CellTemplate = template;
                col.Width = 250;
            }
        }
  
        // returns a data table - one column - the column name is random and contains a really long string
        public DataTable GetData()
        {
            Random r = new Random((int)DateTime.Now.Second);
            List<string> colNames = new List<string>() 
                { "ColumnA", "ColumnB", "ColumnC", "ColumnD" };
            List<string> words = new List<string>() 
                { "apples ", "pears ", "oranges ", "bananas ", "grapefruit ", "grapes ", "mangos ", "tangerines " };
            DataTable dt = new DataTable();
  
            string colName = colNames[r.Next() % colNames.Count];
            dt.Columns.Add(new DataColumn() { ColumnName = colName, DataType = typeof(string) });
  
            for (int i = 0; i < 10; i++)
            {
                string s = "";
                for (int j = 0; j < 100; j++)
                    s += words[r.Next() % words.Count];
                DataRow dr = dt.NewRow();
                dr[colName] = s;
                dt.Rows.Add(dr);
            }
  
            return dt;
        }
    }
  
    // chop string for display in grid
    public class StringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((string)value).Substring(0, 30);
        }
  
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((string)value).ToLower();
        }
    }
      
}
0
Milan
Telerik team
answered on 25 Aug 2010, 01:56 PM
Hello scott,

You could possibly utilize our CellTemplateSelector to change the template of all cells that have large content. I have attached a sample application that demonstrates this approach. 

Might be useful.


Sincerely yours,
Milan
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
scott
Top achievements
Rank 1
answered on 26 Aug 2010, 04:26 PM
Hi Milan...

That implementation looks great, but how would you pass the long string to the button click handler ?

In my code I use

sb.Append("<
telerik:RadButton Tag = '{Binding " + col.Header.ToString() + "}' Content='More...' /> ");

which tags the button with the full text of the wide column so the click handler just gets the tag to access the data.  How would you do it with a template selector ?

Thanks -
Scott
0
Milan
Telerik team
answered on 27 Aug 2010, 02:11 PM
Hi scott,

The text will be set as DataContext so there is no problem to access it. I have updated the original application to demonstrates this.

Regards,
Milan
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
Tags
GridView
Asked by
scott
Top achievements
Rank 1
Answers by
Milan
Telerik team
scott
Top achievements
Rank 1
Share this question
or