One day, two posts! :-) A member of the Silverlight .NET forum asked how he could go about making a Silverlight combobox editable. Well, it's actually easier than you might think, so for all of you who want this kind of behaviour: here's how you do it! :-) The same technique can also be used to make an editable listbox, and usual, sourcecode is included at the end of this post.
I designed a dummy data-object for binding to the combobox. This is a small class which has a Description-propery, an ID and an InEdit-property (to and it implements the INotifyPropertyChanged-interface, so it can notify the UI when its value changes.
1: public class Dummy : INotifyPropertyChanged
2: {3: public int ID { get; set; }
4: 5: private bool pInEdit;
6: public bool InEdit
7: { 8: get 9: {10: return pInEdit;
11: } 12: set 13: {14: pInEdit = value;
15: NotifyPropertyChanged("InEdit");
16: } 17: } 18: 19: private string pDescription;
20: public string Description
21: { 22: get 23: {24: return pDescription;
25: } 26: set 27: {28: pDescription = value;
29: NotifyPropertyChanged("Description");
30: } 31: } 32: 33: #region INotifyPropertyChanged Members
34: 35: public event PropertyChangedEventHandler PropertyChanged;
36: 37: public void NotifyPropertyChanged(string propertyName)
38: {39: if (PropertyChanged != null)
40: {41: PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
42: } 43: } 44: 45: #endregion
46: }Next, we need to build the datatemplate of our combobox. Essentially, we'll have two "views": a normal view, and an editable view. We'll use a button to switch between these views.
1: <ComboBox.ItemTemplate>
2: <DataTemplate>
3: <Grid>
4: <Grid.ColumnDefinitions>
5: <ColumnDefinition Width="200"></ColumnDefinition>
6: <ColumnDefinition Width="Auto"></ColumnDefinition>
7: </Grid.ColumnDefinitions>
8: 9: 10: <TextBlock Text="{Binding Description, Mode=TwoWay}"
11: HorizontalAlignment="Left" VerticalAlignment="Center"
12: IsHitTestVisible="False"
13: Visibility="{Binding InEdit, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=contra}"/>
14: 15: <TextBox Text="{Binding Description, Mode=TwoWay}"
16: Visibility="{Binding InEdit, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=pro}"
17: HorizontalAlignment="Left" VerticalAlignment="Center"/>
18: 19: <Button Width="60" x:Name="btnEdit" Click="btnEditConfirm_Click" Content="Edit" Grid.Column="1"
20: Visibility="{Binding InEdit, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=contra}" />
21: 22: <Button Width="60" x:Name="btnConfirm" Click="btnEditConfirm_Click" Content="Confirm" Grid.Column="1"
23: Visibility="{Binding InEdit, Converter={StaticResource BoolToVisibilityConverter}}"/>
24: 25: </Grid>
26: </DataTemplate>
27: </ComboBox.ItemTemplate>
To make sure the correct view is shown, I use a convertor to convert the InEdit-value of my object to a Visibility-property. When InEdit is true, the textbox & confirm-button will be shown, when it's false you'll only see a textblock and an edit button. For reference, here's what the convertor looks like:
1: public class BoolToVisibilityConverter: IValueConverter
2: { 3: 4: #region IValueConverter Members
5: 6: /// <summary>
7: /// Convert method from bool to visibility
8: /// </summary>
9: /// <param name="value">the boolean/visibility value value</param>
10: /// <param name="targetType"></param>
11: /// <param name="parameter">mappingmode = pro or contra. Pro will map true to visible, contra
12: /// will map true to collapsed</param>
13: /// <param name="culture"></param>
14: /// <returns></returns>
15: public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
16: {17: bool normalDirection = true;
18: 19: if (parameter != null)
20: {21: if (parameter.ToString().Trim().ToLower() == "contra")
22: normalDirection = false;
23: } 24: 25: if (value is bool)
26: {27: if ((bool)value)
28: {29: return normalDirection ? Visibility.Visible : Visibility.Collapsed;
30: }31: else
32: {33: return normalDirection ? Visibility.Collapsed : Visibility.Visible;
34: } 35: }36: else
37: {38: return Visibility.Visible;
39: } 40: } 41: 42: public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
43: {44: bool normalDirection = true;
45: 46: if (parameter.ToString().Trim().ToLower() == "contra")
47: normalDirection = false;
48: 49: if (value is Visibility)
50: {51: if ((Visibility)value == Visibility.Visible)
52: {53: return normalDirection ? true : false;
54: }55: else
56: {57: return normalDirection ? false : true;
58: } 59: }60: else
61: {62: return true;
63: } 64: } 65: 66: #endregion
67: }All we need to do now is handle the click-event of the edit & confirm button. Thanks to the rich, two-way-databinding, all we need to do in these handlers is change the edit-mode: we use the DataContext of the sender to access the underlying object, and change the edit-mode-property. We do not need to write our changes to the underlying collection nor commit them manually in any way, nor update the UI when a value is changed - Silverlights' databinding & notifypropertychanged-interface handles this for us.
1: private void btnEditConfirm_Click(object sender, RoutedEventArgs e)
2: { 3: Dummy tmpDummy = (Dummy)(((Button)sender).DataContext); 4: tmpDummy.InEdit = !tmpDummy.InEdit; 5: }... and that's it, really. :-) As said, the same technique can also be used to make your listbox editable (or any itemscontrol for that matter).
As promised: sourcecode. Enjoy!
0 reacties:
Een reactie plaatsen