如何从绑定到CollectionViewSource的Listbox中找到正确的项目

时间:2011-09-08 13:58:45

标签: c# wpf mvvm listbox

我有一个ListBox,其ItemsSource绑定到一个CollectionViewSource,它绑定到一个ObservableCollection。

ListBoxItem的模板包含一个 CheckBox ,如果选中,则表示该项已被选中。

我的问题是,我不知道如何找出哪些项目点击了CheckBox。

1 个答案:

答案 0 :(得分:1)

绑定的复选框是什么?如果它绑定到集合中对象的属性,则您不需要确定单击了哪个Checkbox。如果它没有绑定到对象或ViewModel上的某些内容,您可以从列表框中获取SelectedItem。

以前我已经将listBox的SelectedItem属性绑定到我的ViewModel上的属性,这样我就可以随时更改它。

关于获取索引,您应该能够将列表框中返回的idex与CollectionViewSource.View中项目的索引进行匹配,该项目包含按照显示顺序显示的集合的当前视图。

如果您不使用MVVM,我会建议。我开始没有使用它,很快陷入了代码隐藏的困境。

MVVM中的示例

假设我们有MyClass有三个字符串属性和一个布尔值。在MVVM中,我们有一个MyClassViewModel,它具有一个包含MyClass实例的属性以及View所需的任何功能(在本例中为listboxitem)。我们还有一个MyWindowViewModel,它将保存数据集合,以及我们主视图的其他内容。

<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>

示例ViewModels

Public Class MainViewModel
    Inherits ViewModelBase

    Public Property MyClassCollection as New ObservableCollection(Of MyClassViewModel)

End Class

Public Class MyClassViewModel
    Inherits ViewModelBase

    Public Property ModelClass as MyClass

    Public Sub New()
    End Sub
    Public Sub New(ByRef CustClass as MyClass)
        ModelClass = CustClass
    End Sub

End Class

当我们获取数据时,我们将它放在ObservableCollection(Of MyClassViewModel)中。我通常在WorkCompleted处理程序中为数据检索后台工作者执行此操作。

   For Each mc as MyClass in e.Results
      MyClassCollection.Add(New MyClassViewModel(mc)
   Next

列表框仍会通过collectionViewSource从observable集合中获取它的项目,但现在它们的类型为MyClassViewModel。

<DataTemplate DataType="{x:Type local:MyClassViewModel}">
    <Border BorderBrush="#FF036200" BorderThickness="1" Background="#FF3CC600" CornerRadius="10">
        <Grid Height="Auto" Margin="4" DataContext={Binding ModelClass}>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.5*"/>
                <ColumnDefinition Width="0.5*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="0.5*"/>
                <RowDefinition Height="0.5*"/>
            </Grid.RowDefinitions>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding StringProp1}" VerticalAlignment="Top" Margin="0" FontSize="16"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding StringProp2}" VerticalAlignment="Top" Margin="0" Grid.Row="1" FontSize="16"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding StringProp3}" VerticalAlignment="Top" Grid.Column="1" Margin="0" FontSize="16"/>
            <CheckBox Content="Is Bool True?" HorizontalAlignment="Left" IsChecked="{Binding BoolProp}" VerticalAlignment="Top" Grid.Column="1" Margin="0" Grid.Row="1" FontSize="16"/>
        </Grid>
    </Border>
</DataTemplate>

因此,当有人单击该复选框时,它会更改下面对象的值,并且由于列表框项表示ViewModel,如果要更改ListBoxItem上的内容,请将其数据绑定到ViewModel上的属性并更改该属性。

例如,假设您想要在用户选中复选框时将ListBoxItem的颜色更改为随机颜色(并且无论出于何种原因您不想使用触发器等等。您可以创建属性它的类型为Brush和Databind的MyClassViewModel和它的Border.Background,以及一个将MyClass属性设置为相同值的Boolean属性。在boolean属性的setter中,检查值,如果为true,则设置画笔值(不包括随机画笔生成器)。

通过这种方式,ViewModel告诉视图如何在模型中显示数据,并且可以截取View中的datachanges并在必要时对其执行某些操作。

<DataTemplate DataType="{x:Type local:MyClassViewModel}">
        <Border BorderBrush="#FF036200" BorderThickness="1" Background="{Binding BorderBackground}" CornerRadius="10">

回复评论

每个人都有自己的做MVVM的方式。我使用了几种不同的ViewModel。有些实际上是表单视图模型(用于控制表单的工作方式),模型视图模型(用于告诉视图[通常是用户控件用于编辑详细信息,或者用于控制项目控件DataTemplate]如何显示数据)。使用表单视图模型,我有时会根据情况将它们分解为NavigationViewModel和Record Maintenance ViewModels。

在这种情况下,我确实有一个用于控制表单的ViewModel和一个用于显示数据的Viewmodel。表单视图模型通常处理用于添加或删除集合中的项目的按钮命令,或指定告诉View是否启用了保存或其他操作按钮的逻辑。

INotifyPropertyChanged的

实现INPC的非常轻的ViewModelBase类

Imports System.ComponentModel

Public MustInherit Class ViewModelBase
    Implements INotifyPropertyChanged

    Public Event PropertyChanged As PropertyChangedEventHandler _
        Implements INotifyPropertyChanged.PropertyChanged

    Protected Sub OnPropertyChanged(ByVal info As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    End Sub

End Class

在继承的ViewModel中:

Public Property IsSelected() As Boolean
    Get
        Return m_IsSelected
    End Get
    Set(ByVal value As Boolean)
        m_IsSelected = value
        OnPropertyChanged("IsSelected")
    End Set
End Property