We have an app that uses simple one way binding with a GridView to display some data. Well, now we need to allow the user to change some of that data, so I’ve been trying to get two way data binding to work in the GridView. So far everything displays correctly, but editing cells in the GridView seems to do nothing at all. What am I messing up? Is two way databinding like this even possible? Should I just start converting everything to use a different control, like maybe a DataGrid?
I wrote a tiny test app that shows my problem. If you try it, you’ll see that the property setters never get called after their initialization.
Xaml:
Title='Window1' Height='300' Width='300'> <Grid> <ListView Name='TestList'> <ListView.View> <GridView> <GridViewColumn Header='Strings'> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Text='{Binding Path=String, Mode=TwoWay}'/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header='Bools'> <GridViewColumn.CellTemplate> <DataTemplate> <CheckBox IsChecked='{Binding Path=Bool, Mode=TwoWay}'/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView> </Grid> </Window>
And here’s the corresponding code:
using System.Collections.Generic; using System.Windows; namespace GridViewTextbox { public partial class Window1 : Window { private List<TestRow> _rows = new List<TestRow>(); public Window1() { InitializeComponent(); _rows.Add(new TestRow('a', false)); _rows.Add(new TestRow('b', true)); _rows.Add(new TestRow('c', false)); TestList.ItemsSource = _rows; TestList.DataContext = _rows; } } public class TestRow : System.Windows.DependencyObject { public TestRow(string s, bool b) { String = s; Bool = b; } public string String { get { return (string)GetValue(StringProperty); } set { SetValue(StringProperty, value); } } // Using a DependencyProperty as the backing store for String. This enables animation, styling, binding, etc... public static readonly DependencyProperty StringProperty = DependencyProperty.Register('String', typeof(string), typeof(TestRow), new UIPropertyMetadata('')); public bool Bool { get { return (bool)GetValue(BoolProperty); } set { SetValue(BoolProperty, value); } } // Using a DependencyProperty as the backing store for Bool. This enables animation, styling, binding, etc... public static readonly DependencyProperty BoolProperty = DependencyProperty.Register('Bool', typeof(bool), typeof(TestRow), new UIPropertyMetadata(false)); } }
When you use Dependency Properties, the Setters will not be called by bindings, instead they change the value directly (using SetValue or something similar).
Try adding a PropertyChangedCallback, and set a breakpoint in there to see if the value is changed from the GridView.