【问题标题】:Windows Phone 8 Binding Multiple Selection ListViewWindows Phone 8 绑定多选 ListView
【发布时间】:2014-12-24 14:03:26
【问题描述】:

我无法使用列表视图设置绑定多个选择,并在我将选择模式切换到单个和多个之间时记住选择。

上下文

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

不能正常工作的部分是 Selected Items 的绑定。我一定遗漏了一些东西,因为可靠地绑定到 SelectedItems 属性似乎非常困难。迄今为止最有效的是 WinRTXamlToolkit 中的 ListViewExtentions,这是我在下面的 xaml 中展示的内容。 It seems to bind the items to the backing property in the view mode when the selection is made, however, when the SelectionMode is switched back to Single, the back property is cleared out.此外,在不修改扩展代码的情况下,它破坏了我的 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 : 布尔 SelectedPlayers : ObservableCollection

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

谢谢, 汤姆

【问题讨论】:

    标签: c# xaml listview windows-phone-8


    【解决方案1】:

    我也遇到过这个问题。当我试图在转换器中更改选择模式时,它的工作方式与预期不同。我发现的任何解决方法都是使用多选模式,但在 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 子类的解决方案。我会尽快发布。我会给你一点帮助。再次感谢!
    【解决方案2】:

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

    用法:视图模型

        private ObservableCollection<Player> _selectedPlayers;
    
        public ObservableCollection<Player> SelectedPlayers
        {
            get
            {
                if (_selectedPlayers == null)
                {
                    _selectedPlayers = new ObservableCollection<Player>();
                }
    
                return _selectedPlayers;
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-15
      • 2013-12-30
      • 1970-01-01
      • 2017-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-02
      相关资源
      最近更新 更多