将ListBox绑定到另一个ListBox

时间:2011-12-09 17:58:05

标签: wpf data-binding mvvm listbox

我有2个listBox,如果你单击顶部的一个项目,那么底部的一个过滤到一些结果。 我正在尝试学习WPF和MVVM,我想知道这是否是正确的方法。这是最好的方式吗?

这是我做的:

class VisitInfoViewModel : ViewModelBase
{
    List<ServiceType> serviceTypes;
    List<ServiceType> allServiceTypes;
    public VisitInfoViewModel()
    {
        ServiceCategories = ServiceCategory.Categories;
        allServiceTypes = ServiceType.ServiceTypes;
    }

    public List<ServiceCategory> ServiceCategories { get; set; }
    public List<ServiceType> ServiceTypes 
    {
        get
        {
            return serviceTypes;
        }
    }

    public ServiceCategory SelectedServiceCategory
    {
        get { return null; }
        set
        {
            serviceTypes = allServiceTypes.FindAll(st => st.ServiceCategoryGuid.Equals(value.Guid));
            OnPropertyChanged("ServiceTypes");
        }
    }
}

和MainWindow.xaml代码段

<ListBox ItemsSource="{Binding Path=VisitInfo.ServiceCategories}" 
         SelectedItem="{Binding Path=VisitInfo.SelectedServiceCategory}" 
         ItemTemplate="{StaticResource listBoxTemplate}"  
         Height="112" 
         HorizontalAlignment="Left" 
         Margin="6,30,0,0" 
         Name="lbxServiceCategory" 
         VerticalAlignment="Top" 
         Width="366" />

<ListBox ItemsSource="{Binding Path=VisitInfo.ServiceTypes}" 
         ItemTemplate="{StaticResource listBoxTemplate}" 
         HorizontalAlignment="Left" 
         Margin="6,0,0,19" 
         Name="lbxServiceType" 
         Width="366" 
         Height="121"
         VerticalAlignment="Bottom" />

另外,为什么我不应该在listBox上为selectedItemChanged添加一个EventHandler? 使用事件处理程序似乎更简单,更清晰。 我认为这是因为如果我这样做它将不再是MVVM ......这是正确的吗? 你会做什么,最佳做法是什么?

1 个答案:

答案 0 :(得分:0)

你正在做的事情大部分时间都很好 - 尽管我会亲自将SelectedServiceCategory变成一个“真正的”属性(带有保存的值)。

与MVVM的不同之处在于,您在处理代码时,是在处理数据。如果您使“当前类别”更改类型,那么您将完全使用数据,而不必担心UI。您可以通过任何机制更改类别,UI将始终保持最新。

我个人建议写这个更像:

class VisitInfoViewModel : ViewModelBase
{
    List<ServiceType> allServiceTypes;
    public VisitInfoViewModel()
    {
        ServiceCategories = ServiceCategory.Categories;
        allServiceTypes = ServiceType.ServiceTypes;
    }

    // This can use a private setter...
    public IEnumerable<ServiceCategory> ServiceCategories { get; private set; }

    private ServiceCategory currentCategory;
    public ServiceCategory CurrentServiceCategory
    {
        get { return this.currentCategory; }
        set
        {
            if (this.currentCategory != value)
            {
                this.currentCategory = value;
                ServiceTypesInCurrentCategory = allServiceTypes.Where(st => st.ServiceCategoryGuid.Equals(this.currentCategory.Guid));
                OnPropertyChagned("CurrentServiceCategory");
                OnPropertyChanged("ServiceTypes");
            }
        }
    }

    public IEnumerable<ServiceType> ServiceTypesInCurrentCategory { get; private set; }
}

这样可以完全自由地在代码中或通过Xaml更改CurrentServiceCategory,而无需任何事件处理程序。它还使您的ViewModel完全与数据相关 - 您不知道或不关心用于显示此内容的内容 - 只要您在View中设置了某些来设置CurrentServiceCategory,所有内容保持同步正确。

  

另外,为什么我不应该在listBox上为selectedItemChanged添加一个EventHandler?使用事件处理程序似乎更简单,更清晰。我认为这是因为如果我这样做它将不再是MVVM ......这是正确的吗?

可以这样做,但此时通常违反了MVVM。主要问题是您要将实现与该事件处理程序相结合 - 通过这样做,您基本上“锁定”了View中针对此特定View实现的代码的行为。通过在MVVM方面保持“纯粹”,你可以自由地改变View(即:你可能希望有一天切换到ServiceCategories的组合框),而根本不会触及你的ViewModel代码......