by Naveen
24. February 2010 10:23
Download Sample Project (367.89 kb)
In one of my previous posts
How to use DataGrid in Silverlight
I showed a very simple usage where data grid was bound to a list of products. Now let us take one more step
in customizing use of this data grid. When I executed my method to get list of products from
AdventureWorks database, it returned me about 1000 records. And then datagrid was bound
to that list, i got a huge page with grid showing all the records. I am sure at this point you are
looking for way to add some kind of paging to your data grid so that user can navigate the list
easily.
Silverlight has a control named DataPager that comes in very handy to add
paging functionality to any control that you use to display lists. From the name
is it obvious that this control is a pager. Following XAML shows how I added paging functionality
to my datagrid.
<StackPanel x:Name="ContentStackPanel" Orientation="Vertical">
<TextBlock x:Name="HeaderText" Style="{StaticResource HeaderTextStyle}"
Text="Products"/>
<data:DataPager x:Name="ProductsPager"
PageSize="10"
DisplayMode="Numeric"
AutoEllipsis="True"
HorizontalAlignment="Left" />
<data:DataGrid x:Name="ProductsGrid">
<data:DataGrid.Columns>
<data:DataGridTemplateColumn>
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Button x:Name="UpdateButton" Content="Update"
Click="UpdateButton_Click"></Button>
</StackPanel>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
</StackPanel>
You can read more about different ways to customize the display of datapager from the documentation. For
this discussion you can see that I have set PageSize, DisplayMode, AutoEipsis and HorizontalAlignment
properties of pager and the screen shot shows how it looks. I will talk more about customization of
DataPager in detail in next post. For now I just want to keep it to simple use.
PageViewCollection
This is the collection object that drives the functionality for DataPager. In general you need a collection
that implements IPagedViewCollection interface. No, you do not have to do any more implementation
to get DataPager to work. We already have list of products obtained from previous web service call. You can
simply wrap that list into PagedViewCollection object and set it as Source
for DataPager object. And then set the source for DataGrid as this PagedViewCollection
object and we are all set to go. Following code shows simple change I made in code from previous sample
project.
void GetProductsCompleted(object sender, GetProductsCompletedEventArgs e)
{
_products = e.Result;
if (null != _products)
{
_pagedProductsView = new PagedCollectionView(_products);
ProductsPager.Source = _pagedProductsView;
ProductsGrid.ItemsSource = _pagedProductsView;
}
}
Add References
PagedViewCollection is defined in System.Windows.Data assembly.
So you will need to add reference to this assembly in your Silverlight project and then
add using directive for the namespace in your source code to refer to the
classes in this namespace and assembly.
Adding Paging to DataGrid in Silverlight is as easy as that.
by Naveen
11. February 2010 15:36
Download Sample Project
In the previous post How to use Silverlight DataGrid I discussed simple use of DataGrid in Silverlight application. Now it is time to start putting together implementation that we have from day to day to applications. One of the tasks that you may come across is that you need to add buttons to each row in the
DataGrid and then handle click events for those buttons. In the previous post I mentioned use of DataGridTemplateColumn to provide custom rendering of columns in the grid. So to add button(s) to your column, you will use the template column and then provide Button control to add them to each row. Following snippet shows how it looks like in my sample application.
<data:DataGrid x:Name="ProductsGrid">
<data:DataGrid.Columns>
<data:DataGridTemplateColumn>
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Button x:Name="UpdateButton" Content="Update"
Click="UpdateButton_Click"></Button>
</StackPanel>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
Handling Click Event For Button In DataGrid
As you can see from the XAML above, I just added handling of Click event on Button control. And in the codebehind provided implementation for it.
private void UpdateButton_Click(object sender, RoutedEventArgs e)
{
var ctl = e.OriginalSource as Button;
if (null != ctl)
{
var product = ctl.DataContext as Product;
if (null != product)
{
var msg = string.Format("{0}, {1}, {2}",
product.ProductID, product.Name, product.ListPrice);
MessageBox.Show(msg);
}
}
}
Accessing Data Associated With Row In DataGrid
When user clicks on the button in datagrid row, the method gets called. Next question you have is how do you access the data associated with the row on which button was clicked. It is very straight forward. When DataGrid rendering takes place, each control in the row is bound to DataContext. This DataContext is the data that was used to render that row. So you simple look at DataContext property of Button control that raised the event and got the actual data object used for that row.
I think this should give you a good starting point on how to add buttons or some other controls in DataGrid rows and how to access data for them as well. In next post I will discuss more of customization of Silverlight DataGrid.
7844ddb0-9be1-40f3-a07b-788272c5bc4d|0|.0
Views: 11249
Tags:
DataGrid
by Viper
14. July 2009 14:12
Download Sample Project
This is based on a question asked by one of my blog readers.
I have 2 datagrids. Each Grid has the same amount of columns and each grid has a select column as the last column on the right added from the
"gridview/ edit Columns/ CommandField/ Add" sequence.
The first GridView has the Select column as a Link
The second GridView has the select Column as a button
I want to be able to change the text for both the Link and button in cell(4), setting them to the value in cell(1) from the same row using the GridView_RowDataBound event.
However, using "cell(4).text = cell(1).text" just overwrites the text value removing the hyperlink and button.
The behavior described in this question is as expected. When you set text of a cell in grid, it directly affects HTML that is going to be rendered. When you set text
value of a cell, it means that you are setting innerText of the cell. The column that GridView creates for command fields (Edit, Delete and Select)
are a (anchor) or button elements. So you can see what will happen if you set text value in that cell. It will wipe out those link or button
controls and replace them with simple text string.
There are properties like EditText, DeleteText and SelectText for CommandField column in grid view. If you try to
set these values using a server side method by passing it DataContainer object, you will get following exception thrown.
Databinding expressions are only supported on objects that have a DataBinding event.
System.Web.UI.WebControls.CommandField does not have a DataBinding event.
After looking at the requirements, i realized that requirements are as simple as replacing text with value from another cell in the same row. There is no need
for doing any server side tricks or things like that. I can simple put together a simple client side java script that will take values from cell 1 and put them
in whatever cell I want. Abd I came up with this small javascript solution using jQuery. This small code snippet shows how you can
manipulate GridView or DataGrid on client side using jQuery. Let me show you the client side javascript that
I added on the page. Then I will explain what this code is doing.
<script type="text/javascript">
function updateCommandLinks() {
var $gridTable = $('#productsGrid');
var rows = $gridTable.find('tbody > tr');
var slicedRows = rows.slice(1, rows.length - 2);
slicedRows.each(function() {
var cells = $(this).find('td');
var cellElem1 = cells.get(1);
var cellElem5 = cells.get(5);
$(cellElem5).find('a').each(function() {
$(this).addClass('commandlink').append(" " + cellElem1.innerText);
});
});
}
$(document).ready(function() {
updateCommandLinks();
});
</script>
The above code may look little verbose considering you can write very concise code using jQuery. But for sale of
explaining and debugging, I decided to make it little bit verbose. I am sure you can reduce it to half the lines of code that I
have written.
The implementation adds a handler for document load event. In that event handler here are the steps it follows:
- Finds the element that has id of productsGrid. In our case, that is HTML element ID of our grid view.
- In the table, it gets collection of all the rows, identified by tr tag.
- Since in my implementation I have header and pager, that adds three rows into the collection. One top row for the header
and then the last row itself will contain another table that contains a row for paging elements. To keep it simple, I decided to
use slice function to remove first and last 2 rows from collection. You will need to modify this implementation
depending on your grid rendering.
- It iterates over each row in the collection.
- For each row it then finds all cells, identified by td tag.
- In my case, I want to replace text in command links with text from second column. So I saved reference to cell at index
1 by using get function.
- Then I extracted all elements with tag a from sixth column.
- Then it iterates over collection of anchor a tags and appends text from second cell to text in each of the links.
I think that is a simple implementation that serves the purpose without making any changes on the server side. The attached project has
the complete implementation for this grid. This is a Visual Studio 2010 project. But you should be able to copy the script
from the page to your implementation.
by Viper
2. July 2009 05:08
Download Sample Project
While working on a car dealership listings web site, I was experimenting with inserting google maps
into the data grid. The grid will show name and address of top rated car dealers in certain
categories. And along side their information, it will show their location on google map. To accomplish
this task, I needed the longitude and latitude of car dealership's address or location. Some time back in
my earlier post
Convert Address and/or IP address to Geo Location I described how you can utilize google
map's api to convert a physical address to geo location coordinates. This is the same technique that I used in
Backyardtweets to show tweets in a specified
location. So use the google map api to get these coordinates and insert these coordinates in the
java script.
Now that you have geo location corresponding to an address, your task is to insert that little piece of
java script in each row of the data grid. The way google map java script works is that it requires
a HTML element where it can insert the map image. So I inserted a div with unique id in a cell in
each row and then passed that unique id to java script that is used to render the map. Add an event
handler for RowDataBound event and there you can add the element and register a
client script for map as well. Here is some code snippet that shows how this all is accomplished.
protected void OnDealerRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var carDealer = e.Row.DataItem as CarDealer;
var divId = string.Format("dealloc_{0}", carDealer.Id);
var mapPanel = e.Row.Cells[2].FindControl("mapPanel") as Panel;
var div = new HtmlGenericControl("div");
div.Attributes.Add("id", divId);
div.Attributes.Add("class", "mapdiv");
mapPanel.Controls.Add(div);
string js = GetGoogleMapScript(carDealer, divId);
ScriptManager.RegisterStartupScript
(this.Page, this.GetType(), "_map_" + carDealer.Id, js, true);
}
}
private string GetGoogleMapScript(CarDealer dealer, string ctlId)
{
string loc = string.Empty;
if (!string.IsNullOrEmpty(dealer.State))
{
loc = string.Format("{0},", dealer.State);
}
loc += dealer.Country;
decimal longitude, latitude;
GoogleMapUtility.GetGeoLocationFromGoogle(loc, out longitude, out latitude);
dealer.Location.Latitude = latitude;
dealer.Location.Longitude = longitude;
return GetJScriptForGeoLocations(longitude, latitude, ctlId);
}
public static string GetJScriptForGeoLocations(decimal longitude, decimal latitude, string elemId)
{
StringBuilder sb = new StringBuilder();
sb.Append("function initialize_" + elemId + "() {{");
sb.Append(" if (GBrowserIsCompatible()) {{ ");
sb.Append(" var map = new GMap2(document.getElementById(\"{0}\"));");
sb.Append(" map.setCenter(new GLatLng({1}, {2}), 13);");
sb.Append(" map.setUIToDefault();}}}} initialize_" + elemId + "();");
return string.Format(sb.ToString(), elemId, latitude, longitude);
}
The attached project with this post has all the implementation for this sample implementation. And this is
a Visual Studio 2010 project. I have not used any 2010 specific namespaces or code in this implementation so
you should be able to take all the code and move it into a VS2008 or VS2005 project. And you will need to
get key for google map api use from google as well.