TheFaithfulLearner
TheFaithfulLearner

Reputation: 693

Combobox within a listbox and a related data binding issue

Alrighty, so I have, as I said, a ComboBox within a ListBox. These are both controls (WPF project using C# in Visual Studio 2010 and MVVM).

I can create them all good and well.

The ListBox contains an ObservableCollection of something called IntWrapper, which just contains and int.

The ComboBox is loaded with an ObservableCollection of something called MissionViewModel, which is just a class that contains a few basic data types.

So the ItemSource for the ListBox and the ComboBox are different.

I can add and items to the ListBox with a button, which just adds a new IntWrapper to the ObservableCollection. Visually this gives me a new ComboBox, which is populated.

What I can't figure out is how to get one of the properties of MissionViewModel to go to the property in the IntWrapper when I select it.

Previously I just used a TextBox in the ListBox, which looked like this:

<ListBox x:Name="lbMissionsToGive" ItemsSource="{Binding MissionsToGive}" SelectedItem="{Binding SelectedMissionToGive}" ContextMenu="{StaticResource RemoveMissionToGiveMenu}">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Border BorderThickness="2" BorderBrush="LightBlue" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" CornerRadius="5,5,5,5">
                                        <StackPanel Orientation="Horizontal">
                                                    <TextBlock Margin="1">Mission ID: </TextBlock>
                                            <TextBox Margin="1" Text="{Binding Int, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                                        </StackPanel>
                                    </Border>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>

My (non working) attempt whereby I replace the TextBox with the ComboBox is this:

<ListBox x:Name="lbMissionsToGive" ItemsSource="{Binding MissionsToGive}" SelectedItem="{Binding SelectedMissionToGive}" ContextMenu="{StaticResource RemoveMissionToGiveMenu}">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Border BorderThickness="2" BorderBrush="LightBlue" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" CornerRadius="5,5,5,5">
                                        <StackPanel Orientation="Horizontal">
                                                <ComboBox DisplayMemberPath="MissionNameAndID" SelectedValuePath="Int" ItemsSource="{Binding MissionListViewModel.MissionVMs, Source={StaticResource Locator}}"></ComboBox>
                                        </StackPanel>
                                    </Border>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>

I had thought SelectedValuePath would be the thing I wanted, but this so far doesn't seem to work (perhaps I'm using it incorrectly).

Any assistance would be appreciated.

Upvotes: 0

Views: 88

Answers (2)

mm8
mm8

Reputation: 169160

Bind the SelectedValue property of the ComboBox to the Int property of the IntWrapper:

<ComboBox DisplayMemberPath="MissionNameAndID" SelectedValuePath="Int" SelectedValue="{Binding Int}"
          ItemsSource="{Binding MissionListViewModel.MissionVMs, Source={StaticResource Locator}}" />

This should work provided that the IntWrapper.Int property has a public setter and that the Int property of the MissionViewModel is of the same type as the Int property of the IntWrapper.

Upvotes: 1

Eike B
Eike B

Reputation: 231

I tried to create a solution for your problem based on your description. To help you more qualified, we would need more information about the MissionViewModel and the Properties contained in it.

I suppose, your Binding does not point to the correct ViewModel. I tried to recreate what you describe below and in my case, the combobox is filled with the Name Property of the MissionVm class.

This is the XAML. Here I changed the ItemsSource Binding to directly point to the ObservableCollection of the DataContext of the parent window.

<ListBox x:Name="lbMissionsToGive" ItemsSource="{Binding MissionsToGive}" SelectedItem="{Binding SelectedMissionToGive}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Border BorderThickness="2" BorderBrush="LightBlue" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" CornerRadius="5,5,5,5">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding }"></TextBlock>
                        <ComboBox Margin="20" Width="50" ItemsSource="{Binding DataContext.MissionVMs, RelativeSource={RelativeSource AncestorType=Window}}" DisplayMemberPath="Name"></ComboBox>
                    </StackPanel>
                </Border>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

And this is the ViewModel based on your description:

public class ViewModel : INotifyPropertyChanged
{
    public ViewModel()
    {
        var vm1 = new MissionVM { Id = 1, Name = "111"};
        var vm2 = new MissionVM { Id = 2, Name = "222" };
        var vm3 = new MissionVM { Id = 3, Name = "333" };

        MissionVMs = new ObservableCollection<MissionVM> { vm1, vm2, vm3};

        MissionsToGive = new ObservableCollection<int> {1, 2, 3};
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ObservableCollection<int> MissionsToGive { get; set; }

    public int SelectedMissionToGive { get; set; }

    public ObservableCollection<MissionVM> MissionVMs { get; set; }
}

public class MissionVM
{
    public int Id { get; set; }

    public string Name { get; set; }
}

This is the Output:

enter image description here

I hope this helps. If i misunderstood you, please give further explanation of the problem.

Upvotes: 0

Related Questions