Я хочу, чтобы поля со списком в моей форме 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.
Как сделать так, чтобы в полях выбора и раскрывающихся списках всегда отображались самые свежие данные?