IsSynchronizedWithCurrentItem 属性和当前项目更新

发布于 2024-08-12 17:57:15 字数 2660 浏览 1 评论 0 原文

我有一个视图模型来管理对话框类型的视图,允许过滤列表(如果需要)和选择项目。无论我是否将 IsSynchronizedWithCurrentItem 设置为 true,代码都可以正常工作。我的理解是,这个属性在 ListView 中默认不是 true,所以我想更好地理解这个属性。

以下是视图的 xaml 中的绑定设置(在没有同步属性设置的情况下也能正常工作):

    <ListView  
          ItemsSource="{Binding Projects.View}" 
          IsSynchronizedWithCurrentItem="True"
          SelectedItem="{Binding SelectedProject, Mode=TwoWay}"             
                      >

视图模型 Projects 实际上是一个由私有 ObservableCollection 支持的 CollectionViewSource。我想我是从 Josh Smith 的一个示例项目中记住了这个想法的,但老实说我现在不记得了。下面是与 xaml 绑定相关的 VM 的相关部分:

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; }

CollectionViewSource 的 Filter 属性有一个处理程序,该处理程序返回列表中视图模型项的各种谓词,这些谓词由绑定正确拾取。以下是该代码的要点(位于同一个 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 是多余的,因为默认情况下 ListView 的 SelectedItem 绑定是两种方式,但我不介意明确说明它(我可能有不同的感觉)一旦我更好地理解 WPF)。

我的代码如何使 IsSynchronizedWithCurrentItem=True 变得多余?

我的直觉是,这是不错的代码,但我不喜欢它的那些部分似乎是通过“魔法”工作的,这意味着我欢迎任何建设性的反馈!

干杯,
贝里尔

I have a view model to manage a dialog type of view that allows filtering of a listing (if necessary) and selection of an item. The code works fine whether I set IsSynchronizedWithCurrentItem to true or not. My understanding is that this property is not true by default in a ListView, so I'd like to better understand this property.

Here is the binding setup in the view's xaml (which works just as well without the synch property setting):

    <ListView  
          ItemsSource="{Binding Projects.View}" 
          IsSynchronizedWithCurrentItem="True"
          SelectedItem="{Binding SelectedProject, Mode=TwoWay}"             
                      >

The view model Projects is actually a CollectionViewSource that is backed by a private ObservableCollection. I think I glommed this idea from a sample project of Josh Smith's, but I honestly don't recall right now. Here is the relevant portion of the VM that relates to the xaml binding:

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; }

The Filter property of the CollectionViewSource has a handler which returns various predicates on the view model items in the list which is picked up by the bindings correctly. Here is the gist of that code (which is in the same 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;
    }

Setting the Mode=TwoWay is redundant since the ListView's SelectedItem binding is two way by default, but I don't mind being explicit about it (I might feel differently about that once I understand WPF better).

What about my code is making the IsSynchronizedWithCurrentItem=True redundant?

My gut is that this is decent code, but I don't like that pieces of it seem to be working via "magic", which means I would welcome any constructive feedback!

Cheers,
Berryl

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你的他你的她 2024-08-19 17:57:15

IsSynchronizedWithCurrentItem 同步 < 的 >CurrentItem绑定集合的 code>CollectionView 与控件的 SelectedItem

由于您从不使用 CollectionViewCurrentItem 并且您似乎没有两次绑定到同一个集合,因此设置相关属性根本没有可见的效果。


属性如何同步的演示(适用于 XAMLPad 等 XAML 查看器):

<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>

IsSynchronizedWithCurrentItem syncs the CurrentItem of the default CollectionView of the bound collection with the SelectedItem of your control.

Since you never use the CurrentItem of the CollectionView and you do not appear to bind to the same collection twice, setting the property in question has no visible effect at all.


Demo of how the property syncs (for XAML viewers like 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文