1

I am trying to make a WPF program, where I have an AgreementModel. The agreements are then shown using a ListView control, but displaying only a few key properties. I then have a StackPanel control, which I use to display all agreement details, for the selected item. I have made a DataTemplate for each of the ways of displaying the item.

And this is where my issue is. While I can easily bind the ListView to the agreements (an ObservableCollection in my view model), I simply cannot figure out how to bind the details to the selected agreement (an AgreementModel in the view model).

Everything I can find seems to relate to binding collections. How do I bind only the selected item to a StackPanel or similar?

View XAML

<UserControl.Resources>
    <!--Template for list view-->
    <DataTemplate x:Key="agreementRowTemplate">
        <StackPanel Orientation="Horizontal">

            <TextBlock
                Text="{Binding Path=Property1}" />

            <TextBlock
                Text="{Binding Path=Property2}" />

            <TextBlock
                Text="{Binding Path=Property3}" />

        </StackPanel>
    </DataTemplate>

    <!--Template for the detail view-->
    <DataTemplate x:Key="agreementDetailTemplate">
        <StackPanel>
            <TextBlock
            Text="Property 1:" />

            <TextBox
            Text="{Binding Path=Property1}" />

        </StackPanel>            
    </DataTemplate>
</UserControl.Resources>

<Grid Background="White">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="600" />
        <ColumnDefinition Width="1*" />
    </Grid.ColumnDefinitions>

    <!-- This list view works as intended -->
    <ListBox
        Grid.Column="1"
        ItemsSource="{Binding Agreements}"
        SelectedItem="{Binding SelectedAgreement}"
        ItemTemplate="{StaticResource agreementRowTemplate}"/>

    <!-- I am trying to add my detail view here -->
    <ItemsControl ItemTemplate="{StaticResource agreementDetailTemplate}" ItemsSource="{Binding SelectedAgreement}">
    </ItemsControl>

</Grid>

ViewModel C#

private AgreementModel selectedAgreement;

public ValuationViewModel()
{
    LoadAgreements();
}

public ObservableCollection<AgreementModel> Agreements
{
    get; set; 
}

// I have tried 'return Agreements[0]' to check if this was the problem
public AgreementModel SelectedAgreement
{
    get { return _selectedAgreement; }
    set { selectedAgreement = value; }
}

public void LoadAgreements()
{
    ObservableCollection<AgreementModel> agreements =
        new ObservableCollection<AgreementModel>();

    agreements.Add(new AgreementModel { Property1 = 123, Property2 = "Some Text", Property3 = "Status: OK" });
    agreements.Add(new AgreementModel { Property1 = 456, Property2 = "Some Text", Property3 = "Status: Not OK" });
    agreements.Add(new AgreementModel { Property1 = 789, Property2 = "Some Text", Property3 = "Status: Somewhat OK" });

    Agreements = agreements;
}
Jakob Busk Sørensen
  • 5,599
  • 7
  • 44
  • 96
  • 2
    For a single item (`SelectedAgreement`) you may also use `ContentControl` instead of `ItemsControl`. Anyway, just set `SelectedAgreement` appropriately when `ListView` selected item changes...how? See https://stackoverflow.com/a/29885442/1207195 – Adriano Repetti Jan 16 '18 at 14:11

2 Answers2

4

An ItemsControl is used to display a collection, or rather an IEnumerable, of items.

If you simply want to display the details of the currently selected AgreementModel in a StackPanel, you could bind its DataContext to the SelectedAgreement property or use a ContentControl:

<ContentControl Content="{Binding SelectedAgreement}" ContentTemplate="{StaticResource agreementDetailTemplate}" />

<StackPanel DataContext="{Binding SelectedAgreement}">
...
</StackPanel>

You should also make sure that your view model class implements the INotifyPropertyChanged interface and raise the PropertyChanged event whenever the SelectedAgreement property is set.

Otherwise the ContentControl/StackPanel won't be updated when you select an item in the ListBox.

mm8
  • 163,881
  • 10
  • 57
  • 88
1

You need to bind the SelectedIndex to a property (e.g. SelectedAgreementIndex) in your ViewModel. Then, in the setter of the SelectedAgreementIndex property, you could set a SelectedAgreement property based on the SelectedIndex. Then it's just to bind to the SelectedAgreement using e.g. a ContentControl in the View that's using your data template.

Oystein
  • 1,232
  • 11
  • 26