2013-08-21 26 views
2

我知道這是一個很長的項目,但請耐心等待。在Windows App Store中迭代所選項目Gridview

我創建了一個Windows應用程序商店程序,它非常類似於使用MVVM輕型框架的MVVM光源樣本中的Laurent Bugnion的「MyFriends」程序。

在他的程序中,他使用gridview的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)); 
      } 

     } 
    } 
} 

TimesheetViewModel:

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屬性的綁定中。

任何幫助,將不勝感激。

回答

1

@ Jerry-Nixon-MSFT的答案促使我重新思考(感謝他),並提出了以下解決方案。

首先,我改變了XAML接受新的helper方法SelectionChangedCommand.Command和其綁定到RelayCommand稱爲SelectionChangedCommand在我的視圖模型

的MainPage。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輔助類,在我的助手命名空間來翻譯的SelectionChanged事件爲ICommand的

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); 

     } 
    } 

} 

此綁定的SelectionChanged的任何事件控件從繼承ListViewBase(我們的gridview)到一種叫做的方法OnSelectionChangedOnSelectionChanged隨後將在控件上傳遞的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; 

} 

我知道有鑄造的事情了相當數量的,但我們僅限於通過接口對象。

希望這會有所幫助。

+0

我知道這是很久以前發佈的,但我想知道一些事情:1)如果您創建從GridView繼承的自定義GridView,是否沒有將GridView控件實現爲GridView控件的一部分的方法? 2)在視圖模型中觸發SelectionCommand時,如果使用JerryNixon-MSFT發佈的方法,它似乎總是被觸發,但所選項目的總數不正確。它似乎總是選擇一個落後。有任何想法嗎? – Thierry

6

當然,我知道你的意思。太糟糕了,這不是自動的,但事實並非如此。解決方案涉及從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; } } 
} 

而且這裏是你的自定義的GridView:

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

祝你好運!

+0

請注意ObservableCollection 用於ViewModel中的Selected。 –

+0

謝謝傑裏,我會放棄這一點。我正在查看是否可以將代碼提取到輔助方法中,並將回發。 – Sico

+0

剛剛添加了一個答案。重做它以使用助手類。謝謝。 – Sico

相關問題