Атрибут IsSynchronizedWithCurrentItem и текущие обновления элементов
-
10-07-2019 - |
Вопрос
У меня есть модель представления для управления представлением диалогового типа, которое позволяет фильтровать список (при необходимости) и выбирать элемент.Код работает нормально независимо от того, установил ли я для IsSynchronizedWithCurrentItem значение true или нет.Насколько я понимаю, это свойство по умолчанию не соответствует действительности в ListView, поэтому я хотел бы лучше понять это свойство.
Вот настройка привязки в xaml представления (которая работает так же хорошо без настройки свойства синхронизации):
<ListView
ItemsSource="{Binding Projects.View}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedProject, Mode=TwoWay}"
>
Модель представления Projects на самом деле представляет собой CollectionViewSource, поддерживаемый частной ObservableCollection.Кажется, я почерпнул эту идею из примера проекта Джоша Смита, но, честно говоря, сейчас не припоминаю.Вот соответствующая часть виртуальной машины, относящаяся к привязке xaml:
private ObservableCollection<ProjectViewModel> _projectsInternal { get; set; }
public CollectionViewSource Projects { get; set; }
private void _populateProjectListings(IEnumerable<Project> openProjects) {
var listing = (from p in openProjects
orderby p.Code.ToString()
select new ProjectViewModel(p)).ToList();
foreach (var pvm in listing)
pvm.PropertyChanged += _onProjectViewModelPropertyChanged;
_projectsInternal = new ObservableCollection<ProjectViewModel>(listing);
Projects = new CollectionViewSource {Source = _projectsInternal};
}
/// <summary>Property that is updated via the binding to the view</summary>
public ProjectViewModel SelectedProject { get; set; }
Свойство Filter объекта CollectionViewSource имеет обработчик, который возвращает различные предикаты для элементов модели представления в списке, которые правильно подбираются привязками.Вот суть этого кода (который находится в той же ProjectSelctionViewModel):
/// <summary>Trigger filtering of the <see cref="Projects"/> listing.</summary>
public void Filter(bool applyFilter)
{
if (applyFilter)
Projects.Filter += _onFilter;
else
Projects.Filter -= _onFilter;
OnPropertyChanged<ProjectSelectionViewModel>(vm=>vm.Status);
}
private void _onFilter(object sender, FilterEventArgs e)
{
var project = e.Item as ProjectViewModel;
if (project == null) return;
if (!project.IsMatch_Description(DescriptionText)) e.Accepted = false;
if (!project.IsMatch_SequenceNumber(SequenceNumberText)) e.Accepted = false;
if (!project.IsMatch_Prefix(PrefixText)) e.Accepted = false;
if (!project.IsMatch_Midfix(MidfixText)) e.Accepted = false;
if (!project.IsAvailable) e.Accepted = false;
}
Установка Mode=TwoWay является избыточной, поскольку привязка SelectedItem ListView по умолчанию является двусторонней, но я не против сказать об этом явно (я могу относиться к этому по-другому, как только лучше пойму WPF).
А как насчет моего кода, который делает IsSynchronizedWithCurrentItem=True избыточным?
Я считаю, что это достойный код, но мне не нравится, что некоторые его части работают с помощью «магии», а это значит, что я буду рад любой конструктивной обратной связи!
Ваше здоровье,
Беррил
Решение
IsSynchronizedWithCurrentItem
синхронизирует CurrentItem
по умолчанию CollectionView
связанной коллекции с SelectedItem
вашего контроля.
Поскольку вы никогда не используете CurrentItem
принадлежащий CollectionView
и вы, похоже, не привязываетесь к одной и той же коллекции дважды, установка рассматриваемого свойства вообще не имеет видимого эффекта.
Демонстрация того, как синхронизируется свойство (для средств просмотра XAML, например Каксамль или XAMLPad):
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:Array x:Key="Items" Type="{x:Type sys:String}">
<sys:String>Apple</sys:String>
<sys:String>Orange</sys:String>
<sys:String>Pear</sys:String>
<sys:String>Lime</sys:String>
</x:Array>
</Page.Resources>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel Background="Transparent">
<ListBox IsSynchronizedWithCurrentItem="True" ItemsSource="{StaticResource Items}" />
<ListBox IsSynchronizedWithCurrentItem="True" ItemsSource="{StaticResource Items}" />
<!-- This TextBlock binds to the CurrentItem of the Items via the "/" -->
<TextBlock Text="{Binding Source={StaticResource Items}, Path=/}"/>
</StackPanel>
</ScrollViewer>
</Page>