IsSynchronizedWithCurrentItem attribut et mises à jour d'élément en cours
-
10-07-2019 - |
Question
Je dispose d’un modèle de vue pour gérer un type de vue de dialogue qui permet de filtrer une liste (si nécessaire) et de sélectionner un élément. Le code fonctionne correctement, que je mette IsSynchronizedWithCurrentItem sur true ou non. D'après ce que j'ai compris, cette propriété n'est pas vraie par défaut dans un ListView. J'aimerais donc mieux comprendre cette propriété.
Voici la configuration de la liaison dans le xaml de la vue (qui fonctionne aussi bien sans le paramètre de propriété synch):
<ListView
ItemsSource="{Binding Projects.View}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedProject, Mode=TwoWay}"
>
Le modèle de vue Projects est en réalité un CollectionViewSource qui est sauvegardé par un ObservableCollection privé. Je pense que j'ai eu cette idée d'un exemple de projet de Josh Smith, mais honnêtement, je ne m'en souviens pas maintenant. Voici la partie pertinente de la machine virtuelle qui concerne la liaison 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; }
La propriété Filter de CollectionViewSource a un gestionnaire qui renvoie divers prédicats sur les éléments de modèle de vue de la liste, lesquels sont correctement pris en compte par les liaisons. Voici l'essentiel de ce code (qui se trouve dans le même 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;
}
La définition du mode = TwoWay est redondante car la liaison SelectedItem de ListView est bidirectionnelle par défaut, mais cela ne me dérange pas d'être explicite à ce sujet (je pourrais me sentir différent de cela une fois que je comprendrai mieux WPF).
Pourquoi mon code rend-il IsSynchronizedWithCurrentItem = True redondant?
Mon instinct est que c'est un code correct, mais je n'aime pas que certaines de ses parties semblent fonctionner via "magique", ce qui signifie que je serais heureux de recevoir des commentaires constructifs!
À la vôtre,
Berryl
La solution
IsSynchronizedWithCurrentItem
synchronise le . CurrentItem
de la valeur par défaut CollectionView
de la collection liée avec le SelectedItem
de votre contrôle.
Puisque vous n'utilisez jamais le CurrentItem
du CollectionView
et que vous ne semblez pas se lier deux fois à la même collection, la définition de la propriété en question n'a aucun effet visible.
Démonstration de la synchronisation de la propriété (pour les visualiseurs XAML tels que Kaxaml ou 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>