2013-07-10 41 views
0

在使用MVVM處理小型Windows應用商店應用時,我遇到了一個棘手的問題。我想使用ListBox顯示Big Brother第14季的房客名單。按照設計,每個ListBoxItem中應該有一個按鈕。單擊按鈕時,應該觸發一個命令,它將從列表框中刪除ListBoxItem。如何通過單擊其DataTemplate中的按鈕從分組列表框中刪除/刪除項目?

下面是我目前的解決方案。它可以工作,但不是很令人滿意,因爲無論何時從ListBox中刪除項目,模型都需要過濾整個集合並刷新整個ListBox,這會導致一些性能問題,尤其是當原始集合非常龐大時。

[MainPage.xaml中]

<Page 
    x:Class="App1.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:App1" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d"> 

    <Page.Resources> 
     <CollectionViewSource x:Name="groupInfo" IsSourceGrouped="true" ItemsPath="Items" /> 
     <local:BigBrotherModel x:Name="BBModel" /> 
     <DataTemplate x:Key="lvwItemTemp"> 
      <StackPanel> 
       <Grid Height="30"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="40" /> 
         <ColumnDefinition Width="100" /> 
         <ColumnDefinition Width="100" /> 
        </Grid.ColumnDefinitions> 

        <Button Grid.Column="0" Padding="0" Foreground="Red" FontFamily="Segoe UI Symbol" 
           Command="{Binding DataContext.RemoveHouseGuestCommand, ElementName=lbxHouseGuests}" 
           CommandParameter="{Binding}">&#xE221;</Button> 
        <TextBlock Grid.Column="1" Text="{Binding FirstName}" HorizontalAlignment="Stretch" /> 
        <TextBlock Grid.Column="2" Text="{Binding LastName}" HorizontalAlignment="Stretch" /> 
       </Grid> 
      </StackPanel> 
     </DataTemplate> 
    </Page.Resources> 


    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> 
     <ListBox x:Name="lbxHouseGuests" DataContext="{StaticResource BBModel}" ItemsSource="{Binding Source={StaticResource groupInfo}}" ItemTemplate="{StaticResource lvwItemTemp}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> 
      <ListBox.GroupStyle> 
       <GroupStyle> 
        <GroupStyle.HeaderTemplate> 
         <DataTemplate> 
          <Border BorderBrush="Red" BorderThickness="0" Background="DarkGray" HorizontalAlignment="Stretch"> 
           <TextBlock Width="500" Text="{Binding Role}"/> 
          </Border> 
         </DataTemplate> 
        </GroupStyle.HeaderTemplate> 
       </GroupStyle> 
      </ListBox.GroupStyle> 
     </ListBox> 
    </Grid> 
</Page> 

[MainPage.cs]

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Windows.Input; 
using Windows.Foundation; 
using Windows.Foundation.Collections; 
using System.Collections.ObjectModel; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Controls.Primitives; 
using Windows.UI.Xaml.Data; 
using Windows.UI.Xaml.Input; 
using Windows.UI.Xaml.Media; 
using Windows.UI.Xaml.Navigation; 
using Windows.UI.Popups; 
using System.Diagnostics; 


namespace App1 
{ 


    public class HouseGuest 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public string Role { get; set; } 
     public bool Deleted { get; set; } 
    } 

    public class BigBrotherModel 
    { 
     public ObservableCollection<HouseGuest> houseGuests { get; set; } 
     public ListBox lbx { get; set; } 
     public CollectionViewSource cvs { get; set; } 

     public BigBrotherModel() 
     { 
      houseGuests = new ObservableCollection<HouseGuest>(); 
      houseGuests.Add(new HouseGuest() { FirstName = "Ian", LastName = "Terry", Role="Player" }); 
      houseGuests.Add(new HouseGuest() { FirstName = "Shane", LastName = "Meaney", Role = "Player" }); 
      houseGuests.Add(new HouseGuest() { FirstName = "Wil", LastName = "Heuser", Role = "Player" }); 
      houseGuests.Add(new HouseGuest() { FirstName = "Danielle", LastName = "Murphree", Role = "Player" }); 
      houseGuests.Add(new HouseGuest() { FirstName = "Jenn", LastName = "Arroyo", Role = "Player" }); 
      houseGuests.Add(new HouseGuest() { FirstName = "Jodi", LastName = "Rollins", Role = "Player" }); 
      houseGuests.Add(new HouseGuest() { FirstName = "Ashley", LastName = "Iocco", Role = "Player" }); 

      houseGuests.Add(new HouseGuest() { FirstName = "Britney", LastName = "Haynes", Role = "Coach" }); 
      houseGuests.Add(new HouseGuest() { FirstName = "Dan", LastName = "Gheesling", Role = "Coach"}); 
      houseGuests.Add(new HouseGuest() { FirstName = "Janelle", LastName = "Pierzina", Role = "Coach" }); 
      houseGuests.Add(new HouseGuest() { FirstName = "Mike", LastName = "Boogie", Role = "Coach"}); 


      RemoveHouseGuestCommand = new DelegateCommand(RemoveHouseGuest); 
     } 
     public ICommand RemoveHouseGuestCommand { get; set; } 

     void RemoveHouseGuest(object param) 
     { 
      Debug.Assert(param is HouseGuest); 
      (param as HouseGuest).Deleted = true; 
      RefreshListBox(); 
     } 

     object GetGroupedView() 
     { 
      var view = from hg in houseGuests 
         where hg.Deleted == false 
         group hg by hg.Role into g 
         orderby g.Key 
         select new { Role = g.Key, Items = g }; 
      return view; 
     } 

     public void RefreshListBox() 
     { 
      cvs.Source = GetGroupedView(); 
     } 
    } 

    public sealed partial class MainPage : Page 
    { 

     public MainPage() 
     { 
      this.InitializeComponent(); 
      BBModel.cvs = groupInfo; 
      BBModel.lbx = lbxHouseGuests; 

      BBModel.RefreshListBox(); 
     } 
    } 
} 

我的問題是:有沒有辦法刪除從分組列表框一個ListBoxItem的,而不需要刷新整個ListBox使用MVVM?我真的被困在這裏。任何建議,將不勝感激。提前謝謝了。

[編輯] 感謝Nate的建議,我在MainPage.cs中重寫我的代碼,並且它工作的很棒。以下是源代碼。

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Windows.Input; 
using Windows.Foundation; 
using Windows.Foundation.Collections; 
using System.Collections.ObjectModel; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Controls.Primitives; 
using Windows.UI.Xaml.Data; 
using Windows.UI.Xaml.Input; 
using Windows.UI.Xaml.Media; 
using Windows.UI.Xaml.Navigation; 
using Windows.UI.Popups; 
using System.Diagnostics; 
using System.Collections.Specialized; 


namespace App1 
{ 


    public class HouseGuest 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public string Role { get; set; } 
     public bool Deleted { get; set; } 
    } 

    public class HouseGuestGroup : IGrouping<string, HouseGuest> 
    { 
     public ObservableCollection<HouseGuest> Items { get; set; } 
     public string Role { get; set; } 
     public HouseGuestGroup() 
     { 
      Items = new ObservableCollection<HouseGuest>(); 
     } 

     public string Key 
     { 
      get { return Role; } 
     } 

     public IEnumerator<HouseGuest> GetEnumerator() 
     { 
      return Items.GetEnumerator(); 
     } 

     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
     { 
      return Items.GetEnumerator(); 
     } 


    } 

    public class BigBrotherModel : ObservableCollection<HouseGuestGroup> 
    { 
     public BigBrotherModel() 
     { 
      RemoveHouseGuestCommand = new DelegateCommand(RemoveHouseGuest); 
     } 

     public ICommand RemoveHouseGuestCommand { get; set; } 

     void RemoveHouseGuest(object param) 
     { 
      Debug.Assert(param is HouseGuest); 
      HouseGuest guest = param as HouseGuest; 

      foreach (var g in Items) 
      { 
       if (g.Role == guest.Role) 
       { 
        g.Items.Remove(guest); 
        break; 
       } 
      } 
     } 

    } 

    public sealed partial class MainPage : Page 
    { 

     public MainPage() 
     { 
      this.InitializeComponent(); 

      HouseGuestGroup guestGroup; 

      guestGroup = new HouseGuestGroup(); 
      guestGroup.Role = "Coach"; 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Britney", LastName = "Haynes", Role = "Coach" }); 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Dan", LastName = "Gheesling", Role = "Coach" }); 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Janelle", LastName = "Pierzina", Role = "Coach" }); 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Mike", LastName = "Boogie", Role = "Coach" }); 
      BBModel.Add(guestGroup); 



      guestGroup = new HouseGuestGroup(); 
      guestGroup.Role = "Player"; 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Ian", LastName = "Terry", Role = "Player" }); 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Shane", LastName = "Meaney", Role = "Player" }); 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Wil", LastName = "Heuser", Role = "Player" }); 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Danielle", LastName = "Murphree", Role = "Player" }); 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Jenn", LastName = "Arroyo", Role = "Player" }); 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Jodi", LastName = "Rollins", Role = "Player" }); 
      guestGroup.Items.Add(new HouseGuest() { FirstName = "Ashley", LastName = "Iocco", Role = "Player" }); 
      BBModel.Add(guestGroup); 

      groupInfo.Source = BBModel; 
     } 
    } 
} 

順便說一句,我認爲這是更好地把這個問題留給打開,希望一些更好的解決方案,可以出來最後。

回答

0

發生了什麼是LINQ語句每次都創建一個新列表,因此當您影響可觀察集合時,它不會被反映,因爲它們是兩個不同的列表。你需要做的是創建一個自定義的Group對象,其中有ObservableCollection來存儲客人。然後,您必須創建這些組的ObservableCollection。然後,您可以對靜態集合(或任何子集合)進行任何更改,並將其反映在您的視圖中。

然後,你可以做一些簡單直接給定的觀察到的集合像

void RemoveHouseGuest(object param) 
{ 
    Debug.Assert(param is HouseGuest); 
    if(houseGuests.Contains(param as HouseGuest)) 
     houseGuests.Remove(param); 
    //(param as HouseGuest).Deleted = true; 
    //RefreshListBox(); 
} 

希望這有助於和編碼快樂!

+0

Nate,感謝您的幫助。但似乎這個解決方案不起作用,當我點擊一個按鈕時,什麼也沒有發生。也許這樣做的原因是:ListBox的Datasource是由LINQ語句創建的視圖,而不是原始集合housegGuests。我只是不知道如何直接在命令中訪問ListBoxItem。如果我們可以獲得ListBoxItem的引用,那麼我們可以直接從ListBox中移除它。 – SimonFisher

+0

啊,的確如此。發生什麼事是LINQ語句每次都創建一個新列表,因此當您影響可觀察集合時,它不會被反映,因爲它們是兩個不同的列表。你需要做的是創建一個自定義的Group對象,其中有ObservableCollection來存儲客人。然後,您必須創建這些組的ObservableCollection。然後,您可以對靜態集合(或任何子集合)進行任何更改,並將其反映在您的視圖中。 –

+0

我試過了你的建議,確實有效。所以我會將你的建議標記爲對原始問題的回答。謝謝! – SimonFisher

相關問題