Binding SelectedItem to ItemsSource between two datagrids

A recent problem I had was to bind the SelectedItem from a master datagrid, to the ItemsSource of a child datagrid. My work around’s using mouse clicks had too many limitations when used with MVVM – delete the selected item from the parent collection, the child collection did not update. Whilst watching John Papas PDC video for building large scale Silverlight application I spotted his sweet DataGridRowSelected command behaviours (documented http://thoughtjelly.blogspot.com/2009/12/silverlight-commands-data-grid-row.html)

To implement this you can do the following, XAML:

<UserControl x:Class="NestedDataGrid.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"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView"
xmlns:this="clr-namespace:NestedDataGrid"
xmlns:commands="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"
>




<data:DataGrid x:Name="dgTeams"
SelectedItem="{Binding SelectedTeam}"
ItemsSource="{Binding Teams}"
this:DataGridRowSelected.Command="{Binding GridViewRowSelectedCommand}"
/>






<Button Content="Delete Current"
commands:Click.Command="{Binding DeleteCurrentTeamCommand}"
commands:Click.CommandParameter="{Binding SelectedTeam}"
/>



Code behind:

public partial class MainPage : UserControl
{

ViewModel viewModel = new ViewModel();

public MainPage()
{
InitializeComponent();
this.LayoutRoot.DataContext = viewModel;
}

}

and ViewModel:

public class ViewModel: ObjectBase
{
ObservableCollection _rainbowPeeps;
ObservableCollection _theSimpsons;
ObservableCollection _familyGuyKids;


public ViewModel()
{
/// setting up some dummy data
_rainbowPeeps = new ObservableCollection()
{
new Person(){ PersonId=1, Name="George"},
new Person(){ PersonId=2, Name="Zippy"},
new Person(){ PersonId=3, Name="Bungle"},
};

_theSimpsons = new ObservableCollection()
{
new Person(){ PersonId=4, Name="Moe"},
new Person(){ PersonId=5, Name="Barney"},
new Person(){ PersonId=6, Name="Selma"},
};

_familyGuyKids = new ObservableCollection()
{
new Person(){ PersonId=7, Name="Stewie"},
new Person(){ PersonId=8, Name="Meg"},
new Person(){ PersonId=9, Name="Chris"},
};


Teams = new ObservableCollection()
{
new Team(){ TeamId=1, TeamDesc="Rainbow", People=_rainbowPeeps},
new Team(){ TeamId=2, TeamDesc="Simpsons", People=_theSimpsons},
new Team(){ TeamId=3, TeamDesc="Family Guys", People=_familyGuyKids },
};

/// COMMAND IMPLEMENTATIONS. The DataGridRowSelected parameter
/// is the datacontext of the selected row.
GridViewRowSelectedCommand = new DelegateCommand(
delegate(Team team) { SelectedTeam = team; }
);

DeleteCurrentTeamCommand = new DelegateCommand(
delegate(Team team)
{
Teams.Remove(team);
if (Teams.Count > 0)
SelectedTeam = Teams[0];
else
SelectedTeam = null;
}
);
}

private ObservableCollection _teams;
public ObservableCollection Teams
{
get { return _teams; }
set
{
SetValue(ref _teams, value, "Teams");
}
}

private Team _selectedTeam;
public Team SelectedTeam
{
get { return _selectedTeam; }
set
{
SetValue(ref _selectedTeam, value, "SelectedTeam");
}
}

///
/// Command to handle the selection of a row.
///

private DelegateCommand _gridViewRowSelectedCommand;
public DelegateCommand GridViewRowSelectedCommand
{
get { return _gridViewRowSelectedCommand; }
set
{
SetValue(ref _gridViewRowSelectedCommand, value, "GridViewRowSelectedCommand");
}
}

///
/// Used to simulate the deletion of a parent team
///

private DelegateCommand _deleteCurrentTeamCommand;
public DelegateCommand DeleteCurrentTeamCommand
{
get { return _deleteCurrentTeamCommand; }
set
{
SetValue(ref _deleteCurrentTeamCommand, value, "DeleteCurrentTeamCommand");
}
}

}

Finally, some misc data classes and the ObjectBase super class for INotifyPropertyChanged:

public abstract class ObjectBase : Object, INotifyPropertyChanged
{
public ObjectBase()
{ }

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void _OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler pceh = PropertyChanged;
if (pceh != null)
{
pceh(this, new PropertyChangedEventArgs(propertyName));
}
}

protected virtual bool SetValue(ref T target, T value, string propertyName)
{
if (Object.Equals(target, value))
{
return false;
}

target = value;
_OnPropertyChanged(propertyName);

return true;
}

}


public class Person: ObjectBase
{
private int _personId;
public int PersonId
{
get { return _personId; }
set
{
SetValue(ref _personId, value, "PersonId");
}
}

private string _name;
public string Name
{
get { return _name; }
set
{
SetValue(ref _name, value, "Name");
}
}

}

public class Team : ObjectBase
{

private int _teamId;
public int TeamId
{
get { return _teamId; }
set
{
SetValue(ref _teamId, value, "TeamId");
}
}

private string _teamDesc;
public string TeamDesc
{
get { return _teamDesc; }
set
{
SetValue(ref _teamDesc, value, "TeamDesc");
}
}


private ObservableCollection _people;
public ObservableCollection People
{
get { return _people; }
set
{
SetValue(ref _people, value, "People");
}
}

public override string ToString()
{
return _teamId.ToString() + " " + _teamDesc;
}

}

Brilliant 🙂

NOTE: Code for DataGridRowSelected and DataGridRowSelectedCommandBehaviour is here

One thought on “Binding SelectedItem to ItemsSource between two datagrids

Add yours

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

A WordPress.com Website.

Up ↑

%d bloggers like this: