绑定到MVVM从数据网格或列表框SelectedItems [英] Bind to SelectedItems from DataGrid or ListBox in MVVM

查看:472
本文介绍了绑定到MVVM从数据网格或列表框SelectedItems的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

查看我的回答底部

只是在做WPF的一些闲书,我需要绑定一个从DataGrid中selectedItems但我无法拿出实实在在的东西。我只需要选定的对象。

DataGrid的:

 <数据网格Grid.Row =5
    Grid.Column =0
    Grid.ColumnSpan =4
    NAME =ui_dtgAgreementDocuments
    的ItemsSource ={绑定路径=文档,模式=双向}
    的SelectedItem ={绑定路径= DocumentSelection,模式=双向,UpdateSourceTrigger =的PropertyChanged}
    的Horizo​​ntalAlignment =弹力
    VerticalAlignment =弹力
    背景=白
    的SelectionMode =扩展保证金=2,5
    IsReadOnly =真
    CanUserAddRows =假
    CanUserReorderColumns =假
    CanUserResizeRows =假
    GridLinesVisibility =无
    Horizo​​ntalScrollBarVisibility =隐藏
    columnHeaderStyle ={StaticResource的绿茶}
    HeadersVisibility =列
    了borderThickness =2
    BorderBrush =浅灰色
    CellStyle ={StaticResource的NonSelectableDataGridCellStyle}
    SelectionUnit =FullRow
    Horizo​​ntalContentAlignment =弹力的AutoGenerateColumns =FALSE>


解决方案

这将工作:

MultiSelectorBehaviours.vb

  System.Collections中导入
进口System.Windows
进口System.Windows.Controls.Primitives
System.Windows.Controls的进口
进口系统公共NotInheritable类MultiSelectorBehaviours
    私人小组新的()
    结束小组    公共共享只读SynchronizedSelectedItems作为的DependencyProperty = _
        DependencyProperty.RegisterAttached(SynchronizedSelectedItems的GetType(IList的)的GetType(MultiSelectorBehaviours),新PropertyMetadata(没有新PropertyChangedCallback(AddressOf OnSynchronizedSelectedItemsChanged)))    私人共享只读SynchronizationManagerProperty作为的DependencyProperty = DependencyProperty.RegisterAttached(SynchronizationManager的GetType(SynchronizationManager)的GetType(MultiSelectorBehaviours),新PropertyMetadata(没有))    '''<总结>
    '''获取同步选定的项目。
    '''< /总结>
    '''&下; PARAM NAME =DependencyObject的>将依赖物体下; /参数>
    '''<退货和GT;要充当同步列表清单< /回报>
    公共共享功能GetSynchronizedSelectedItems(BYVAL的DependencyObject作为DependencyObject的)作为IList的
        返回DirectCast(dependencyObject.GetValue(SynchronizedSelectedItems)的IList)
    结束功能    '''<总结>
    '''设置同步选定的项目。
    '''< /总结>
    '''&下; PARAM NAME =DependencyObject的>将依赖物体下; /参数>
    '''< PARAM NAME =值>该值被设置为同步的项目< /参数>
    公共共享子SetSynchronizedSelectedItems(BYVAL的DependencyObject作为DependencyObject的,BYVAL值作为IList的)
        dependencyObject.SetValue(SynchronizedSelectedItems,值)
    结束小组    私人共享功能GetSynchronizationManager(BYVAL的DependencyObject作为DependencyObject的)由于SynchronizationManager
        返回DirectCast(dependencyObject.GetValue(SynchronizationManagerProperty),SynchronizationManager)
    结束功能    私人共享子SetSynchronizationManager(BYVAL的DependencyObject作为DependencyObject的,BYVAL值作为SynchronizationManager)
        dependencyObject.SetValue(SynchronizationManagerProperty,值)
    结束小组    私人共享子OnSynchronizedSelectedItemsChanged(BYVAL的DependencyObject作为DependencyObject的,BYVAL E上DependencyPropertyChangedEventArgs)
        如果e.OldValue状态并没有任何再
            昏暗的同步器作为SynchronizationManager = GetSynchronizationManager(DependencyObject的)
            synchronizer.StopSynchronizing()            SetSynchronizationManager(DependencyObject的,没什么)
        万一        昏暗名单的IList = TryCast(e.NewValue,IList的)
        昏暗的选择作为选择= TryCast(DependencyObject的,选择器)        检查这个属性是一个IList,并且它正在一个列表框设置
        如果列表状态并没有任何AndAlso运算选择状态并没有任何再
            昏暗的同步器作为SynchronizationManager = GetSynchronizationManager(DependencyObject的)
            如果同步器没有那么
                同步=新SynchronizationManager(选择)
                SetSynchronizationManager(DependencyObject的,同步器)
            万一            synchronizer.StartSynchronizingList()
        万一
    结束小组    '''<总结>
    '''的同步管理器。
    '''< /总结>
    私有类SynchronizationManager
        私人只读_multiSelector作为选择
        私人_synchronizer作为TwoListSynchronizer        '''<总结>
        '''初始化℃的新的实例;参见CREF =SynchronizationManager/>类。
        '''< /总结>
        '''&下; PARAM NAME =选择方式>该选择器与所述; /参数>
        朋友的Sub New(BYVAL选择为选择器)
            _multiSelector =选择
        结束小组        '''<总结>
        '''启动同步列表。
        '''< /总结>
        公用Sub StartSynchronizingList()
            昏暗名单的IList = GetSynchronizedSelectedItems(_multiSelector)            如果列表状态并没有任何再
                _synchronizer =新TwoListSynchronizer(GetSelectedItemsCollection(_multiSelector),列表)
                _synchronizer.StartSynchronizing()
            万一
        结束小组        '''<总结>
        '''停止同步列表。
        '''< /总结>
        公用Sub StopSynchronizing()
            _synchronizer.StopSynchronizing()
        结束小组        公共共享功能GetSelectedItemsCollection(BYVAL选择作为选择器)作为IList的
            如果TypeOf运算选择是MultiSelector然后
                返回TryCast(选择,MultiSelector).SelectedItems
            elseif的TypeOf运算选择是列表框然后
                返回TryCast(选择器,列表框).SelectedItems
            其他
                抛出新的InvalidOperationException异常(目标对象有没有selectedItems属性绑定。)
            万一
        结束功能    末级
末级

IListItemConverter.vb

 '''<总结>
'''在主列表将转换项目目标列表中的项目,然后再返回。
'''< /总结>
公共接口IListItemConverter
    '''<总结>
    '''指定的主列表项转换。
    '''< /总结>
    '''< PARAM NAME =masterListItem>在主列表项目< /参数>
    '''<返回>将转换的结果< /回报>
    功能转换(BYVAL masterListItem作为对象)作为对象    '''<总结>
    '''指定的目标列表项转换。
    '''< /总结>
    '''&下; PARAM NAME =targetListItem>将目标列表项< /参数>
    '''<返回>将转换的结果< /回报>
    功能ConvertBack(BYVAL targetListItem作为对象)作为对象
结束接口

TwoListSynchronizer.vb

  System.Collections中导入
进口System.Collections.Specialized
进口System.Linq的
进口System.Windows'''<总结>
'''保持同步的两个清单。
'''< /总结>
公共类TwoListSynchronizer
    实现IWeakEventListener    私人共享只读DefaultConverter作为IListItemConverter =新DoNothingListItemConverter()
    私人只读_masterList作为IList的
    私人只读_masterTargetConverter作为IListItemConverter
    私人只读_targetList作为IList的
    '''<总结>
    '''初始化℃的新的实例;参见CREF =TwoListSynchronizer/>类。
    '''< /总结>
    '''< PARAM NAME =masterList>在主列表< /参数>
    '''< PARAM NAME =TARGETLIST>该目标列表< /参数>
    '''< PARAM NAME =masterTargetConverter方式>主靶器< /参数>
    的Public Sub New(BYVAL masterList作为IList的,BYVAL TARGETLIST作为IList的,BYVAL masterTargetConverter作为IListItemConverter)
        _masterList = masterList
        _targetList = TARGETLIST
        _masterTargetConverter = masterTargetConverter
    结束小组    '''<总结>
    '''初始化℃的新的实例;参见CREF =TwoListSynchronizer/>类。
    '''< /总结>
    '''< PARAM NAME =masterList>在主列表< /参数>
    '''< PARAM NAME =TARGETLIST>该目标列表< /参数>
    的Public Sub New(BYVAL masterList作为IList的,BYVAL TARGETLIST作为IList的)
        Me.New(masterList,TARGETLIST,DefaultConverter)
    结束小组    私人代表小组ChangeListAction(BYVAL名单的IList,BYVAL E上NotifyCollectionChangedEventArgs,BYVAL转换器转换器(的对象,对象))    '''<总结>
    '''启动同步列表。
    '''< /总结>
    公用Sub StartSynchronizing()
        ListenForChangeEvents(_masterList)
        ListenForChangeEvents(_targetList)        更新从主列表中的目标列表
        SetListValues​​FromSource(_masterList,_targetList,AddressOf ConvertFromMasterToTarget)        在某些情况下,目标列表可能对哪些项目应列入自己的看法:
        所以,从更新的目标列表主列表
        '(这是与列表框SelectedItems集合的情况下:从的ItemsSource唯一项目可以包括在SelectedItems)
        如果不TargetAndMasterCollectionsAreEqual()然后
            SetListValues​​FromSource(_targetList,_masterList,AddressOf ConvertFromTargetToMaster)
        万一
    结束小组    '''<总结>
    '''停止同步列表。
    '''< /总结>
    公用Sub StopSynchronizing()
        StopListeningForChangeEvents(_masterList)
        StopListeningForChangeEvents(_targetList)
    结束小组    '''<总结>
    '''接收来自集中式事件管理器的事件。
    '''< /总结>
    '''&下; PARAM NAME =managerType>该类型的<参见CREF =T:System.Windows.WeakEventManager/> 。调用此方法< /参数>
    '''< PARAM NAME =发件人>产生事件对象< /参数>
    '''< PARAM NAME =E>事件数据< /参数>
    '''<退货和GT;
    ''如果监听器处理的事件真。它被认为是通过&lt一个错误;见CREF =T:System.Windows.WeakEventManager/>在WPF处理以注册听者不处理事件的侦听器。无论如何,如果它接收到它不能识别或处理事件的方法应返回假。
    '''< /回报>
    公共职能ReceiveWeakEvent(BYVAL managerType类型中,BYVAL发件人为对象,BYVAL E上的EventArgs)为布尔实现System.Windows.IWeakEventListener.ReceiveWeakEvent
        HandleCollectionChanged(TryCast(发件人,IList的),TryCast(即NotifyCollectionChangedEventArgs))        返回TRUE
    结束功能    '''<总结>
    '''侦听名单上更改事件。
    '''< /总结>
    '''< PARAM NAME =名单>该列表收听上述< /参数>
    保护小组ListenForChangeEvents(BYVAL名单的IList)
        如果TypeOf运算列表,然后INotifyCollectionChanged
            CollectionChangedEventManager.AddListener(TryCast(列表,INotifyCollectionChanged),ME)
        万一
    结束小组    '''<总结>
    '''停止侦听改变事件。
    '''< /总结>
    '''< PARAM NAME =名单>该名单停止监听上述< /参数>
    保护小组StopListeningForChangeEvents(BYVAL名单的IList)
        如果TypeOf运算列表,然后INotifyCollectionChanged
            CollectionChangedEventManager.RemoveListener(TryCast(列表,INotifyCollectionChanged),ME)
        万一
    结束小组    私人小组为addItems(BYVAL名单的IList,BYVAL E上NotifyCollectionChangedEventArgs,BYVAL转换器转换器(的对象,对象))
        昏暗ITEMCOUNT作为整数= e.NewItems.Count        对于我作为整数= 0〜ITEMCOUNT - 1
            昏暗insertionPoint作为整数= e.NewStartingIndex + I            如果insertionPoint> list.Count然后
                list.Add(变换器(e.NewItems(ⅰ)))
            其他
                list.Insert(insertionPoint,转换器(e.NewItems(I)))
            万一
        下一个
    结束小组    专用功能ConvertFromMasterToTarget(BYVAL masterListItem作为对象)作为对象
        返回如果(_masterTargetConverter不算什么,masterListItem,_masterTargetConverter.Convert(masterListItem))
    结束功能    专用功能ConvertFromTargetToMaster(BYVAL targetListItem作为对象)作为对象
        返回如果(_masterTargetConverter不算什么,targetListItem,_masterTargetConverter.ConvertBack(targetListItem))
    结束功能    私人小组HandleCollectionChanged(BYVAL发件人为对象,BYVAL E上NotifyCollectionChangedEventArgs)
        昏暗SOURCELIST作为IList的= TryCast(发件人,IList的)        选择案例e.Action
            案例NotifyCollectionChangedAction.Add
                PerformActionOnAllLists(AddressOf为addItems,SOURCELIST,E)
                退出选择
            案例NotifyCollectionChangedAction.Move
                PerformActionOnAllLists(AddressOf MoveItems,SOURCELIST,E)
                退出选择
            案例NotifyCollectionChangedAction.Remove
                PerformActionOnAllLists(AddressOf为removeItems,SOURCELIST,E)
                退出选择
            案例NotifyCollectionChangedAction.Replace
                PerformActionOnAllLists(AddressOf ReplaceItems,SOURCELIST,E)
                退出选择
            案例NotifyCollectionChangedAction.Reset
                UpdateListsFromSource(TryCast(发件人,IList的))
                退出选择
            否则案例
                退出选择
        结束选择
    结束小组    私人小组MoveItems(BYVAL名单的IList,BYVAL E上NotifyCollectionChangedEventArgs,BYVAL转换器转换器(的对象,对象))
        为removeItems(列表,电子,转换器)
        为addItems(列表,电子,转换器)
    结束小组    私人小组PerformActionOnAllLists(BYVAL行动ChangeListAction,BYVAL SOURCELIST作为IList的,BYVAL collectionChangedArgs作为NotifyCollectionChangedEventArgs)
        如果SOURCELIST是_masterList然后
            PerformActionOnList(_targetList,动作,collectionChangedArgs,AddressOf ConvertFromMasterToTarget)
        其他
            PerformActionOnList(_masterList,动作,collectionChangedArgs,AddressOf ConvertFromTargetToMaster)
        万一
    结束小组    私人小组PerformActionOnList(BYVAL名单的IList,BYVAL行动ChangeListAction,BYVAL collectionChangedArgs作为NotifyCollectionChangedEventArgs,BYVAL转换器转换器(的对象,对象))
        StopListeningForChangeEvents(名单)
        行动(列表,collectionChangedArgs,转换器)
        ListenForChangeEvents(名单)
    结束小组    私人小组为removeItems(BYVAL名单的IList,BYVAL E上NotifyCollectionChangedEventArgs,BYVAL转换器转换器(的对象,对象))
        昏暗ITEMCOUNT作为整数= e.OldItems.Count        对于被删除的项目数,从旧的开始索引中删除的项目
        (这将导致以下项目将下移,以填补孔)。
        对于我作为整数= 0〜ITEMCOUNT - 1
            list.RemoveAt(e.OldStartingIndex)
        下一个
    结束小组    私人小组ReplaceItems(BYVAL名单的IList,BYVAL E上NotifyCollectionChangedEventArgs,BYVAL转换器转换器(的对象,对象))
        为removeItems(列表,电子,转换器)
        为addItems(列表,电子,转换器)
    结束小组    私人小组SetListValues​​FromSource(BYVAL SOURCELIST作为IList的,BYVAL TARGETLIST作为IList的,BYVAL转换器转换器(的对象,对象))
        StopListeningForChangeEvents(目标列)        targetList.Clear()        对于每个O作为对象在SOURCELIST
            targetList.Add(转换器(O))
        下一个        ListenForChangeEvents(目标列)
    结束小组    私有函数TargetAndMasterCollectionsAreEqual()为布尔
        返回_masterList.Cast(的对象)()。SequenceEqual(_targetList.Cast(的对象)()。[选择](功能(项目)ConvertFromTargetToMaster(项目)))
    结束功能    '''<总结>
    '''确保所有同步列表有作为源列表相同的值。
    '''< /总结>
    '''< PARAM NAME =SOURCELIST>在源列表< /参数>
    私人小组UpdateListsFromSource(BYVAL SOURCELIST作为IList的)
        如果SOURCELIST是_masterList然后
            SetListValues​​FromSource(_masterList,_targetList,AddressOf ConvertFromMasterToTarget)
        其他
            SetListValues​​FromSource(_targetList,_masterList,AddressOf ConvertFromTargetToMaster)
        万一
    结束小组
    '''<总结>
    ''',什么也不做了转换的实现。
    '''< /总结>
    友元类DoNothingListItemConverter
        实现IListItemConverter        '''<总结>
        '''指定的主列表项转换。
        '''< /总结>
        '''< PARAM NAME =masterListItem>在主列表项目< /参数>
        '''<返回>将转换的结果< /回报>
        公共职能转换(BYVAL masterListItem作为对象)作为对象实现IListItemConverter.Convert
            返回masterListItem
        结束功能        '''<总结>
        '''指定的目标列表项转换。
        '''< /总结>
        '''&下; PARAM NAME =targetListItem>将目标列表项< /参数>
        '''<返回>将转换的结果< /回报>
        公共职能ConvertBack(BYVAL targetListItem作为对象)作为对象实现IListItemConverter.ConvertBack
            返回targetListItem
        结束功能
    末级末级

那么对于XAML:

 < D​​ataGrid中.....地方:MultiSelectorBehaviours.SynchronizedSelectedItems ={结合SelectedResults}/>

最后的VM:

 公共只读属性SelectedResults作为的ObservableCollection(中StatisticsResultModel)
    得到
        返回_objSelectedResults
    到底得的
高端物业

幸得:的http://博客。 functionalfun.net/2009/02/how-to-databind-to-selecteditems.html

SEE MY ANSWER AT THE BOTTOM

Just doing some light reading on WPF where I need to bind the selectedItems from a DataGrid but I am unable to come up with anything tangible. I just need the selected objects.

DataGrid:

<DataGrid Grid.Row="5" 
    Grid.Column="0" 
    Grid.ColumnSpan="4" 
    Name="ui_dtgAgreementDocuments"
    ItemsSource="{Binding Path=Documents, Mode=TwoWay}"
    SelectedItem="{Binding Path=DocumentSelection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
    HorizontalAlignment="Stretch" 
    VerticalAlignment="Stretch" 
    Background="White"
    SelectionMode="Extended" Margin="2,5" 
    IsReadOnly="True" 
    CanUserAddRows="False" 
    CanUserReorderColumns="False" 
    CanUserResizeRows="False"
    GridLinesVisibility="None" 
    HorizontalScrollBarVisibility="Hidden"
    columnHeaderStyle="{StaticResource GreenTea}" 
    HeadersVisibility="Column" 
    BorderThickness="2" 
    BorderBrush="LightGray" 
    CellStyle="{StaticResource NonSelectableDataGridCellStyle}"
    SelectionUnit="FullRow" 
    HorizontalContentAlignment="Stretch" AutoGenerateColumns="False">

解决方案

This will work:

MultiSelectorBehaviours.vb

Imports System.Collections
Imports System.Windows
Imports System.Windows.Controls.Primitives
Imports System.Windows.Controls
Imports System

Public NotInheritable Class MultiSelectorBehaviours
    Private Sub New()
    End Sub

    Public Shared ReadOnly SynchronizedSelectedItems As DependencyProperty = _
        DependencyProperty.RegisterAttached("SynchronizedSelectedItems", GetType(IList), GetType(MultiSelectorBehaviours), New PropertyMetadata(Nothing, New PropertyChangedCallback(AddressOf OnSynchronizedSelectedItemsChanged)))

    Private Shared ReadOnly SynchronizationManagerProperty As DependencyProperty = DependencyProperty.RegisterAttached("SynchronizationManager", GetType(SynchronizationManager), GetType(MultiSelectorBehaviours), New PropertyMetadata(Nothing))

    ''' <summary>
    ''' Gets the synchronized selected items.
    ''' </summary>
    ''' <param name="dependencyObject">The dependency object.</param>
    ''' <returns>The list that is acting as the sync list.</returns>
    Public Shared Function GetSynchronizedSelectedItems(ByVal dependencyObject As DependencyObject) As IList
        Return DirectCast(dependencyObject.GetValue(SynchronizedSelectedItems), IList)
    End Function

    ''' <summary>
    ''' Sets the synchronized selected items.
    ''' </summary>
    ''' <param name="dependencyObject">The dependency object.</param>
    ''' <param name="value">The value to be set as synchronized items.</param>
    Public Shared Sub SetSynchronizedSelectedItems(ByVal dependencyObject As DependencyObject, ByVal value As IList)
        dependencyObject.SetValue(SynchronizedSelectedItems, value)
    End Sub

    Private Shared Function GetSynchronizationManager(ByVal dependencyObject As DependencyObject) As SynchronizationManager
        Return DirectCast(dependencyObject.GetValue(SynchronizationManagerProperty), SynchronizationManager)
    End Function

    Private Shared Sub SetSynchronizationManager(ByVal dependencyObject As DependencyObject, ByVal value As SynchronizationManager)
        dependencyObject.SetValue(SynchronizationManagerProperty, value)
    End Sub

    Private Shared Sub OnSynchronizedSelectedItemsChanged(ByVal dependencyObject As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        If e.OldValue IsNot Nothing Then
            Dim synchronizer As SynchronizationManager = GetSynchronizationManager(dependencyObject)
            synchronizer.StopSynchronizing()

            SetSynchronizationManager(dependencyObject, Nothing)
        End If

        Dim list As IList = TryCast(e.NewValue, IList)
        Dim selector As Selector = TryCast(dependencyObject, Selector)

        ' check that this property is an IList, and that it is being set on a ListBox
        If list IsNot Nothing AndAlso selector IsNot Nothing Then
            Dim synchronizer As SynchronizationManager = GetSynchronizationManager(dependencyObject)
            If synchronizer Is Nothing Then
                synchronizer = New SynchronizationManager(selector)
                SetSynchronizationManager(dependencyObject, synchronizer)
            End If

            synchronizer.StartSynchronizingList()
        End If
    End Sub

    ''' <summary>
    ''' A synchronization manager.
    ''' </summary>
    Private Class SynchronizationManager
        Private ReadOnly _multiSelector As Selector
        Private _synchronizer As TwoListSynchronizer

        ''' <summary>
        ''' Initializes a new instance of the <see cref="SynchronizationManager"/> class.
        ''' </summary>
        ''' <param name="selector">The selector.</param>
        Friend Sub New(ByVal selector As Selector)
            _multiSelector = selector
        End Sub

        ''' <summary>
        ''' Starts synchronizing the list.
        ''' </summary>
        Public Sub StartSynchronizingList()
            Dim list As IList = GetSynchronizedSelectedItems(_multiSelector)

            If list IsNot Nothing Then
                _synchronizer = New TwoListSynchronizer(GetSelectedItemsCollection(_multiSelector), list)
                _synchronizer.StartSynchronizing()
            End If
        End Sub

        ''' <summary>
        ''' Stops synchronizing the list.
        ''' </summary>
        Public Sub StopSynchronizing()
            _synchronizer.StopSynchronizing()
        End Sub

        Public Shared Function GetSelectedItemsCollection(ByVal selector As Selector) As IList
            If TypeOf selector Is MultiSelector Then
                Return TryCast(selector, MultiSelector).SelectedItems
            ElseIf TypeOf selector Is ListBox Then
                Return TryCast(selector, ListBox).SelectedItems
            Else
                Throw New InvalidOperationException("Target object has no SelectedItems property to bind.")
            End If
        End Function

    End Class
End Class

IListItemConverter.vb

''' <summary>
''' Converts items in the Master list to Items in the target list, and back again.
''' </summary>
Public Interface IListItemConverter
    ''' <summary>
    ''' Converts the specified master list item.
    ''' </summary>
    ''' <param name="masterListItem">The master list item.</param>
    ''' <returns>The result of the conversion.</returns>
    Function Convert(ByVal masterListItem As Object) As Object

    ''' <summary>
    ''' Converts the specified target list item.
    ''' </summary>
    ''' <param name="targetListItem">The target list item.</param>
    ''' <returns>The result of the conversion.</returns>
    Function ConvertBack(ByVal targetListItem As Object) As Object
End Interface

TwoListSynchronizer.vb

Imports System.Collections
Imports System.Collections.Specialized
Imports System.Linq
Imports System.Windows

''' <summary>
''' Keeps two lists synchronized. 
''' </summary>
Public Class TwoListSynchronizer
    Implements IWeakEventListener

    Private Shared ReadOnly DefaultConverter As IListItemConverter = New DoNothingListItemConverter()
    Private ReadOnly _masterList As IList
    Private ReadOnly _masterTargetConverter As IListItemConverter
    Private ReadOnly _targetList As IList


    ''' <summary>
    ''' Initializes a new instance of the <see cref="TwoListSynchronizer"/> class.
    ''' </summary>
    ''' <param name="masterList">The master list.</param>
    ''' <param name="targetList">The target list.</param>
    ''' <param name="masterTargetConverter">The master-target converter.</param>
    Public Sub New(ByVal masterList As IList, ByVal targetList As IList, ByVal masterTargetConverter As IListItemConverter)
        _masterList = masterList
        _targetList = targetList
        _masterTargetConverter = masterTargetConverter
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the <see cref="TwoListSynchronizer"/> class.
    ''' </summary>
    ''' <param name="masterList">The master list.</param>
    ''' <param name="targetList">The target list.</param>
    Public Sub New(ByVal masterList As IList, ByVal targetList As IList)
        Me.New(masterList, targetList, DefaultConverter)
    End Sub

    Private Delegate Sub ChangeListAction(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))

    ''' <summary>
    ''' Starts synchronizing the lists.
    ''' </summary>
    Public Sub StartSynchronizing()
        ListenForChangeEvents(_masterList)
        ListenForChangeEvents(_targetList)

        ' Update the Target list from the Master list
        SetListValuesFromSource(_masterList, _targetList, AddressOf ConvertFromMasterToTarget)

        ' In some cases the target list might have its own view on which items should included:
        ' so update the master list from the target list
        ' (This is the case with a ListBox SelectedItems collection: only items from the ItemsSource can be included in SelectedItems)
        If Not TargetAndMasterCollectionsAreEqual() Then
            SetListValuesFromSource(_targetList, _masterList, AddressOf ConvertFromTargetToMaster)
        End If
    End Sub

    ''' <summary>
    ''' Stop synchronizing the lists.
    ''' </summary>
    Public Sub StopSynchronizing()
        StopListeningForChangeEvents(_masterList)
        StopListeningForChangeEvents(_targetList)
    End Sub

    ''' <summary>
    ''' Receives events from the centralized event manager.
    ''' </summary>
    ''' <param name="managerType">The type of the <see cref="T:System.Windows.WeakEventManager"/> calling this method.</param>
    ''' <param name="sender">Object that originated the event.</param>
    ''' <param name="e">Event data.</param>
    ''' <returns>
    ''' true if the listener handled the event. It is considered an error by the <see cref="T:System.Windows.WeakEventManager"/> handling in WPF to register a listener for an event that the listener does not handle. Regardless, the method should return false if it receives an event that it does not recognize or handle.
    ''' </returns>
    Public Function ReceiveWeakEvent(ByVal managerType As Type, ByVal sender As Object, ByVal e As EventArgs) As Boolean Implements System.Windows.IWeakEventListener.ReceiveWeakEvent
        HandleCollectionChanged(TryCast(sender, IList), TryCast(e, NotifyCollectionChangedEventArgs))

        Return True
    End Function

    ''' <summary>
    ''' Listens for change events on a list.
    ''' </summary>
    ''' <param name="list">The list to listen to.</param>
    Protected Sub ListenForChangeEvents(ByVal list As IList)
        If TypeOf list Is INotifyCollectionChanged Then
            CollectionChangedEventManager.AddListener(TryCast(list, INotifyCollectionChanged), Me)
        End If
    End Sub

    ''' <summary>
    ''' Stops listening for change events.
    ''' </summary>
    ''' <param name="list">The list to stop listening to.</param>
    Protected Sub StopListeningForChangeEvents(ByVal list As IList)
        If TypeOf list Is INotifyCollectionChanged Then
            CollectionChangedEventManager.RemoveListener(TryCast(list, INotifyCollectionChanged), Me)
        End If
    End Sub

    Private Sub AddItems(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))
        Dim itemCount As Integer = e.NewItems.Count

        For i As Integer = 0 To itemCount - 1
            Dim insertionPoint As Integer = e.NewStartingIndex + i

            If insertionPoint > list.Count Then
                list.Add(converter(e.NewItems(i)))
            Else
                list.Insert(insertionPoint, converter(e.NewItems(i)))
            End If
        Next
    End Sub

    Private Function ConvertFromMasterToTarget(ByVal masterListItem As Object) As Object
        Return If(_masterTargetConverter Is Nothing, masterListItem, _masterTargetConverter.Convert(masterListItem))
    End Function

    Private Function ConvertFromTargetToMaster(ByVal targetListItem As Object) As Object
        Return If(_masterTargetConverter Is Nothing, targetListItem, _masterTargetConverter.ConvertBack(targetListItem))
    End Function

    Private Sub HandleCollectionChanged(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs)
        Dim sourceList As IList = TryCast(sender, IList)

        Select Case e.Action
            Case NotifyCollectionChangedAction.Add
                PerformActionOnAllLists(AddressOf AddItems, sourceList, e)
                Exit Select
            Case NotifyCollectionChangedAction.Move
                PerformActionOnAllLists(AddressOf MoveItems, sourceList, e)
                Exit Select
            Case NotifyCollectionChangedAction.Remove
                PerformActionOnAllLists(AddressOf RemoveItems, sourceList, e)
                Exit Select
            Case NotifyCollectionChangedAction.Replace
                PerformActionOnAllLists(AddressOf ReplaceItems, sourceList, e)
                Exit Select
            Case NotifyCollectionChangedAction.Reset
                UpdateListsFromSource(TryCast(sender, IList))
                Exit Select
            Case Else
                Exit Select
        End Select
    End Sub

    Private Sub MoveItems(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))
        RemoveItems(list, e, converter)
        AddItems(list, e, converter)
    End Sub

    Private Sub PerformActionOnAllLists(ByVal action As ChangeListAction, ByVal sourceList As IList, ByVal collectionChangedArgs As NotifyCollectionChangedEventArgs)
        If sourceList Is _masterList Then
            PerformActionOnList(_targetList, action, collectionChangedArgs, AddressOf ConvertFromMasterToTarget)
        Else
            PerformActionOnList(_masterList, action, collectionChangedArgs, AddressOf ConvertFromTargetToMaster)
        End If
    End Sub

    Private Sub PerformActionOnList(ByVal list As IList, ByVal action As ChangeListAction, ByVal collectionChangedArgs As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))
        StopListeningForChangeEvents(list)
        action(list, collectionChangedArgs, converter)
        ListenForChangeEvents(list)
    End Sub

    Private Sub RemoveItems(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))
        Dim itemCount As Integer = e.OldItems.Count

        ' for the number of items being removed, remove the item from the Old Starting Index
        ' (this will cause following items to be shifted down to fill the hole).
        For i As Integer = 0 To itemCount - 1
            list.RemoveAt(e.OldStartingIndex)
        Next
    End Sub

    Private Sub ReplaceItems(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))
        RemoveItems(list, e, converter)
        AddItems(list, e, converter)
    End Sub

    Private Sub SetListValuesFromSource(ByVal sourceList As IList, ByVal targetList As IList, ByVal converter As Converter(Of Object, Object))
        StopListeningForChangeEvents(targetList)

        targetList.Clear()

        For Each o As Object In sourceList
            targetList.Add(converter(o))
        Next

        ListenForChangeEvents(targetList)
    End Sub

    Private Function TargetAndMasterCollectionsAreEqual() As Boolean
        Return _masterList.Cast(Of Object)().SequenceEqual(_targetList.Cast(Of Object)().[Select](Function(item) ConvertFromTargetToMaster(item)))
    End Function

    ''' <summary>
    ''' Makes sure that all synchronized lists have the same values as the source list.
    ''' </summary>
    ''' <param name="sourceList">The source list.</param>
    Private Sub UpdateListsFromSource(ByVal sourceList As IList)
        If sourceList Is _masterList Then
            SetListValuesFromSource(_masterList, _targetList, AddressOf ConvertFromMasterToTarget)
        Else
            SetListValuesFromSource(_targetList, _masterList, AddressOf ConvertFromTargetToMaster)
        End If
    End Sub




    ''' <summary>
    ''' An implementation that does nothing in the conversions.
    ''' </summary>
    Friend Class DoNothingListItemConverter
        Implements IListItemConverter

        ''' <summary>
        ''' Converts the specified master list item.
        ''' </summary>
        ''' <param name="masterListItem">The master list item.</param>
        ''' <returns>The result of the conversion.</returns>
        Public Function Convert(ByVal masterListItem As Object) As Object Implements IListItemConverter.Convert
            Return masterListItem
        End Function

        ''' <summary>
        ''' Converts the specified target list item.
        ''' </summary>
        ''' <param name="targetListItem">The target list item.</param>
        ''' <returns>The result of the conversion.</returns>
        Public Function ConvertBack(ByVal targetListItem As Object) As Object Implements IListItemConverter.ConvertBack
            Return targetListItem
        End Function
    End Class

End Class

Then for the XAML:

<DataGrid ..... local:MultiSelectorBehaviours.SynchronizedSelectedItems="{Binding SelectedResults}" />

And finally the VM:

Public ReadOnly Property SelectedResults As ObservableCollection(Of StatisticsResultModel)
    Get
        Return _objSelectedResults
    End Get
End Property

Credit Goes to: http://blog.functionalfun.net/2009/02/how-to-databind-to-selecteditems.html

这篇关于绑定到MVVM从数据网格或列表框SelectedItems的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆