我希望我的 MVVM 表单中的组合框在绑定数据更改后立即刷新显示当前所选项目的选择框和当前所选项目的下拉列表项。我不能让这发生。刷新图片也很重要。
示例表单有 2 个显示预加载人员的组合框和一个用于添加人员的按钮和一个用于更改现有人员的某些数据的按钮。单击该按钮时,该Person.Type
字段会随机更改一些,并且将不同的图片文件字符串存储在Person.PicFullPath
.
<Window x:Class="combobox_test__01.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:combobox_test__01"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="420" WindowStartupLocation="CenterScreen">
<Window.Resources>
<local:VM x:Key="vm" />
<DataTemplate x:Key="cboTemplate" >
<StackPanel Orientation="Horizontal">
<Border Height="80" Width="80" >
<Image>
<Image.Source>
<PriorityBinding>
<Binding Path="PicFullPath" Mode="TwoWay"/>
</PriorityBinding>
</Image.Source>
</Image>
</Border>
<Canvas Height="80" Width="160" >
<StackPanel>
<TextBlock HorizontalAlignment="Left" Height="16" Text="{Binding Path=Name, Mode=TwoWay}" />
<TextBlock HorizontalAlignment="Left" Height="16" Text="{Binding Path=Type, Mode=TwoWay}" />
</StackPanel>
</Canvas>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<Binding Source="{StaticResource vm}" />
</Window.DataContext>
<Grid>
<ComboBox Name="cbo1" IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left" Margin="19,11,0,0" VerticalAlignment="Top" Width="159"
ItemsSource="{Binding People}"
SelectedItem="{Binding SelectedPerson}"
DisplayMemberPath="Type" />
<Button Content="New Row" HorizontalAlignment="Left" Margin="224,11,0,0" VerticalAlignment="Top" Width="142"
Command="{Binding NewRowCommand}" />
<Button Content="Change current row data" HorizontalAlignment="Left" Margin="224,48,0,0" VerticalAlignment="Top" Width="142"
Command="{Binding AlterRowCommand}" />
<ComboBox Name="cbo2" IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left" Margin="19,130,0,0" VerticalAlignment="Top" Width="159" Height="82"
ItemsSource="{Binding People}"
SelectedItem="{Binding SelectedPerson}"
ItemTemplate="{StaticResource cboTemplate}" />
</Grid>
</Window>
using myAssemblies;
using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.ComponentModel;
namespace combobox_test__01
{
public class VM : INotifyPropertyChanged
{
private ObservableCollection<Person> people;
public ObservableCollection<Person> People
{
get { return people; }
set
{
people = value;
OnPropertyChanged("People");
}
}
private Person selectedPerson;
public Person SelectedPerson
{
get { return selectedPerson; }
set
{
selectedPerson = value;
OnPropertyChanged("SelectedPerson");
People = People;
}
}
private int idx = 0;
private string[,] newP;
private string DefaultPic = @"D:\Visual Studio Testing\Icons\user-icon.png",
NewPic = @"D:\Visual Studio Testing\Small size pictures\mugshot";
private Random random = new Random();
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
public VM()
{
People = new ObservableCollection<Person>()
{
new Person() {Name="Aa", Type="Taa", PicFullPath=DefaultPic},
new Person() {Name="Bb", Type="Tbb", PicFullPath=DefaultPic},
new Person() {Name="Cc", Type="Tcc", PicFullPath=DefaultPic}
};
newP = new string[4, 3] { { "Dd", "Tdd", "" }, { "Ee", "Tee", "" }, { "Ff", "Tff", "" }, { "Gg", "Tgg", "" } };
}
public ICommand AlterRowCommand => new RelayCommandBase(AlterRow);
private void AlterRow(object parameter)
{
//Make SelectedPerson.Type into a string ending with 2 randomish digits
string fmts, picChoice;
GetDifferentData(out fmts, out picChoice);
string s = SelectedPerson.Type.Substring(0,3).PadRight(5);
SelectedPerson.Type = s + fmts;
// Use those 2 randomish digits to choose a picture from existing ones
SelectedPerson.PicFullPath = NewPic + picChoice;
// Force both setters to execute
SelectedPerson = SelectedPerson;
}
public ICommand NewRowCommand => new RelayCommandBase(NewRow);
private void NewRow(object parameter)
{
string fmts, picChoice;
GetDifferentData(out fmts, out picChoice);
People.Add(new Person() { Name = newP[idx, 0], Type = newP[idx++, 1], PicFullPath = NewPic + picChoice });
}
private void GetDifferentData(out string fmts, out string picChoice)
{
int randomi = random.Next(1, 35);
fmts = randomi.ToString("D2");
picChoice = fmts + ".jpg";
}
}
public class Person
{
public string Name { get; set; }
public string Type { get; set; }
public string PicFullPath { get; set; }
}
}
这是行为:
运行应用程序
视图模型处于状态 1
单击“更改当前行数据”
视图模型处于状态 2
没有可见变化:我希望选择框显示更改的Type
数据和不同的图片
点击组合框 cbo1
下拉列表显示People.Type
. 选择框仍然显示旧数据。
点击组合框cbo2
下拉列表显示变化People.Type
和不同的图片。选择框仍然显示旧数据。
再次单击“更改当前行数据”而不移动所选项目。
视图模型处于状态 3。
没有可见的变化:随着下拉列表收回,表单看起来与初始化时相同。
点击组合框 cbo1
下拉列表仍显示第一次更改的People.Type
,但People.Type
已再次更改。选择框仍然显示原始数据。
单击组合框 cbo2
下拉列表自上次删除后未更改。选择框仍然显示原始数据。
视图模型中的状态发生了 3 次更改,但组合框在选择框中显示状态 1,在下拉列表中显示状态 2。我希望他们在两个地方都显示状态 3。
单击组合框 cbo1 并选择另一个项目,然后选择第一个项目。所以我们已经移动了选定的项目并将其移回。
两个组合框都在选择框中显示最新数据,
下拉列表已过时。两者都显示状态 2,因此更改选择并将其更改回并没有更改下拉列表中显示的数据。
单击“新行”
视图模型处于状态 4
无可见变化:正如预期的那样 - 未选择新人员,因此不会有可见变化。
单击组合框
下拉列表中显示新人,但第一项仍显示状态 2。
没有点击将使下拉列表在第一次更改后显示更改 - 它们卡在显示状态 2。
如何使选择框和下拉列表始终显示最新数据?