How can I programmatically add a column with a Button in it (and a Click event on the button) to a grid? The following way does not work:
DataTemplate dt;
GridViewDataColumn gc;
dt = (DataTemplate)XamlReader.Load(
@"<DataTemplate
xmlns=""http://schemas.microsoft.com/client/2007"">
<Button Click=""Button_Click"" Content=""Click Here"" />
</DataTemplate>"
);
gc = new GridViewDataColumn();
gc.CellTemplate = dt;
rgvMainGrid.Columns.Add(gc); //Adding the column to the grid
Another question, how would I set button's content to an image in the same code?
Thank you!
10 Answers, 1 is accepted
Do you actually need to load the DataTemplate using XamlReader.Load method?
There are a couple of approaches you may use. Define your DataTemplate as a resource and reference it as a CellTemplate in a GridViewDataColumn created at code-behind. You may create your own custom column as it is described in the following online article. Considering the image in this button just define it as Content of the RadButton:
<telerik:RadButton> <Image Source="Image1.png" ..../> </telerik:RadButton>All the best,
Vanya Pavlova
the Telerik team
I don't have to create the button the way I've described. I've tried the method you are proposing and ran into a couple of problems through:
1. I'm trying to set the Image's Tag value to {Binding LanId} (which is unique for each record). How can I create a button using overridden class the article is describing and pass this LanId to it, so it would have the unique identifier associated with it?
2. I have a specific method I'm setting on the MouseLeftButtonUp event of the Image button. The method does the following:
- Get the value of the Tag property from the sender
- Create a RadHtmlPlaceholder and set its SourceUri to new Uri(string.Format("http://my.host.com/Folder/Page.aspx?id={0}", tag));. The page with the query string that is loaded into the Placeholder generates a vCard file based on the LanId. How can i still add an even handler tied to my page (it need to access a StackPanel located on the page) using the method described in the article?
[ The reason for this weirdness is this: I'm doing it this way because Silverlight won't generate and open a file due to permissions issue. Instead, I've created and deployed an .aspx page that takes a query parameter (LanId), and then generates the vCard file I need and sends it back and the system's default program (Outlook, for example), which opens the Save/Open dialog. I could, of course, just add an Image or a Button and use HtmlPage.Window.Navigate(myUrl) to navigate to the page, but if I do it like this, a new window pops up for 1/2 of a second, which is undesireable. I found a way to do it without the popup window. I'm using the RadHtmlPlaceholder to load that .aspx page (and the vCard pops up just fine, without the annoying popup). Once a user clicks my Image or Button, my event handler is executed, generates a RadHtmlPlaceholder with the Url set with the LanId (which is stored in the Image's or Button's Tag property) and places it into a StackPanel that is 1x1 pixels in size and therefore is pretty much invisible. As the result, I'm getting the behavior I'm looking for, but dooing it in a very ugly way. :) ]
Thank you!
-Vassili.
Thank you for the detailed information. I came to the conclusion that in your particular case you need to use the approach demonstrated in the previously referenced article through creating your custom column, below it is code-behind equivalent:
public class CustomButtonColumn:GridViewDataColumn { public override FrameworkElement CreateCellElement(GridViewCell cell, object dataItem) { var button = cell.Content as RadButton; if (button == null) { button = new RadButton(); button.Width = 100; button.Height = 100; button.ClickMode = ClickMode.Hover; Image img= new Image(); img.Width = 50; img.Height = 50; img.Cursor = Cursors.Hand; img.Stretch = Stretch.Fill; //Bind custom property of your custom object ot the
//Tag property of your Image img.SetBinding(Image.TagProperty, new Binding("Property1") { Source = dataItem });
//Bind custom property of your custom object ot the
//Source property of your Image img.SetBinding(Image.SourceProperty, new Binding("Property4") { Source = dataItem }); button.Content = img; img.MouseLeftButtonUp += new MouseButtonEventHandler(img_MouseLeftButtonUp); cell.Content = button; } return button; } private void img_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
try { Image business = (Image)sender; if (business != null) { int businessID = 0; if (business.Tag != null) { string busID = business.Tag.ToString(); MessageBox.Show(busID); } } } catch (Exception ex) { } } However you can see that the ClickMode property of RadButton is set to Hover, because only in this way the MouseLeftButtonUp event of the Image will be fired, you can read more about this here.
Also you may find attached the complete solution.
If you need any any further assistance please let me know.
All the best,
Vanya Pavlova
the Telerik team
Great example! I can see now how I can pass the binding parameter. I was wondering if I could bother you with one more thing. Is there a way to create an RadHtmlPlaceholder in the CustomButtonColumn class and have it displayed? Since the class does not really have access to my page, I'm not sure how to achieve the final step: open an .aspx page in a HtmlPlaceholder via the button click event.
Thank you!
Best Regards,
Vassili.
You may try to integrate RadHtmlPlaceHolder in RadWindow and within Image's MouseLeftButton event you may open this window. I would suggest you to refer to the samples below:
Integrating RadHtmlPlaceHolder and RadWindow
Use RadWindow as UserControl
Greetings,
Vanya Pavlova
the Telerik team
This still boils down to this question: how would I access anything created on the Page (where my grid is located) from a separate class (where my button column is being defined). Do you know how to do that?
Thank you!
-VK
Anything you add by code in a visual element, may be later accessed using the ChildrenOfType extension method. to be able to use it, you need to add a "using Telerik.Windows.Controls".
Then for example if you have added a button to a visual element , you may get a reference to it with a code like :
MyVusualElement.ChildrenOfType<Button>() - this will return a collection with all buttons in your element. When adding it you may give it a name , so later you can find it in the collection ( in case you have more than one buttons ) .
Hope that helps.
All the best,
Pavel Pavlov
the Telerik team
Thank you for your input. True, you can have access to cild elements. But how about the other way around? let's consider the following example:
I have a page that has a RadGridView. The page provides people directory of a company. There is a bunch of buttons that retrieve pre-defined sets of data from my database (for example, everybody by office, or department, or title, etc.). The data sets have different number of data columns in them (for example, one set may have Name, Email, Phone, and another have Name, Email, Phone, Title, Education columns). As a result, I have to programatically re-build the grid each time a new data set is pulled in based on the button that was pressed. I'm simplifying the thing, but, in essence, my project is very much like this example.
One of the columns that I've recently added is a vCard column (a vCard is a very simple file with .vcf extension that is formatted in a specific way and is usually, when generated by, say, a regular .aspx page, picked up by Outlook (you'll see the Open/Save/Cancel dialog)). The column contains little image buttons for each record. If done in .aspx page, the process is simple and straightforward: have the image buttons pass a parameter that is passed to the vCard generating class. In the class, a few lines of code generate a file and use the PopUpNewWindow method that uses HttpContext.Current.Response to generate and open the file (and that's when you see the Open/Save/Cancel dialog window if you have Outlook installed on your computer). Silverlight, however, has security measures that prevent one from opening a file in this manner.
A solution I came up with was to have an .aspx page that accepts a query string parameter to generate and open the vCard (.vcf) file. I have another page that has a RadGridView on it, but it is simpler and I never have to programmatically rebuild the grid, and hence I can add all columns in XAML. I've also added a RadHtmlPlaceholder control inside of 1 pixel x 1 pixel StackPanel. My vCard buttons' click event, basically, reloads RadHtmlPlaceholder with my vCard-generating .aspx page with unique (for the row a clicked button is on) parameter sent to the query string (for example, http://www.mysite.net/mVcardGeneratingPage.aspx?parameter=recordId). I could, of course, simply create a LinkButton, add an Image to it via DataTemplate (all doable in code), and have the link point to that same page and avoid all this madness with PlaceHolders, BUT the problem is that LinkButton opens a new window, which then pops up the file. As a result, a user in case of the LinkButton approach sees a new blank window poping up on his or her screen for about 1/2 second, after which the Open/Save/Cancel dialog appears. This blank page popup is undesireable and the way to get rid of it was to load the .aspx page not in a new window, but in a PlaceHolder. There is no blank new window popup in this scenario, which is just awesome. So, this approach works like a charm for my simpler page. The problem is, however, that I have no clue how to create an image button (or just a regular button) in code for my more complex page (the one where I have to rebuild the grid in code depending on the data set). That is the original reaon for this post.
The solution suggested by Vanya (the separate class for generating button colum) is great and does generate the column. I can even add the event handler for the buttons in that class... The problem is that I don't see how the event handler of the button defined in this separate class can have access to the HtmlPlaceholder I've been describing above and reload its content with an appropriate page+queryString combo. The solution you've provided above is good for retrieval of all button elements that exist in my RadGridView. However, it does not work the other way around. Also, the myButton.Parent only goes as far as the column, I think, and the column's (the coulmn that is generated in my MyImageButtonColumn : GridViewColumn class) Parent is null. So, the question remains: how can I access the HtmlPlaceholder? If that is not possible, is there a different way to add a button programmatically on the same page where the RadHemlPlaceholder is defined?
Thank you! I appreciate all your help!
-VK.
I have prepared an example for you that demonstrates how to access the RadHtmlPlaceHolder within img_MouseLeftButtonUp event of the Image element. If you need to access this control, you should host it in a control like PopUp, RadWindow or another custom UserControl that could be suitable in such cases. The SourceUrl property of the RadHtmlPlaceHolder is bound to a property of the custom object and the main idea behind this is to show you how you can pass some data to this control in an appropriate matter.
I believe that the updated project will be helpful for you, feel free to customize it in the way you need.
I will be waiting for your response.
Vanya Pavlova
the Telerik team
This sure did work! In the MouseLeftButtonUp event I'm generating a RadHtmlPlaceholder with its SourceUrl set to my vCard generating page with a query string parameter set to the value of the tag of the image. I then set con.DataContext to this RadHtmlPlaceholder. I've also modified RadWindowControl to be invisible (size 1x1 and opacity set to 0, with all options (move, header, etc.) set to false of blank), so it appears like it is not even there. And - VoilĂ ! - it all works as needed. Thank you very much for your patience and your help.
Sincerely,
VK.