我正在尝试通过选择列表框中的项目来更改组合框中显示的项目。 我在列表框中选择了不同的项目,但组合框不会显示任何项目。 组合框应填充类型。在下面你看到我做的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));
}
}
}
答案 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));
}
}