[英]Windows Phone 8 Binding Multiple Selection ListView
我在使用“列表视图”设置绑定多个选择时遇到麻烦,并且在将“选择模式”切换到“单个”和“多个”之间时还记得选择。
上下文
我正在创建一个足球教练应用程序。 列表视图将显示播放器名册。 在比赛当天,我希望有一种简单的方法来选择出现的玩家。 我想使用“多重选择”模式来允许用户选择出现的球员。 我将在应用程序栏中提供一个按钮,该按钮将通过转换器控制SelectionMode。 它将列表视图从单个切换到多个。 这部分工作正常。 我可以看到列表视图在单个和多个之间切换。
不能正常工作的部分是所选项目的绑定。 我必须缺少一些东西,因为要可靠地绑定到SelectedItems属性似乎非常困难。 到目前为止,最有效的方法是WinRTXamlToolkit中的ListViewExtentions,这是我在下面的xaml中显示的内容。 进行选择时,似乎在视图模式下将项目绑定到backing属性,但是,当SelectionMode切换回Single时,将清除back属性。 另外,在不修改扩展代码的情况下,它破坏了我的SelectionMode代码。 _listView.SelectedItems.Clear()上的扩展名中有一个灾难性的失败。 如果我删除该行,则SelectionMode将恢复工作。
我不在乎使用WinRTXamlToolkit中的ListViewExtentions。 我只在这里展示它,所以您知道我已经尝试过了。 最终,我正在寻找绑定SelectedItems的正确解决方案。
这是列表视图XAML。
<ListView ItemsSource="{Binding Roster}"
toolkitExt:ListViewExtensions.BindableSelection="{Binding SelectedPlayers, Mode=TwoWay}"
SelectionMode="{Binding IsEditingGameRoster, Converter={StaticResource ListViewSelectionModeFromBooleanNoneOrMultipleConverter}}">
<ListView.ItemTemplate>
<DataTemplate>
<!-- List View Display Not important for describing problem. -->
</DataTemplate>
</ListView.ItemTemplate>
命名空间为:xmlns:toolkitExt =“ using:WinRTXamlToolkit.Controls.Extensions”
视图模型具有以下属性:成员名册:ObservableCollection IsEditingGameRoster:Bool SelectedPlayers:ObservableCollection
感谢您展示任何绑定多重选择的示例,尤其是如果它也处理切换SelectionMode的示例。
谢谢汤姆
我也面临这个问题。 当我尝试更改转换器中的选择模式时,它无法按预期工作。 我发现的任何解决方法都是使用多个选择模式,但是在具有添加/删除的项目的CollectionChanged事件中运行。 例如,如果我需要单选模式,我会将选择重写为新的选定项目。
像这样:
private void OnSelectedPlayersChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
if (this.SelectionMode == Mode.Once)
{
SynchronizationContextProvider.UIThreadSyncContext.Post((d) =>
{
this.SelectedPlayers.Clear();
this.SelectedPlayers.Add((Players)e.NewItems[0]);
}, null);
}
}
if (e.Action == NotifyCollectionChangedAction.Remove)
{
//some logic
}
}
到目前为止,这是最好的选择。 如果您发现更好的东西,我将很乐意使用它。
我最终解决了我希望看到的问题,但仍然不够完美。 我最终创建了ListView的子类,并添加了两个属性SelectedItems2和SelectionMode2。 如果有人可以帮助调整以下代码,以便我可以重用SelectedItems和SelectionMode,则可以使解决方案更加接近完美。
子类代码
/// <summary>
/// Enhanced List View
///
/// SeletionMode Switching:
/// This class enhances ListView to support changing the selection mode from None/Single to Multiple and back and having it
/// bind the selected items without forgetting them when changing selection mode. The base ListView will remove the selected items when switching
/// from Multiple SelectionMode to another SelectionMode.
/// 1) Created SelectedItems2 to bind to View Model as SelectedItems will have items removed and SelectedItems is not easy to bind to SelectedItems.
/// 2) On SelectionChanged, remember the selected items in SelectedItems2 how the user selected or unselected them.
/// 3) On SelectionMode set to Multiple, fill the underlying SelectedItems with the values from SelectedItems2 so that the checkboxes are checked on the ListView.
/// 4) Use _isMergingItems flag to ignore selection changed events being fired by merging of the SelectedItem2 and SelectedItems2 collections.
///
/// Doesn't support changing SelectedItems2 bound collection while in Multiple SelectionMode yet.
/// To do so we would need to hook the CollectionChanged event on the SelectedItems2 List object that is bound.
/// and likely handle threading issues with the merging of SelectedItems and SelectedItems2.
/// </summary>
public class MyListView : ListView
{
private bool _isMergingItems;
public MyListView()
{
SelectionChanged += MyListView_SelectionChanged;
}
private void MyListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Ignore selection changed event when selection mode is not multiple.
// This is mainly here because when changing from Multiple to Single, this event is fired and will cause
// the items to be removed from SelectedItems2 which is not what is desired.
if (SelectionMode != ListViewSelectionMode.Multiple) { return; }
if (_isMergingItems) { return; }
try
{
_isMergingItems = true;
var selectedItems2List = SelectedItems2 as IList;
if (selectedItems2List == null) { return; }
foreach (var itemToAdd in e.AddedItems)
{
selectedItems2List.Add(itemToAdd);
}
foreach (var itemToRemove in e.RemovedItems)
{
selectedItems2List.Remove(itemToRemove);
}
}
finally
{
_isMergingItems = false;
}
}
#region --- Dependency Properties ---
private static readonly DependencyProperty SelectionMode2Property = DependencyProperty.Register("SelectionMode2", typeof(ListViewSelectionMode), typeof(MyListView), new PropertyMetadata(ListViewSelectionMode.None, SelectionMode2Changed));
public ListViewSelectionMode SelectionMode2
{
get { return (ListViewSelectionMode)GetValue(SelectionMode2Property); }
set { SetValue(SelectionMode2Property, value); }
}
private static void SelectionMode2Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var listView = d as MyListView;
var value = (ListViewSelectionMode)e.NewValue;
// Set the underlying selection mode property to cause the control to
// change to and from Multiple selection mode.
listView.SelectionMode = value;
// When Multiple selction mode, we will need to load the underlying SelectedItems of the ListView
// so that the checkboxes are checked appropriatly. When the selection mode is changed the underlying ListView
// removes the selected items.
if (value == ListViewSelectionMode.Multiple)
{
listView.FillUnderlyingSelectedItems();
}
}
private static readonly DependencyProperty SelectedItems2Property = DependencyProperty.Register("SelectedItems2", typeof(object), typeof(MyListView), null);
/// <summary>
/// SelectedItems2 is used as the property to bind the selected items to the ViewModel.
/// Using a List as the data type did not seem to work for binding. Since ItemSource is an object on the base class
/// object was chosen for this property as well.
///
/// However, SelectedItems2 will need to bind to IList in order for it to work properly.
/// </summary>
public object SelectedItems2
{
get { return (object)GetValue(SelectedItems2Property); }
set { SetValue(SelectedItems2Property, value); }
}
#endregion
private void FillUnderlyingSelectedItems()
{
var selectedItems2List = SelectedItems2 as IList;
if (selectedItems2List == null) { return; }
try
{
_isMergingItems = true;
foreach (var item in selectedItems2List)
{
SelectedItems.Add(item);
}
}
finally
{
_isMergingItems = false;
}
}
}
用法:XAML
<localUI:MyListView ItemsSource="{Binding Roster}"
SelectedItems2="{Binding SelectedPlayers}"
SelectionMode2="{Binding IsEditingGameRoster, Converter={StaticResource ListViewSelectionModeFromBooleanNoneOrMultipleConverter}}">
<ListView.ItemTemplate>
<DataTemplate>
<!-- List View Display Not important for describing problem. -->
</DataTemplate>
</ListView.ItemTemplate>
</localUI:MyListView>
用法:ViewModel
private ObservableCollection<Player> _selectedPlayers;
public ObservableCollection<Player> SelectedPlayers
{
get
{
if (_selectedPlayers == null)
{
_selectedPlayers = new ObservableCollection<Player>();
}
return _selectedPlayers;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.