Oma*_*Mir 18 c# vb.net wpf xaml mvvm
在底部看到我的答案
只是在WPF上做一些轻量级阅读,我需要从DataGrid绑定selectedItems,但我无法想出任何有形的东西.我只需要选定的对象.
数据网格:
<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">
Run Code Online (Sandbox Code Playgroud)
Jul*_*bre 42
我可以向你保证:SelectedItems确实可以绑定为XAML CommandParameter
经过大量的挖掘和谷歌搜索,我终于找到了解决这个常见问题的简单方法.
要使其工作,您必须遵循以下所有规则:
按照Ed Ball的建议 ',在您的XAML命令数据绑定上,定义CommandParameter属性BEFORE Command属性.这是一个非常耗时的错误.
确保ICommand的CanExecute和Execute方法具有对象类型的参数.这样就可以防止沉默,每当发生数据绑定转换异常CommandParameter类型不匹配您的命令方法的参数类型.
private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)
{
// Your code goes here
}
private bool OnDeleteSelectedItemsExecute(object SelectedItems)
{
// Your code goes here
}
Run Code Online (Sandbox Code Playgroud)例如,您可以将listview/listbox的SelectedItems属性发送给ICommand方法,也可以将listview/listbox发送给它自己.太棒了,不是吗?
希望它可以防止有人花费大量时间来弄清楚如何接收SelectedItems作为CanExecute参数.
dev*_*xer 24
我的原始答案是错误的(你无法绑定,SelectedItems
因为它是一个只读属性).
一个相当MVVM友好的解决方法是绑定到IsSelected
属性DataGridRow
.
您可以像这样设置绑定:
<DataGrid ItemsSource="{Binding DocumentViewModels}"
SelectionMode="Extended">
<DataGrid.Resources>
<Style TargetType="DataGridRow">
<Setter Property="IsSelected"
Value="{Binding IsSelected}" />
</Style>
</DataGrid.Resources>
</DataGrid>
Run Code Online (Sandbox Code Playgroud)
然后,您需要创建一个DocumentViewModel
继承自ViewModelBase
(或您使用的任何MVVM基类)并且具有Document
您想要在DataGrid中呈现的IsSelected
属性以及属性的属性.
然后,在主视图模型中,创建一个List(Of DocumentViewModel)
名为DocumentViewModels
绑定DataGrid
到的.(注意:如果您要添加/删除列表中的项目,请ObservableCollection(T)
改用.)
现在,这是棘手的部分.您需要挂钩列表中PropertyChanged
的每个事件DocumentViewModel
,如下所示:
For Each documentViewModel As DocumentViewModel In DocumentViewModels
documentViewModel.PropertyChanged += DocumentViewModel_PropertyChanged
Next
Run Code Online (Sandbox Code Playgroud)
这允许您响应任何变化DocumentViewModel
.
最后,DocumentViewModel_PropertyChanged
您可以遍历列表(或使用Linq查询)来获取每个项目的信息IsSelected = True
.
通过一些技巧,您可以扩展DataGrid以创建SelectedItems
属性的可绑定版本.我的解决方案需要结合有Mode=OneWayToSource
,因为我只是想反正从属性看,但它也许可以延长我的解决方案,以允许读写属性.
我假设类似的技术可以用于ListBox,但我还没有尝试过.
public class BindableMultiSelectDataGrid : DataGrid
{
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(IList), typeof(BindableMultiSelectDataGrid), new PropertyMetadata(default(IList)));
public new IList SelectedItems
{
get { return (IList)GetValue(SelectedItemsProperty); }
set { throw new Exception("This property is read-only. To bind to it you must use 'Mode=OneWayToSource'."); }
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
SetValue(SelectedItemsProperty, base.SelectedItems);
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个简单的解决方案。这样您就可以将任何数据传递/更新到 ViewModel
设计器.xaml
<DataGrid Grid.Row="1" Name="dgvMain" SelectionChanged="DataGrid_SelectionChanged" />
Run Code Online (Sandbox Code Playgroud)
设计师.cs
ViewModel mModel = null;
public Designer()
{
InitializeComponent();
mModel = new ViewModel();
this.DataContext = mModel;
}
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
mModel.SelectedItems = dgvMain.SelectedItems;
}
Run Code Online (Sandbox Code Playgroud)
视图模型.cs
public class ViewModel
{
public IList SelectedItems { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我来到这里寻找答案,我得到了很多很棒的答案.我将它们全部组合成一个附属的属性,非常类似于Omar提供的属性,但是在一个类中.处理INotifyCollectionChanged并将列表切换出来.不泄漏事件.我写了它,所以这将是非常简单的代码.用C#编写,处理listbox selectedItems和dataGrid selectedItems.
这适用于DataGrid和ListBox.
(我刚学会了如何使用GitHub)GitHub https://github.com/ParrhesiaJoe/SelectedItemsAttachedWpf
使用方法:
<ListBox ItemsSource="{Binding MyList}" a:Ex.SelectedItems="{Binding ObservableList}"
SelectionMode="Extended"/>
<DataGrid ItemsSource="{Binding MyList}" a:Ex.SelectedItems="{Binding OtherObservableList}" />
Run Code Online (Sandbox Code Playgroud)
这是代码.Git上有一些小样本.
public class Ex : DependencyObject
{
public static readonly DependencyProperty IsSubscribedToSelectionChangedProperty = DependencyProperty.RegisterAttached(
"IsSubscribedToSelectionChanged", typeof(bool), typeof(Ex), new PropertyMetadata(default(bool)));
public static void SetIsSubscribedToSelectionChanged(DependencyObject element, bool value) { element.SetValue(IsSubscribedToSelectionChangedProperty, value); }
public static bool GetIsSubscribedToSelectionChanged(DependencyObject element) { return (bool)element.GetValue(IsSubscribedToSelectionChangedProperty); }
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.RegisterAttached(
"SelectedItems", typeof(IList), typeof(Ex), new PropertyMetadata(default(IList), OnSelectedItemsChanged));
public static void SetSelectedItems(DependencyObject element, IList value) { element.SetValue(SelectedItemsProperty, value); }
public static IList GetSelectedItems(DependencyObject element) { return (IList)element.GetValue(SelectedItemsProperty); }
/// <summary>
/// Attaches a list or observable collection to the grid or listbox, syncing both lists (one way sync for simple lists).
/// </summary>
/// <param name="d">The DataGrid or ListBox</param>
/// <param name="e">The list to sync to.</param>
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is ListBox || d is MultiSelector))
throw new ArgumentException("Somehow this got attached to an object I don't support. ListBoxes and Multiselectors (DataGrid), people. Geesh =P!");
var selector = (Selector)d;
var oldList = e.OldValue as IList;
if (oldList != null)
{
var obs = oldList as INotifyCollectionChanged;
if (obs != null)
{
obs.CollectionChanged -= OnCollectionChanged;
}
// If we're orphaned, disconnect lb/dg events.
if (e.NewValue == null)
{
selector.SelectionChanged -= OnSelectorSelectionChanged;
SetIsSubscribedToSelectionChanged(selector, false);
}
}
var newList = (IList)e.NewValue;
if (newList != null)
{
var obs = newList as INotifyCollectionChanged;
if (obs != null)
{
obs.CollectionChanged += OnCollectionChanged;
}
PushCollectionDataToSelectedItems(newList, selector);
var isSubscribed = GetIsSubscribedToSelectionChanged(selector);
if (!isSubscribed)
{
selector.SelectionChanged += OnSelectorSelectionChanged;
SetIsSubscribedToSelectionChanged(selector, true);
}
}
}
/// <summary>
/// Initially set the selected items to the items in the newly connected collection,
/// unless the new collection has no selected items and the listbox/grid does, in which case
/// the flow is reversed. The data holder sets the state. If both sides hold data, then the
/// bound IList wins and dominates the helpless wpf control.
/// </summary>
/// <param name="obs">The list to sync to</param>
/// <param name="selector">The grid or listbox</param>
private static void PushCollectionDataToSelectedItems(IList obs, DependencyObject selector)
{
var listBox = selector as ListBox;
if (listBox != null)
{
if (obs.Count > 0)
{
listBox.SelectedItems.Clear();
foreach (var ob in obs) { listBox.SelectedItems.Add(ob); }
}
else
{
foreach (var ob in listBox.SelectedItems) { obs.Add(ob); }
}
return;
}
// Maybe other things will use the multiselector base... who knows =P
var grid = selector as MultiSelector;
if (grid != null)
{
if (obs.Count > 0)
{
grid.SelectedItems.Clear();
foreach (var ob in obs) { grid.SelectedItems.Add(ob); }
}
else
{
foreach (var ob in grid.SelectedItems) { obs.Add(ob); }
}
return;
}
throw new ArgumentException("Somehow this got attached to an object I don't support. ListBoxes and Multiselectors (DataGrid), people. Geesh =P!");
}
/// <summary>
/// When the listbox or grid fires a selectionChanged even, we update the attached list to
/// match it.
/// </summary>
/// <param name="sender">The listbox or grid</param>
/// <param name="e">Items added and removed.</param>
private static void OnSelectorSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var dep = (DependencyObject)sender;
var items = GetSelectedItems(dep);
var col = items as INotifyCollectionChanged;
// Remove the events so we don't fire back and forth, then re-add them.
if (col != null) col.CollectionChanged -= OnCollectionChanged;
foreach (var oldItem in e.RemovedItems) items.Remove(oldItem);
foreach (var newItem in e.AddedItems) items.Add(newItem);
if (col != null) col.CollectionChanged += OnCollectionChanged;
}
/// <summary>
/// When the attached object implements INotifyCollectionChanged, the attached listbox
/// or grid will have its selectedItems adjusted by this handler.
/// </summary>
/// <param name="sender">The listbox or grid</param>
/// <param name="e">The added and removed items</param>
private static void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Push the changes to the selected item.
var listbox = sender as ListBox;
if (listbox != null)
{
listbox.SelectionChanged -= OnSelectorSelectionChanged;
if (e.Action == NotifyCollectionChangedAction.Reset) listbox.SelectedItems.Clear();
else
{
foreach (var oldItem in e.OldItems) listbox.SelectedItems.Remove(oldItem);
foreach (var newItem in e.NewItems) listbox.SelectedItems.Add(newItem);
}
listbox.SelectionChanged += OnSelectorSelectionChanged;
}
var grid = sender as MultiSelector;
if (grid != null)
{
grid.SelectionChanged -= OnSelectorSelectionChanged;
if (e.Action == NotifyCollectionChangedAction.Reset) grid.SelectedItems.Clear();
else
{
foreach (var oldItem in e.OldItems) grid.SelectedItems.Remove(oldItem);
foreach (var newItem in e.NewItems) grid.SelectedItems.Add(newItem);
}
grid.SelectionChanged += OnSelectorSelectionChanged;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我知道这篇文章有点老了,已经回答了.但我想出了一个非MVVM的答案.它很容易,对我有用.添加另一个DataGrid,假设您的Selected Collection是SelectedResults:
<DataGrid x:Name="SelectedGridRows"
ItemsSource="{Binding SelectedResults,Mode=OneWayToSource}"
Visibility="Collapsed" >
Run Code Online (Sandbox Code Playgroud)
在后面的代码中,将其添加到构造函数:
public ClassConstructor()
{
InitializeComponent();
OriginalGrid.SelectionChanged -= OriginalGrid_SelectionChanged;
OriginalGrid.SelectionChanged += OriginalGrid_SelectionChanged;
}
private void OriginalGrid_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
SelectedGridRows.ItemsSource = OriginalGrid.SelectedItems;
}
Run Code Online (Sandbox Code Playgroud)
小智 5
我有一个解决方案,使用适合我需要的解决方法。
做一个EventToCommand
对ListItemTemplate
上MouseUp
,并作为CommandParameter
发送的SelectedItems
集合
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp">
<helpers:EventToCommand Command="{Binding DataContext.SelectionChangedUpdate,
RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding ElementName=personsList, Path=SelectedItems}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Run Code Online (Sandbox Code Playgroud)
这样你就可以在视图模型中有一个命令来处理这个或保存选定的项目以供以后使用。玩得开心编码
对我来说,最简单的方法是在 SelectionChanged 事件中填充 ViewModel 属性。
private void MyDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
(DataContext as MyViewModel).SelectedItems.Clear();
(DataContext as MyViewModel).SelectedItems.AddRange(MyDataGrid.SelectedItems.OfType<ItemType>());
}
Run Code Online (Sandbox Code Playgroud)
直接绑定做视图模型,有点小技巧的版本:
1) 创建 ICommand:
public class GetSelectedItemsCommand : ICommand
{
public GetSelectedItemsCommand(Action<object> action)
{
_action = action;
}
private readonly Action<object> _action;
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action(parameter);
}
}
Run Code Online (Sandbox Code Playgroud)
2) 创建数据网格
<DataGrid x:Name="DataGridOfDesperatePeople" SelectionMode="Extended">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction CommandParameter="{Binding ElementName=DataGridOfDesperatePeople, Path=SelectedItems}" Command="{Binding SelectedItemsCommand }" />
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
Run Code Online (Sandbox Code Playgroud)
3) 在视图模型中创建
public List<YourClassOfItemInTheGrid> SelectedItems { get; set; } = new List<YourClassOfItemInTheGrid>();
public ICommand SelectedItemsCommand
{
get
{
return new GetSelectedItemsCommand(list =>
{
SelectedItems.Clear();
IList items = (IList)list;
IEnumerable<YourClassOfItemInTheGrid> collection = items.Cast<YourClassOfItemInTheGrid>();
SelectedItems = collection.ToList();
});
}
}
Run Code Online (Sandbox Code Playgroud)
这将起作用:
\n\n多选择器行为.cs
\n\nImports System.Collections\nImports System.Windows\nImports System.Windows.Controls.Primitives\nImports System.Windows.Controls\nImports System\n\nPublic NotInheritable Class MultiSelectorBehaviours\n Private Sub New()\n End Sub\n\n Public Shared ReadOnly SynchronizedSelectedItems As DependencyProperty = _\n DependencyProperty.RegisterAttached("SynchronizedSelectedItems", GetType(IList), GetType(MultiSelectorBehaviours), New PropertyMetadata(Nothing, New PropertyChangedCallback(AddressOf OnSynchronizedSelectedItemsChanged)))\n\n Private Shared ReadOnly SynchronizationManagerProperty As DependencyProperty = DependencyProperty.RegisterAttached("SynchronizationManager", GetType(SynchronizationManager), GetType(MultiSelectorBehaviours), New PropertyMetadata(Nothing))\n\n \'\'\' <summary>\n \'\'\' Gets the synchronized selected items.\n \'\'\' </summary>\n \'\'\' <param name="dependencyObject">The dependency object.</param>\n \'\'\' <returns>The list that is acting as the sync list.</returns>\n Public Shared Function GetSynchronizedSelectedItems(ByVal dependencyObject As DependencyObject) As IList\n Return DirectCast(dependencyObject.GetValue(SynchronizedSelectedItems), IList)\n End Function\n\n \'\'\' <summary>\n \'\'\' Sets the synchronized selected items.\n \'\'\' </summary>\n \'\'\' <param name="dependencyObject">The dependency object.</param>\n \'\'\' <param name="value">The value to be set as synchronized items.</param>\n Public Shared Sub SetSynchronizedSelectedItems(ByVal dependencyObject As DependencyObject, ByVal value As IList)\n dependencyObject.SetValue(SynchronizedSelectedItems, value)\n End Sub\n\n Private Shared Function GetSynchronizationManager(ByVal dependencyObject As DependencyObject) As SynchronizationManager\n Return DirectCast(dependencyObject.GetValue(SynchronizationManagerProperty), SynchronizationManager)\n End Function\n\n Private Shared Sub SetSynchronizationManager(ByVal dependencyObject As DependencyObject, ByVal value As SynchronizationManager)\n dependencyObject.SetValue(SynchronizationManagerProperty, value)\n End Sub\n\n Private Shared Sub OnSynchronizedSelectedItemsChanged(ByVal dependencyObject As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)\n If e.OldValue IsNot Nothing Then\n Dim synchronizer As SynchronizationManager = GetSynchronizationManager(dependencyObject)\n synchronizer.StopSynchronizing()\n\n SetSynchronizationManager(dependencyObject, Nothing)\n End If\n\n Dim list As IList = TryCast(e.NewValue, IList)\n Dim selector As Selector = TryCast(dependencyObject, Selector)\n\n \' check that this property is an IList, and that it is being set on a ListBox\n If list IsNot Nothing AndAlso selector IsNot Nothing Then\n Dim synchronizer As SynchronizationManager = GetSynchronizationManager(dependencyObject)\n If synchronizer Is Nothing Then\n synchronizer = New SynchronizationManager(selector)\n SetSynchronizationManager(dependencyObject, synchronizer)\n End If\n\n synchronizer.StartSynchronizingList()\n End If\n End Sub\n\n \'\'\' <summary>\n \'\'\' A synchronization manager.\n \'\'\' </summary>\n Private Class SynchronizationManager\n Private ReadOnly _multiSelector As Selector\n Private _synchronizer As TwoListSynchronizer\n\n \'\'\' <summary>\n \'\'\' Initializes a new instance of the <see cref="SynchronizationManager"/> class.\n \'\'\' </summary>\n \'\'\' <param name="selector">The selector.</param>\n Friend Sub New(ByVal selector As Selector)\n _multiSelector = selector\n End Sub\n\n \'\'\' <summary>\n \'\'\' Starts synchronizing the list.\n \'\'\' </summary>\n Public Sub StartSynchronizingList()\n Dim list As IList = GetSynchronizedSelectedItems(_multiSelector)\n\n If list IsNot Nothing Then\n _synchronizer = New TwoListSynchronizer(GetSelectedItemsCollection(_multiSelector), list)\n _synchronizer.StartSynchronizing()\n End If\n End Sub\n\n \'\'\' <summary>\n \'\'\' Stops synchronizing the list.\n \'\'\' </summary>\n Public Sub StopSynchronizing()\n _synchronizer.StopSynchronizing()\n End Sub\n\n Public Shared Function GetSelectedItemsCollection(ByVal selector As Selector) As IList\n If TypeOf selector Is MultiSelector Then\n Return TryCast(selector, MultiSelector).SelectedItems\n ElseIf TypeOf selector Is ListBox Then\n Return TryCast(selector, ListBox).SelectedItems\n Else\n Throw New InvalidOperationException("Target object has no SelectedItems property to bind.")\n End If\n End Function\n\n End Class\nEnd Class\n
Run Code Online (Sandbox Code Playgroud)\n\nIListItemConverter.cs
\n\n\'\'\' <summary>\n\'\'\' Converts items in the Master list to Items in the target list, and back again.\n\'\'\' </summary>\nPublic Interface IListItemConverter\n \'\'\' <summary>\n \'\'\' Converts the specified master list item.\n \'\'\' </summary>\n \'\'\' <param name="masterListItem">The master list item.</param>\n \'\'\' <returns>The result of the conversion.</returns>\n Function Convert(ByVal masterListItem As Object) As Object\n\n \'\'\' <summary>\n \'\'\' Converts the specified target list item.\n \'\'\' </summary>\n \'\'\' <param name="targetListItem">The target list item.</param>\n \'\'\' <returns>The result of the conversion.</returns>\n Function ConvertBack(ByVal targetListItem As Object) As Object\nEnd Interface\n
Run Code Online (Sandbox Code Playgroud)\n\nTwoListSynchronizer.vb
\n\nImports System.Collections\nImports System.Collections.Specialized\nImports System.Linq\nImports System.Windows\n\n\'\'\' <summary>\n\'\'\' Keeps two lists synchronized. \n\'\'\' </summary>\nPublic Class TwoListSynchronizer\n Implements IWeakEventListener\n\n Private Shared ReadOnly DefaultConverter As IListItemConverter = New DoNothingListItemConverter()\n Private ReadOnly _masterList As IList\n Private ReadOnly _masterTargetConverter As IListItemConverter\n Private ReadOnly _targetList As IList\n\n\n \'\'\' <summary>\n \'\'\' Initializes a new instance of the <see cref="TwoListSynchronizer"/> class.\n \'\'\' </summary>\n \'\'\' <param name="masterList">The master list.</param>\n \'\'\' <param name="targetList">The target list.</param>\n \'\'\' <param name="masterTargetConverter">The master-target converter.</param>\n Public Sub New(ByVal masterList As IList, ByVal targetList As IList, ByVal masterTargetConverter As IListItemConverter)\n _masterList = masterList\n _targetList = targetList\n _masterTargetConverter = masterTargetConverter\n End Sub\n\n \'\'\' <summary>\n \'\'\' Initializes a new instance of the <see cref="TwoListSynchronizer"/> class.\n \'\'\' </summary>\n \'\'\' <param name="masterList">The master list.</param>\n \'\'\' <param name="targetList">The target list.</param>\n Public Sub New(ByVal masterList As IList, ByVal targetList As IList)\n Me.New(masterList, targetList, DefaultConverter)\n End Sub\n\n Private Delegate Sub ChangeListAction(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))\n\n \'\'\' <summary>\n \'\'\' Starts synchronizing the lists.\n \'\'\' </summary>\n Public Sub StartSynchronizing()\n ListenForChangeEvents(_masterList)\n ListenForChangeEvents(_targetList)\n\n \' Update the Target list from the Master list\n SetListValuesFromSource(_masterList, _targetList, AddressOf ConvertFromMasterToTarget)\n\n \' In some cases the target list might have its own view on which items should included:\n \' so update the master list from the target list\n \' (This is the case with a ListBox SelectedItems collection: only items from the ItemsSource can be included in SelectedItems)\n If Not TargetAndMasterCollectionsAreEqual() Then\n SetListValuesFromSource(_targetList, _masterList, AddressOf ConvertFromTargetToMaster)\n End If\n End Sub\n\n \'\'\' <summary>\n \'\'\' Stop synchronizing the lists.\n \'\'\' </summary>\n Public Sub StopSynchronizing()\n StopListeningForChangeEvents(_masterList)\n StopListeningForChangeEvents(_targetList)\n End Sub\n\n \'\'\' <summary>\n \'\'\' Receives events from the centralized event manager.\n \'\'\' </summary>\n \'\'\' <param name="managerType">The type of the <see cref="T:System.Windows.WeakEventManager"/> calling this method.</param>\n \'\'\' <param name="sender">Object that originated the event.</param>\n \'\'\' <param name="e">Event data.</param>\n \'\'\' <returns>\n \'\'\' true if the listener handled the event. It is considered an error by the <see cref="T:System.Windows.WeakEventManager"/> handling in WPF\xc2\xa0to 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.\n \'\'\' </returns>\n Public Function ReceiveWeakEvent(ByVal managerType As Type, ByVal sender As Object, ByVal e As EventArgs) As Boolean Implements System.Windows.IWeakEventListener.ReceiveWeakEvent\n HandleCollectionChanged(TryCast(sender, IList), TryCast(e, NotifyCollectionChangedEventArgs))\n\n Return True\n End Function\n\n \'\'\' <summary>\n \'\'\' Listens for change events on a list.\n \'\'\' </summary>\n \'\'\' <param name="list">The list to listen to.</param>\n Protected Sub ListenForChangeEvents(ByVal list As IList)\n If TypeOf list Is INotifyCollectionChanged Then\n CollectionChangedEventManager.AddListener(TryCast(list, INotifyCollectionChanged), Me)\n End If\n End Sub\n\n \'\'\' <summary>\n \'\'\' Stops listening for change events.\n \'\'\' </summary>\n \'\'\' <param name="list">The list to stop listening to.</param>\n Protected Sub StopListeningForChangeEvents(ByVal list As IList)\n If TypeOf list Is INotifyCollectionChanged Then\n CollectionChangedEventManager.RemoveListener(TryCast(list, INotifyCollectionChanged), Me)\n End If\n End Sub\n\n Private Sub AddItems(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))\n Dim itemCount As Integer = e.NewItems.Count\n\n For i As Integer = 0 To itemCount - 1\n Dim insertionPoint As Integer = e.NewStartingIndex + i\n\n If insertionPoint > list.Count Then\n list.Add(converter(e.NewItems(i)))\n Else\n list.Insert(insertionPoint, converter(e.NewItems(i)))\n End If\n Next\n End Sub\n\n Private Function ConvertFromMasterToTarget(ByVal masterListItem As Object) As Object\n Return If(_masterTargetConverter Is Nothing, masterListItem, _masterTargetConverter.Convert(masterListItem))\n End Function\n\n Private Function ConvertFromTargetToMaster(ByVal targetListItem As Object) As Object\n Return If(_masterTargetConverter Is Nothing, targetListItem, _masterTargetConverter.ConvertBack(targetListItem))\n End Function\n\n Private Sub HandleCollectionChanged(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs)\n Dim sourceList As IList = TryCast(sender, IList)\n\n Select Case e.Action\n Case NotifyCollectionChangedAction.Add\n PerformActionOnAllLists(AddressOf AddItems, sourceList, e)\n Exit Select\n Case NotifyCollectionChangedAction.Move\n PerformActionOnAllLists(AddressOf MoveItems, sourceList, e)\n Exit Select\n Case NotifyCollectionChangedAction.Remove\n PerformActionOnAllLists(AddressOf RemoveItems, sourceList, e)\n Exit Select\n Case NotifyCollectionChangedAction.Replace\n PerformActionOnAllLists(AddressOf ReplaceItems, sourceList, e)\n Exit Select\n Case NotifyCollectionChangedAction.Reset\n UpdateListsFromSource(TryCast(sender, IList))\n Exit Select\n Case Else\n Exit Select\n End Select\n End Sub\n\n Private Sub MoveItems(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))\n RemoveItems(list, e, converter)\n AddItems(list, e, converter)\n End Sub\n\n Private Sub PerformActionOnAllLists(ByVal action As ChangeListAction, ByVal sourceList As IList, ByVal collectionChangedArgs As NotifyCollectionChangedEventArgs)\n If sourceList Is _masterList Then\n PerformActionOnList(_targetList, action, collectionChangedArgs, AddressOf ConvertFromMasterToTarget)\n Else\n PerformActionOnList(_masterList, action, collectionChangedArgs, AddressOf ConvertFromTargetToMaster)\n End If\n End Sub\n\n Private Sub PerformActionOnList(ByVal list As IList, ByVal action As ChangeListAction, ByVal collectionChangedArgs As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))\n StopListeningForChangeEvents(list)\n action(list, collectionChangedArgs, converter)\n ListenForChangeEvents(list)\n End Sub\n\n Private Sub RemoveItems(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))\n Dim itemCount As Integer = e.OldItems.Count\n\n \' for the number of items being removed, remove the item from the Old Starting Index\n \' (this will cause following items to be shifted down to fill the hole).\n For i As Integer = 0 To itemCount - 1\n list.RemoveAt(e.OldStartingIndex)\n Next\n End Sub\n\n Private Sub ReplaceItems(ByVal list As IList, ByVal e As NotifyCollectionChangedEventArgs, ByVal converter As Converter(Of Object, Object))\n RemoveItems(list, e, converter)\n AddItems(list, e, converter)\n End Sub\n\n Private Sub SetListValuesFromSource(ByVal sourceList As IList, ByVal targetList As IList, ByVal converter As Converter(Of Object, Object))\n StopListeningForChangeEvents(targetList)\n\n targetList.Clear()\n\n For Each o As Object In sourceList\n targetList.Add(converter(o))\n Next\n\n ListenForChangeEvents(targetList)\n End Sub\n\n Private Function TargetAndMasterCollectionsAreEqual() As Boolean\n Return _masterList.Cast(Of Object)().SequenceEqual(_targetList.Cast(Of Object)().[Select](Function(item) ConvertFromTargetToMaster(item)))\n End Function\n\n \'\'\' <summary>\n \'\'\' Makes sure that all synchronized lists have the same values as the source list.\n \'\'\' </summary>\n \'\'\' <param name="sourceList">The source list.</param>\n Private Sub UpdateListsFromSource(ByVal sourceList As IList)\n If sourceList Is _masterList Then\n SetListValuesFromSource(_masterList, _targetList, AddressOf ConvertFromMasterToTarget)\n Else\n SetListValuesFromSource(_targetList, _masterList, AddressOf ConvertFromTargetToMaster)\n End If\n End Sub\n\n\n\n\n \'\'\' <summary>\n \'\'\' An implementation that does nothing in the conversions.\n \'\'\' </summary>\n Friend Class DoNothingListItemConverter\n Implements IListItemConverter\n\n \'\'\' <summary>\n \'\'\' Converts the specified master list item.\n \'\'\' </summary>\n \'\'\' <param name="masterListItem">The master list item.</param>\n \'\'\' <returns>The result of the conversion.</returns>\n Public Function Convert(ByVal masterListItem As Object) As Object Implements IListItemConverter.Convert\n Return masterListItem\n End Function\n\n \'\'\' <summary>\n \'\'\' Converts the specified target list item.\n \'\'\' </summary>\n \'\'\' <param name="targetListItem">The target list item.</param>\n \'\'\' <returns>The result of the conversion.</returns>\n Public Function ConvertBack(ByVal targetListItem As Object) As Object Implements IListItemConverter.ConvertBack\n Return targetListItem\n End Function\n End Class\n\nEnd Class\n
Run Code Online (Sandbox Code Playgroud)\n\n然后对于 XAML:
\n\n<DataGrid ..... local:MultiSelectorBehaviours.SynchronizedSelectedItems="{Binding SelectedResults}" />\n
Run Code Online (Sandbox Code Playgroud)\n\n最后是虚拟机:
\n\nPublic ReadOnly Property SelectedResults As ObservableCollection(Of StatisticsResultModel)\n Get\n Return _objSelectedResults\n End Get\nEnd Property\n
Run Code Online (Sandbox Code Playgroud)\n\n信用转到:http://blog.functionfun.net/2009/02/how-to-databind-to-selecteditems.html
\n