Monday 14 February 2011

Making two cells in a grid dependable

One of my colleague was trying to create a Silverlight grid, where two columns are dependent. For sake of simplicity, lets say I have two columns, A and B. If A has a value in a valid range then Column B will be editable otherwise it is read only. Even though I said, it is columns, in reality it is cells. The reason I did not make the distinction in the beginning is that, it is taken care by binding. So how do we go about solve this problem. It is actually very easy than what we think. Now that we going to see the example, just want to point one out, I use Component One data gird a lot and I thought, I will bring in component one grid in this example as well.

1. First create a class where we will use this dependency. For simplicity I created a Person class as follows.

public class Person : INotifyPropertyChanged
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged("Name");
}
}

private double _amount;
private int _bonus;

public double Amount
{
get
{
return _amount;
}
set
{
_amount = value;
RaisePropertyChanged("Amount");
}
}

public int Bonus
{
get
{
return _bonus;
}
set
{
_bonus = value;
RaisePropertyChanged("Bonus");
}
}

public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

public event PropertyChangedEventHandler PropertyChanged;
}

In the above class, the two fields that we are interested in are Amount and Bonus. When the amount is more than 1000 then bonus field will become editable.

2. Create XAML to bind the collection as follows

 1:     <Grid x:Name="LayoutRoot" Background="White">
2: <Grid.Resources>
3: <converter:ColorConverterForReadOnly x:Key="converter1"/>
4: <converter:ReadOnlyConverter x:Key="converter2"/>
5: </Grid.Resources>
6: <c1:C1FlexGridExcel Name="_flex" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
7: <c1:C1FlexGridExcel.Columns>
8: <c1:Column Binding="{Binding Name}"/>
9: <c1:Column Binding="{Binding Age}"/>
10: <c1:Column Binding="{Binding Amount, Mode=TwoWay}"/>
11: <c1:Column Binding="{Binding Bonus, Mode=TwoWay}" HorizontalAlignment="Right">
12: <c1:Column.CellTemplate>
13: <DataTemplate>
14: <Grid>
15: <Border Background="{Binding Amount, Converter={StaticResource converter1}}"/>
16: <TextBlock Text="{Binding Bonus}" VerticalAlignment="Center" HorizontalAlignment="Right"/>
17: </Grid>
18: </DataTemplate>
19: </c1:Column.CellTemplate>
20: <c1:Column.CellEditingTemplate>
21: <DataTemplate>
22: <Grid>
23: <Border Background="{Binding Amount, Converter={StaticResource converter1}}"/>
24: <TextBox IsReadOnly="{Binding Amount, Converter={StaticResource converter2}}" Text="{Binding Bonus, Mode=TwoWay}"
25: Background="{Binding Amount, Converter={StaticResource converter1}}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0"/>
26: </Grid>
27: </DataTemplate>
28: </c1:Column.CellEditingTemplate>
29: </c1:Column>
30: </c1:C1FlexGridExcel.Columns>
31: </c1:C1FlexGridExcel>
32: </Grid>

In the above code,you will notice I am using two converters. First converter will set the back ground color to readonly background color when the amount is less than 1000. The second converter will return true or false based on amount field.

So if you would notice, from line 12 – 28, have two definitions. one for cell template to render the data and cell edit template which will be used when user try to edit the cell.

In cell template, line 15, will set the back ground of the cell to read only look based on the amount. As you can see, Background is bound to amount but the brush will be set in the converter. (will see the converter later).

Line 16 basically shows a text block which by default readonly to show the data.

Line 23 is same as line 15 to change the background color.

Line 24 is a text box which will allow the user to edit the cell if the amount is greater than 1000. This is achived by IsReadOnly property, which is bound to Amount again, when it is passed through the converter, it will check and see if the amount is greater than 1000 and based on the value, it will return true or false. So if the amount is less than 1000 then isreadonly will be true thus making the cell readonly.

3. The Converters:

 1: public class ColorConverter : IValueConverter
2: {
3: public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
4: {
5: double? data = value as double?;
6:   7: if (data == null || data < 1000)
8: {
9: return new SolidColorBrush(Color.FromArgb(255, 200, 200, 200));
10: }
11: else
12: return null;
13: }
14:   15: public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
16: {
17: return null;
18: }
19: }
20:   21: public class ReadOnlyConverter : IValueConverter
22: {
23: public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
24: {
25: double? data = value as double?;
26:   27: return (data == null || data < 1000);
28: }
29:   30: public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
31: {
32: return value;
33: }
34: }

The first converter is background color converter called ColorConverter. Which is used in the background property binding. As you can see in line 7, when the amount is less than 1000, then it returns gray background brush. Other wise, it returns null.

The second converter (line 21) is read only converter. This will return true, when the amount is less than 1000 otherwise is false at line 27.

0 comments:

Post a Comment