首页 文章

Windows Phone 8绑定多个选择ListView

提问于
浏览
1

我在使用列表视图设置来绑定多个选择时遇到问题,并在我将选择模式切换到单个和多个之间时记住选择 .

Context

我正在创建一个足球教练应用程序 . 列表视图将显示播放器名单 . 在比赛日,我想要一种简单的方法来选择出场的球员 . 我想使用多重选择模式允许用户选择出现的玩家 . 我将在应用栏中提供一个按钮,通过转换器控制SelectionMode . 它会将列表视图从单个切换到多个 . 这部分工作正常 . 我可以在Single和Multiple之间看到List View切换 .

不能正常工作的部分是Selected Items的绑定 . 我必须遗漏一些东西,因为似乎很难可靠地绑定到SelectedItems属性 . 到目前为止最好的工作是来自WinRTXamlToolkit的ListViewExtentions,这是我在下面的xaml中显示的内容 . 在进行选择时,它似乎将项目绑定到视图模式中的backing属性,但是,当SelectionMode切换回Single时,back属性被清除 . 此外,在不修改扩展代码的情况下,它破坏了我的SelectionMode代码 . 在_listView.SelectedItems.Clear()上的扩展中存在自然故障 . 如果我删除该行,则SelectionMode将恢复工作 .

我不关心使用WinRTXamlToolkit中的ListViewExtentions . 我只在这里介绍它,所以你知道我已经尝试过了 . 最终,我正在寻找绑定SelectedItems的正确解决方案 .

这是List View 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”

View Model具有以下属性:Roster:ObservableCollection IsEditingGameRoster:Bool SelectedPlayers:ObservableCollection

感谢任何演示绑定多重选择的示例,特别是如果它也处理切换SelectionMode .

谢谢,汤姆

2 回答

  • 0

    我也面临着这个问题 . 当我试图在转换器中更改选择模式时,它的工作方式与预期不符 . 我发现的任何解决方法都是使用多选模式,但在添加/删除项目的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
            }
    }
    

    这是迄今为止我发现的最佳选择 . 如果你能找到更好的东西,我会乐意使用它 .

  • 1

    我最终解决了我希望看到但仍然不完美的问题 . 我最终创建了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;
            }
        }
    

相关问题