正在Windows应用商店网格视图中迭代所选项目

本文关键字:迭代 选项 项目 视图 网格 Windows 应用 正在 | 更新日期: 2023-09-27 18:28:39

我知道这是一个很长的问题,但请耐心等待。

我已经创建了一个windows应用商店程序,非常类似Laurent Bugnion的"MyFriends"程序,使用MVVM light框架在MVVM light示例中。

在他的程序中,他使用网格视图的SelectedItem属性来跟踪哪个项目是所选项目。

问题是,我让用户能够在GridView上选择多个项目,然后使用应用程序栏上的按钮进行操作。对于此SelectedItem将不起作用。

有人知道如何使用多选GridView吗?我根据WPF上的一些文章尝试过GridViewItem的IsSelected属性,但这似乎不起作用。SelectedTimesheets getter在被调用时总是空的。以下是我目前所拥有的:

MainPage.xaml(绑定到具有子TimesheetViewModel可观察集合的MainViewModel):

<GridView 
    x:Name="itemGridView"
    IsItemClickEnabled="True"
    ItemsSource="{Binding Timesheets}"
    ItemTemplate="{StaticResource TimesheetTemplate}" 
    Margin="10"
    Grid.Column="0"
    SelectionMode="Multiple"
    helpers:ItemClickCommand.Command="{Binding NavigateTimesheetCommand}" RenderTransformOrigin="0.738,0.55"  >
    <GridView.ItemContainerStyle>
        <Style TargetType="GridViewItem">
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
        </Style>
    </GridView.ItemContainerStyle>
</GridView>

MainViewModel(从完整代码中截取):

public class MainViewModel : ViewModelBase
{
    private readonly IDataService _dataService;
    private readonly INavigationService _navigationService;
    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>
    public MainViewModel(IDataService dataService, INavigationService navigationService)
    {
        _dataService = dataService;
        _navigationService = navigationService;
        Timesheets = new ObservableCollection<TimesheetViewModel>();
        ExecuteRefreshCommand();
    }
    public ObservableCollection<TimesheetViewModel> Timesheets
    {
        get;
        private set;
    }
    public IEnumerable<TimesheetViewModel> SelectedTimesheets
    {
        get { return Timesheets.Where(o => o.IsSelected); }
    }
    private async void ExecuteRefreshCommand()
    {
        var timesheets = await _dataService.GetTimesheets("domain''user");
        if (timesheets != null)
        {
            Timesheets.Clear();
            foreach (var timesheet in timesheets)
            {
                Timesheets.Add(new TimesheetViewModel(timesheet));
            }
        }
    }
}

时间表视图模型:

public class TimesheetViewModel: ViewModelBase
{
    public bool IsSelected { get; set; }
    public Timesheet Model
    {
        get;
        private set;
    }
    public TimesheetViewModel(Timesheet model)
    {
        Model = model;
    }
}

如果我手动设置IsSelected属性,SelectedTimesheets lambda就会工作,所以问题出在XAML与IsSelected特性的绑定中。

如有任何帮助,我们将不胜感激。

正在Windows应用商店网格视图中迭代所选项目

当然,我知道你的意思。可惜这不是自动魔术,但事实并非如此。该解决方案涉及一个简单的自定义GridView,它继承自GridView。没有什么太疯狂的,也就是说,如果你让它深入人心。这是代码,我刚刚测试了它:

这是您的XAML:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <Grid.ColumnDefinitions >
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <local:MyGridView ItemsSource="{Binding Items}" SelectionMode="Multiple"
                      BindableSelectedItems="{Binding Selected}" />
    <local:MyGridView Grid.Column="1" ItemsSource="{Binding Selected}" />
</Grid>

这是您的视图模型(超级简化):

public class ViewModel
{
    ObservableCollection<string> m_Items
        = new ObservableCollection<string>(Enumerable.Range(1, 100).Select(x => x.ToString()));
    public ObservableCollection<string> Items { get { return m_Items; } }
    ObservableCollection<object> m_Selected = new ObservableCollection<object>();
    public ObservableCollection<object> Selected { get { return m_Selected; } }
}

这是您的自定义网格视图:

public class MyGridView : GridView
{
    public ObservableCollection<object> BindableSelectedItems
    {
        get { return GetValue(BindableSelectedItemsProperty) as ObservableCollection<object>; }
        set { SetValue(BindableSelectedItemsProperty, value as ObservableCollection<object>); }
    }
    public static readonly DependencyProperty BindableSelectedItemsProperty =
        DependencyProperty.Register("BindableSelectedItems",
        typeof(ObservableCollection<object>), typeof(MyGridView),
        new PropertyMetadata(null, (s, e) =>
        {
            (s as MyGridView).SelectionChanged -= (s as MyGridView).MyGridView_SelectionChanged;
            (s as MyGridView).SelectionChanged += (s as MyGridView).MyGridView_SelectionChanged;
        }));
    void MyGridView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (BindableSelectedItems == null)
            return;
        foreach (var item in BindableSelectedItems.Where(x => !this.SelectedItems.Contains(x)).ToArray())
            BindableSelectedItems.Remove(item);
        foreach (var item in this.SelectedItems.Where(x => !BindableSelectedItems.Contains(x)))
            BindableSelectedItems.Add(item);
    }
}

只有一个新属性BindableSelectedItems

祝你好运!

@Jerry Nixon MSFT的回答促使我重新思考(多亏了他),我提出了以下解决方案。

首先,我更改了XAML以接受一个新的助手方法SelectionChangedCommand.Command,并将其绑定到我的视图模型中名为SelectedChangedCommandRelayCommand

主页.xaml

<GridView 
    x:Name="itemGridView"
    IsItemClickEnabled="True"
    ItemsSource="{Binding Timesheets}"
    ItemTemplate="{StaticResource TimesheetTemplate}" 
    Margin="10"
    Grid.Column="0"
    SelectionMode="Multiple"
    helpers:ItemClickCommand.Command="{Binding NavigateTimesheetCommand}" 
    helpers:SelectionChangedCommand.Command="{Binding SelectionChangedCommand}
    "RenderTransformOrigin="0.738,0.55"  >
</GridView>

然后,我在助手名称空间下添加了一个SelectionChangedCommand助手类,以将SelectedChanged事件转换为ICommandTR

namespace TimesheetManager.Helpers
{
    public class SelectionChangedCommand
    {
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached("Command", typeof(ICommand),
            typeof(SelectionChangedCommand), new PropertyMetadata(null, 
            OnCommandPropertyChanged));
        public static void SetCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(CommandProperty, value);
        }
        public static ICommand GetCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CommandProperty);
        }
        private static void OnCommandPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var control = d as ListViewBase;
            if (control != null)
                control.SelectionChanged += OnSelectionChanged;
        }
        private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var control = sender as ListViewBase;
            var command = GetCommand(control);
            if (command != null && command.CanExecute(e))
                command.Execute(e);
        }
    }
}

这将从ListViewBase(我们的网格视图)继承的任何控件的SelectionChanged事件绑定到名为OnSelectionChanged的方法OnSelectionChanged随后将SelectionChangedEventArgs从控件传递到XAML中的RelayCommand绑定。

最后,在MainViewModel中,我处理RelayCommand并设置IsSelected标志:

MainViewModel:

private RelayCommand<object> _selectionChangedCommand;
/// <summary>
/// Gets the SelectionChangedCommand.
/// </summary>
public RelayCommand<object> SelectionChangedCommand
{
    get
    {
        return _selectionChangedCommand ?? (_selectionChangedCommand = new RelayCommand<object>
        ((param) => ExecuteSelectionChangedCommand(param)));
    }
}
private void ExecuteSelectionChangedCommand(object sender)
{
    var x = sender as SelectionChangedEventArgs;
    foreach (var item in x.AddedItems)
            ((TimesheetViewModel)item).IsSelected = true;
    foreach (var item in x.RemovedItems)
            ((TimesheetViewModel)item).IsSelected = false;
}

我知道有相当多的强制转换正在进行,但我们被ICommand接口限制为对象。

希望这能有所帮助。