I'm extremely new to WPF and am trying to use Knockout JS as an analogy when creating bindings. I heard WPF's binding engine was even more powerful, but I'm struggling with something that is dog easy in Knockout.
Suppose I have a Person class which has a collection of Addresses.
public class Person
{
public string PersonId {get;set;}
public IList<Address> Addresses{get; set;}
public string FormattedName{get;set;}
}
public class Address
{
public string AddressId{get;set;}
public string Address1{get;set;}
public string City{get;set;}
public string State{get;set;}
public string Zip{get;set;}
}
Suppose on a page, I have a collection of people and for each person, I'd like to show all address and provide buttons to choose an address. So, my page view model looks like this:
public class AddressSelection
{
public string PersonId{get;set;}
public string AddressId{get;set;}
}
public class PersonAddressSelectionViewModel
{
public IList<Person> People {get; set;}
public Person SelectedPerson {get;set;}
public Address SelectedAddress{get;set;}
public void SelectAddress(string personId, string addressId)
{
this.SelectedPerson = this.People.FirstOrDefault(x => x.PersonId == personId);
this.SelectedAddress = this.SelectedPerson?.Addresses.FirstOrDefault(x => x.AddressId == addressId);
}
public void SelectAddress(AddressSelection arg)
{ SelectAddress(arg.PersonId, arg.AddressId); }
}
Now, I want to show a UI that shows a header for each passenger, then a button for each address. When the button is selected, the SelectAddress function should be triggered. However, in the XAML, I'm not sure how to assign the binding to use both the parent and current element properties; whether it can create an object from them or even just call a method and pass arguments fetch from both.
In knockout, you'd just bind the function and access the parent context like:
<!-- ko foreach: $data.people -->
<h2 data-bind="text: formattedName"></h2>
<ul data-bind="foreach: $data.addresses">
<li>
<button data-bind="click: function() { $parents[1].selectAddress($parent.personId, $data.addressId); }">Select Address</button>
</li>
</ul>
<!-- /ko -->
I can't seem to figure out how to do the same thing in XAML.
<ItemsControl Grid.Row="2" ItemsSource="{x:Bind ViewModel.People, Mode=OneWay}"
HorizontalAlignment="Center" Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Style="{StaticResource TextBlockSmallStyle}" VerticalAlignment="Center" Width="180" Text="{Binding FormattedName, Mode=OneWay}" />
<ItemsControl ItemsSource="{Binding Addresses}" Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Width="180" Style="{StaticResource ButtonStyle}"
Content="{Binding Address1}"
Click="SelectAddressClicked" Tag="{Binding **what to put here**}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
in code behind:
SelectAddressClicked(object sender, object args) {
((Button)sender).Tag as Address; // would prefer this to be something that has both the address id and person id
}