简体   繁体   中英

WPF ComboBox selection causes selection in second ComboBox

I'm binding two comboboxes to the same listviewcollection. The problem is that selecting a value in one combobox, causes the other combobox selected item to change to the exact value of the first combobox. They are coupled and I want them to be independent of each other.

MyListViewCollection is like this

modelsView = new ListCollectionView(MainVM.All_Models);

All_Models is an Observable collection of custom objects like this

public ObservableCollection<MLModel> All_Models { get; set; } = new ObservableCollection<MLModel>() { };

I bind two ComboBoxes to modelsview like this

<ComboBox ItemsSource="{Binding Path=modelsView}" SelectedItem="{Binding SelectedModel_Right}" SelectionChanged="RightSideModelSelection">

<ComboBox ItemsSource="{Binding Path=modelsView}" SelectedItem="{Binding SelectedModel_Left}" SelectionChanged="LeftSideModelSelection">

So everything works fine, the comboboxes contain the identical lists of items from the models view which is what I want. I definitely have bound the selected item to two separate properties in the view model, and those are

    private MLModel _selectedModel_left;
    public MLModel SelectedModel_Left
    {
        get { return _selectedModel_left; }
        set
        {
            SetProperty(ref _selectedModel_left, value);
        }
    }

    private MLModel _selectedModel_right;
    public MLModel SelectedModel_Right
    {
        get { return _selectedModel_right; }
        set
        {
            SetProperty(ref _selectedModel_right, value);
        }
    }

The only thing I can think of is that they are both referencing the same object in the collection, but I'm not exactly sure how it causes this behavior. Also the desired behavior is that each combobox be able to select and display a different item from the same collection.

Any explanation would be helpful as well as the recommended way to decouple the two comboboxes selection from each other.

EDIT : As requested here is the code to create a minimal working example

MainWindow.xaml

<Window x:Class="WpfApplication3.MainWindow"
        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"
        xmlns:local="clr-namespace:WpfApplication3"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel Orientation="Vertical">
            <ComboBox ItemsSource="{Binding Path=modelsView}" SelectedItem="{Binding SelectedModel_Left}" >
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Name}"></TextBlock>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <ComboBox ItemsSource="{Binding Path=modelsView}" SelectedItem="{Binding SelectedModel_Right}" >
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Name}"></TextBlock>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication3
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new ViewModel();
        }
    }
}

MLModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfApplication3
{
    public class MLModel
    {
        public string Name { get; set; }
        public string Type { get; set; }
    }
}

ViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace WpfApplication3
{
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public ViewModel()
        {
            modelsView = new ListCollectionView(All_Models);
            //modelsView.Filter = modelsFilter;
        }
        public ListCollectionView modelsView { get; set; }

        public ObservableCollection<MLModel> All_Models { get; set; } = new ObservableCollection<MLModel>() {
            new MLModel() { Name = "One", Type = "TypeOne" },
            new MLModel() {Name = "Two", Type = "TypeTwo" },
            new MLModel() {Name = "Three", Type = "TypeThree" }
        };

        private MLModel _selectedModel_left;
        public MLModel SelectedModel_Left
        {
            get { return _selectedModel_left; }
            set
            {
                this._selectedModel_left = value;
                NotifyPropertyChanged();
            }
        }

        private MLModel _selectedModel_right;


        public MLModel SelectedModel_Right
        {
            get { return _selectedModel_right; }
            set
            {
                this._selectedModel_right = value;
                NotifyPropertyChanged();
            }
        }
    }
}

From the documentation :

If the target is an ItemsControl, the current item is synchronized with the selected item.

You are sharing the same ListCollectionView between both ComboBox objects. This means that the current selected item is updated in the view, and replicated in any other ItemsControl where that same view is used.

If you don't want this behavior, you need to give each ComboBox its own ListCollectionView object to bind to.

Alternatively, you can set the IsSynchronizedWithCurrentItem property of each ComboBox to false .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM