Question summary: Is there a way in XAML to ensure that my DataGrid component is fully loaded before it initiates a binding on the SelectedIndex property?
My ViewModel is set up like this. I'm using MVVM-light to notify the view of changes. I pass the new model to SetData() whenever the it gets updated from the server.
public class MyViewModel : ViewModelBase
{
public void SetData(DataModel model)
{
Data = model.Data; //Array of 75 DataObjects
DataIndex = model.Index; //int between 0 and 74
}
// Array to Bind to Datagrid ItemsSource
public DataObject[] Data
{
get { return _data; }
private set
{
if (_data!= value)
{
_data= value;
RaisePropertyChanged("Data");
}
}
}
private DataObject[] _data;
// Int to Bind to Datagrid SelectedIndex
public int DataIndex
{
get { return _index; }
private set
{
if (_index != value)
{
_index = value;
RaisePropertyChanged("DataIndex");
}
}
}
private int _index;
}
The view looks like this:
<Application.Resources>
<ResourceDictionary>
<core:ViewModelLocator x:Key="Locator" />
</ResourceDictionary>
</Application.Resources>
<DataGrid ItemsSource="{Binding MyViewModel.Data, Source={StaticResource Locator}}"
SelectedIndex="{Binding MyViewModel.DataIndex, Source={StaticResource Locator}, Mode=OneWay}"
AutoGenerateColumns="True"/>
My issue is that none of the rows are selected on my DataGrid. All the data shows up in the grid correctly but the row does not get selected. I've checked the properties and confirmed that the Array length is 75 and DataIndex is an int between 0 and 74.
It seems the reason is because the DataGrid hasn't finished loading when the binding is set. I can prove this by initializing the binding after the component is loaded. In this case, everything works as expected and my selected item is displayed correctly:
<DataGrid x:Name="MyDataGrid" Loaded="OnDataGridLoaded"
ItemsSource="{Binding MyViewModel.Data, Source={StaticResource Locator}}"
AutoGenerateColumns="True"/>
private void OnDataGridLoaded(object sender, RoutedEventArgs e)
{
Binding b = new Binding("DataIndex");
b.Source = Locator.MyViewModel.Data;
MyDataGrid.SetBinding(DataGrid.SelectedIndexProperty, b);
}
I'd prefer not to have to do it like this because, you know, code-behind. So is there a way to fix this using only XAML? Here is what I've tried so far (none of which worked for me):
- Binding SelectedIndex to an
intproperty on my ViewModel (as shown above) - Binding SelectedItem to a
DataObjectproperty on my ViewModel (same result) - Binding SelectedValue and SelectedPath to a property of my
DataObject(This actually worked, for the first instance only. The problem is I have multiple instances of this Datagrid component, and for some reason this only works on the first instance) - Binding to an ObservableCollection instead of an Array (tried all 3 of the above methods with an ObservableCollection and got the same results for each)
- Delaying the change notification by wrapping it in a call to
Dispatcher.Invoke. This doesn't help because the component is not immediately in view. - Creating the binding in XAML and then updating the target in the Loaded function.
MyDataGrid.GetBindingExpression(DataGrid.SelectedIndexProperty).UpdateTarget();
setDataonWindow.Loadedevent for first time. - esiprogrammerDataContextof the view. that's why ur provided code-behind is working. where do you setDataContext? - esiprogrammer