【问题标题】:What is the easiest way to handle SelectedItem event with MVVM?使用 MVVM 处理 SelectedItem 事件的最简单方法是什么?
【发布时间】:2010-11-03 22:45:33
【问题描述】:

在下面的代码中,当用户在组合框中选择客户时,客户的姓名会显示在文本框中。我使用 ViewModel 上的 ObservableCollection 属性填充 Combox 框,但如何处理 ViewModel 中的 SelectedItem 事件?

使用如下所示的代码隐藏很容易实现这一点,但是如何使用 MVVM 模式来实现这一点?

我目前在我的基本 MVVM 模板中有 DelegateCommandAttachedBehaviors 可以使用,但我不知道如何让它们在“组合框选择”时触发一个新项目”。

查看:

<Window.Resources>
    <DataTemplate x:Key="CustomerTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding LastName}"/>
        </StackPanel>
    </DataTemplate>
</Window.Resources>

<DockPanel LastChildFill="False" Margin="10">
    <ComboBox 
        x:Name="CustomerList"
        ItemTemplate="{StaticResource CustomerTemplate}"
        HorizontalAlignment="Left"
        DockPanel.Dock="Top" 
        Width="200"
        SelectionChanged="CustomerSelected"
        ItemsSource="{Binding Customers}"/>

    <TextBlock x:Name="CurrentlySelectedCustomer"/>
</DockPanel>

代码隐藏:

private void CustomerSelected(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
    Customer customer = (Customer)CustomerList.SelectedItem;
    CurrentlySelectedCustomer.Text = String.Format("{0} {1}", customer.FirstName, customer.LastName);
}

【问题讨论】:

    标签: wpf mvvm selecteditem


    【解决方案1】:

    您应该能够将 ViewModel 中的属性绑定到组合框的 SelectedItem 属性。如果您将其设置为双向绑定,您将在 SelectedItem 更改时收到通知,因为它将触发属性上的 set 方法。

    视图模型:

    public ObservableCollection Customers
    {
       get { return _customers; }
       set
       {
           if (_customers != value)
           {
               _customers = value;
               OnPropertyChanged("Customers");
           }
       }
    }
    
    public Customer SelectedCustomer
    {
       get { return _selectedCustomer; }
       set
       {
           if (_selectedCustomer != value)
           {
               _selectedCustomer= value;
               LastName= value.LastName;
               OnPropertyChanged("SelectedCustomer");
           }
       }
    }
    
    public Customer LastName
    {
       get { return _lastName; }
       set
       {
           if (_lastName!= value)
           {
               _lastName= value;
               OnPropertyChanged("LastName");
           }
       }
    }
    

    Xaml:

    <DockPanel LastChildFill="False" Margin="10">
        <ComboBox 
            x:Name="CustomerList"
            ItemTemplate="{StaticResource CustomerTemplate}"
            HorizontalAlignment="Left"
            DockPanel.Dock="Top" 
            Width="200"
            SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}"
            ItemsSource="{Binding Customers}"/>
    
        <TextBlock x:Name="CurrentlySelectedCustomer"
                   Text="{Binding LastName}"/>
    </DockPanel>
    

    【讨论】:

    • 正是我要找的,不知道这么简单,谢谢
    • 请记住,这会在您的 V/VM 之间产生依赖关系...如果您在没有视图的情况下测试此代码,CurrentlySelectedCustomer 将永远不会更新!如果您使用 CollectionView... 即使您的视图没有绑定回 VM,它也能正常工作!
    • 总的来说,我同意 CollectionView 有一些优势(尽管当您想将同一个列表绑定到多个选择器时有一些限制条件),但我认为您的评论不正确。我的版本没有比你更多的依赖,例如,如果我想编写一个测试来检查 LastName 属性是否正确更新,我不需要视图,我可以通过测试代码设置 SelectedCustomer 属性。跨度>
    • 同意...两者都可以正常工作!我能看到的唯一另一个问题是,如果你想使用一个不同的视图......你必须记住绑定回选定的项目!我的方法有一个类似的问题,因为在我看来,您必须记住将 IsSyncronizedWithCurrent 设置为 true!我绝对喜欢你的 solotion,在某些情况下它肯定会起作用我只是不喜欢依赖于视图......使用 CV 只是更解耦!
    【解决方案2】:

    查看 www.codeproject.com 上的 this 应用程序。这里我使用CollectionView来检测当前选中的item

    更新

    使用 CollectionView 检测当前选中项

    ListCollectionView view = (ListCollectionView)CollectionViewSource.GetDefaultView(Customers); 
    view.CurrentChanged += delegate 
    { 
        SelectedCustomer= (Customer)view.CurrentItem; 
    };
    

    记住也要设置 IsSynchronizedWithCurrentItem="True"

    【讨论】:

    • +1 表示需要IsSynchronizedWithCurrentItem="True"。经过一个小时试图弄清楚为什么 CurrendChanged 从未在我的代码中被解雇后,你已经拯救了这一天。
    猜你喜欢
    • 1970-01-01
    • 2010-09-23
    • 2010-12-27
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-17
    相关资源
    最近更新 更多