如何在列表框中选择项目时更改组合框中的选定项目

时间:2017-05-24 11:03:03

标签: c# wpf mvvm combobox listbox

我正在尝试通过选择列表框中的项目来更改组合框中显示的项目。 我在列表框中选择了不同的项目,但组合框不会显示任何项目。 组合框应填充类型。在下面你看到我做的xaml和c#代码只是让这个工作。你们有什么想法吗? c#代码是一个ViewModel,所以我没有任何代码隐藏,并希望保持这种方式,我正在使用MVVM。

我正在看这个问题几天,所以任何帮助都会感激不尽。

这是我的xaml代码:

<Window x:Class="Databinding.Wpf.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:Databinding.Wpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:TestViewModel></local:TestViewModel>
    </Window.DataContext>
    <StackPanel>
        <ListBox Name="lsbPkmn" Height="150" ItemsSource="{Binding Pokémons}" DisplayMemberPath="Name" SelectedIndex="0"
                 SelectedValuePath="Type" SelectedValue="{Binding SelectedType}"/>
        <TextBlock Text="{Binding ElementName=lsbPkmn, Path=SelectedItem.Name}"/>
        <ComboBox Name="cmbType" Margin="50" ItemsSource="{Binding Types}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedType}"/>
    </StackPanel>
</Window>

这是我的C#代码:

using System.Collections.ObjectModel;
using System.ComponentModel;

namespace Databinding.Wpf
{
    public class TestViewModel : INotifyPropertyChanged
    {
        public TestViewModel()
        {
            Pokémons = new ObservableCollection<Pokémon>
            {
                new Pokémon {Id = 1, Name = "Bulbasaur", Type = new Type {Id = 1, Name = "Grass"}},
                new Pokémon {Id = 4, Name = "Charmander", Type = new Type {Id = 2, Name = "Fire"}},
                new Pokémon {Id = 7, Name = "Squirtle", Type = new Type {Id = 3, Name = "Water"}},
                new Pokémon {Id = 25, Name = "Pikachu", Type = new Type {Id = 4, Name = "Electric"}},
                new Pokémon {Id = 2, Name = "Ivysaur", Type = new Type {Id = 1, Name = "Grass"}}
            };

            Types = new ObservableCollection<Type>
            {
                new Type {Id = 1, Name = "Grass"},
                new Type {Id = 2, Name = "Fire"},
                new Type {Id = 3, Name = "Water"},
                new Type {Id = 4, Name = "Electric"}
            };
        }

        private ObservableCollection<Pokémon> _pokémons;

        public ObservableCollection<Pokémon> Pokémons
        {
            get { return _pokémons; }
            set
            {
                _pokémons = value;
                OnPropertyChanged(nameof(Pokémons));
            }
        }

        private ObservableCollection<Type> _types;

        public ObservableCollection<Type> Types
        {
            get { return _types; }
            set
            {
                _types = value;
                OnPropertyChanged(nameof(Types));
            }
        }


        private Type _selectedType;

        public Type SelectedType
        {
            get { return _selectedType; }
            set
            {
                _selectedType = value;
                OnPropertyChanged(nameof(SelectedType));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

神奇宝贝课程:

using System.ComponentModel;

namespace Databinding.Wpf
{
    public class Pokémon : INotifyPropertyChanged
    {
        private int _id;

        public int Id
        {
            get { return _id; }
            set
            {
                _id = value;
                OnPropertyChanged(nameof(Id));
            }
        }

        private string _name;

        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged(nameof(Name));
            }
        }

        private Type _type;

        public Type Type
        {
            get { return _type; }
            set
            {
                _type = value;
                OnPropertyChanged(nameof(Type));
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

键入类:

using System.ComponentModel;

namespace Databinding.Wpf
{
    public class Type : INotifyPropertyChanged
    {
        private int _id;

        public int Id
        {
            get { return _id; }
            set
            {
                _id = value; 
                OnPropertyChanged(nameof(Id));
            }
        }

        private string _name;

        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged(nameof(Name));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

3 个答案:

答案 0 :(得分:0)

您需要在发生更改时通知SelectedType。你可以这样做

SelectedItem="{Binding SelectedType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

您还需要实现OnPropertyChanged - 本文http://www.blackwasp.co.uk/INotifyPropertyChanged.aspx介绍了如何执行此操作。

如果您为ComboBox和ListBox执行此操作,则在一个中更改选择应更改另一个中的选择。

如果这不是您想要的,您可以更改Mode变量;本文http://www.blackwasp.co.uk/WPFBindingOptions.aspx详细介绍了您的选项。

答案 1 :(得分:0)

问题出在这里......

    <ComboBox Name="cmbType" Margin="50" ItemsSource="{Binding Types}" DisplayMemberPath="Name" SelectedValuePath="Id" SelectedValue="{Binding SelectedType.Id}"/>

您的代码无效的原因是组合框项目列表中不存在所选的类型对象。该比较通过参考完成。所以你需要使用SelectedValue和SelectedValuePath。

顺便说一下,更改类Type的名称。这会给你带来很多问题。

答案 2 :(得分:0)

你可以做这样的事情:

Xaml 设为:

包含命名空间:

xmlns:System="clr-namespace:System;assembly=mscorlib"

<Window.Resources>
    <ObjectDataProvider x:Key="dataFromEnum"
                        MethodName="GetValues"
                        ObjectType="{x:Type System:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="local:Types" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>
<StackPanel>
    <ListBox Name="lsbPkmn"
             Height="150"
             ItemsSource="{Binding Pokémons}"
             DisplayMemberPath="Name"
             SelectedIndex="0"
             SelectedItem="{Binding SelectedPokemon}"/>
    <TextBlock Text="{Binding ElementName=lsbPkmn, Path=SelectedItem.Name}"/>
    <ComboBox Name="cmbType"
              Margin="50"
              ItemsSource="{Binding Source={StaticResource dataFromEnum}}"
              SelectedItem="{Binding SelectedPokemon.Types}" IsSynchronizedWithCurrentItem="True"/>
</StackPanel>

Types只是单独的Enum类。

public enum Types
{
    Grass,
    Fire,
    Water,
    Electric,
};

这就是ViewModel现在的样子

public class TestViewModel : INotifyPropertyChanged
{
    public TestViewModel ()
    {
        Pokémons = new ObservableCollection<Pokémon>
        {
            new Pokémon {Id = 1, Name = "Bulbasaur", Types= Types.Grass },
            new Pokémon {Id = 4, Name = "Charmander",Types=  Types.Fire},
            new Pokémon {Id = 7, Name = "Squirtle", Types= Types.Water},
            new Pokémon {Id = 25, Name = "Pikachu",Types=  Types.Electric},
            new Pokémon {Id = 2, Name = "Ivysaur", Types= Types.Grass}
        };

    }

    private ObservableCollection<Pokémon> _pokémons;

    public ObservableCollection<Pokémon> Pokémons
    {
        get { return _pokémons; }
        set
        {
            _pokémons = value;
            OnPropertyChanged(nameof(Pokémons));
        }
    }


    private Pokémon _selectedPokemon;

    public Pokémon SelectedPokemon
    {
        get { return _selectedPokemon; }
        set
        {
            _selectedPokemon = value;
            OnPropertyChanged();
        }
    }



    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    public virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

}