I have a DataGrid with two way binding and not sure why this does not work, any help would be appreciated.
I wanted to dynamically bind to the DataGrid using a twoway binding object.
I used the columns in XAML. If I just set the 'ItemSource" property directly – it works but then the two binding doesn't work – if I change my source in code the Grid doesn't reflect that change.
I created a simple sample to illustrate my setup
Here is the XAML
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="356" d:DesignWidth="590" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Grid x:Name="LayoutRoot" Background="White">
<sdk:DataGrid AutoGenerateColumns="False" Height="136" HorizontalAlignment="Left" Margin="71,116,0,0" Name="MyGrid" VerticalAlignment="Top" Width="453" >
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding Path=Label, Mode=TwoWay}" CanUserReorder="True" CanUserResize="True" CanUserSort="True" Width="Auto" Header="Selected" />
<sdk:DataGridTextColumn Binding="{Binding Path=YValue, Mode=TwoWay}" CanUserReorder="True" CanUserResize="True" CanUserSort="True" Header="Name" Width="*" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
</UserControl>
Here is the code behind
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
ObservableCollection<Value> values = new ObservableCollection<Value>();
values.Add(new Value() { Label = "Sony", YValue = 50 });
values.Add(new Value() { Label = "Dell", YValue = 35 });
values.Add(new Value() { Label = "HP", YValue = 27 });
values.Add(new Value() { Label = "HCL", YValue = 17 });
values.Add(new Value() { Label = "Toshiba", YValue = 16 });
PagedCollectionView p = new PagedCollectionView(values);
Binding b = new Binding("ValuesBinding");
b.Mode = BindingMode.TwoWay;
b.Source = values;
MyGrid.SetBinding(DataGrid.ItemsSourceProperty, b);
}
}
public class Value : INotifyPropertyChanged
{
public String Label
{
get
{ return _label; }
set
{
_label = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Label"));
}
}
public Double YValue
{
get
{return _yValue;}
set
{
_yValue = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("YValue"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
Double _yValue;
String _label;
}
}
Best Answer
There are a couple of problems that I can see here.
The first line that you use to create your binding is
This won't do what you want. The string
ValuesBinding
is being used as a property-path, and the ObservableCollection you're binding the DataGrid to has no property on it namedValuesBinding
. Indeed, if you look in the VS Output window, you should see a message such asHowever, if you remove
"ValuesBinding"
from the above to leave you withthen you get an error about two-way bindings needing a Path. However, you don't need a two-way binding here. You can simply remove the line
b.Mode = BindingMode.TwoWay;
and the error goes away.Two-way bindings are used to allow the view-layer to set properties in the view-model layer. The Path specifies where to find the view-model property to set. However, since you're binding straight to a collection, there's no property involved and hence nothing that the view-layer could set.
In your case, this binding doesn't need to be two-way. Changes to the collection itself (e.g. adding or removing items) can still be made, even when using a one-way binding for the ItemsSource. The two-way bindings you have on the
Label
andYValue
properties of yourValue
class will also work as you expect. Setting a one-way binding on the DataGrid's ItemsSource doesn't make the whole grid read-only.Finally, I'm not sure why you're creating a binding in code-behind to bind to a collection already available in the code-behind. You can achieve the same by just writing