2016-11-19 65 views
1

我希望能夠單擊ListView項目,然後將我帶到適當的頁面。但是由於ClickedItemItemClick一樣不存在,所以我必須使用SelectedItem(獲取用戶點擊的對象)和SelectionChanged來捕獲它(因爲這是以某種方式設置的當用戶點擊時,他做出選擇,這觸發了這一點)。無法取消選擇MVVM UWP中的ListView項目

由於在MVVM中我不能使用事件,我綁定了什麼是事件,我的ViewModel中的方法。

<GridView x:Name="MyGrid" 
    ItemsSource="{x:Bind ViewModel.myList, Mode=OneWay}" 
    VerticalAlignment="Stretch" 
    HorizontalAlignment="Stretch" 
    IsSwipeEnabled="false" 
    SelectedItem="{Binding mySelectedItem, Mode=TwoWay}" // Binding makes it easier to bind the whole object 
    SelectionChanged="{x:Bind ViewModel.SelectioMade}" 
> 

我在ViewModel中填充我的列表。我正在使用INotifyPropertyChanged的Template10實現。

private MyListItemClass _mySelectedItem; 
public MyListItemClass mySelectedItem{ 
    get { return _mySelectedItem; } 
    set { Set(ref _mySelectedItem, value); } 
} 

而這個簡單的方法將我推到下一個頁面,當用戶點擊一個項目。

public void SelectioMade() { 
    if (_mySelectedItem != null) { 
     NavigationService.Navigate(typeof(Views.DetailPage), _mySelectedItem.id); 
    } 
} 

This Works。

問題在於選擇已完成並且仍然存在。當我點擊DetailPage上的後退按鈕時,當我離開它並且點擊的項目仍然被選中時,我回到這個列表。因此,再次單擊它實際上不會進行選擇並觸發SelectionChanged

當我不再需要該值時,明顯的選擇似乎是將mySelectedItem設置爲null,但它不起作用。

public void SelectioMade() { 
    if (_mySelectedItem != null) { 
     NavigationService.Navigate(typeof(Views.DetailPage), _mySelectedItem.id); 
     mySelectedItem = null; 
    } 
} 

我似乎無法將其設置回null。如果我在mySelectedItem = null;上放置一個斷點,它就不會做任何事情。它會觸發set { Set(ref _mySelectedItem, value); },但視圖不會更新。被單擊的項目不會被取消選擇,也不會被綁定到mySelectedItem.id屬性之一的TextBlock被更改(或更確切地說,被清空)。

我想知道爲什麼不這樣做,並可能如何解決它。我的MVVM可能不完美,我仍然在學習。雖然它可能不完美,但我並不真正在尋找如何正確編寫MVVM的建議。我想知道爲什麼這不起作用,因爲在我看來,它應該工作得很好。

回答

2

似乎GridView不喜歡在SelectionChanged處理程序中更改SelectedItem屬性(如果不使用警衛,它可能會導致無限循環)。你可以改爲在該頁面的OnNavigatedTo處理程序中將SelectedItem設置爲null(或任何相當於Template 10的)。

另外,您並不需要訂閱SelectionChanged事件,因爲您可以在mySelectedItem屬性的setter中檢測到此事件。

但是,我認爲通過偵聽選擇已更改的事件來處理項目點擊是錯誤的,因爲可以通過其他方式(例如上/下箭頭鍵或Tab鍵)更改選擇內容。所有你想要做的就是迴應一個項目點擊並獲得點擊的項目,對不對?對於這一點,你可以X:綁定itemClick事件的方法,在您的視圖模型:

<GridView ItemClick="{x:Bind ViewModel.ItemClick}" SelectionMode="None" IsItemClickEnabled="True"> 
public void ItemClick(object sender, ItemClickEventArgs e) 
{ 
    var item = e.ClickedItem; 
} 

如果你不放心在你的視圖模型的項目單擊方法簽名,那麼你可以讓你自己的ItemClick行爲執行一個暴露在你的視圖模型中的命令,命令的參數綁定到點擊的項目。

如果你不使用行爲,因爲某些原因,那麼你就可以讓自己的附加屬性,而不是,是這樣的:

public class ViewHelpers 
{ 
    #region ItemClickCommand 

    public static readonly DependencyProperty ItemClickCommandProperty = 
     DependencyProperty.RegisterAttached("ItemClickCommand", typeof(ICommand), typeof(ViewHelpers), new PropertyMetadata(null, onItemClickCommandPropertyChanged)); 

    public static void SetItemClickCommand(DependencyObject d, ICommand value) 
    { 
     d.SetValue(ItemClickCommandProperty, value); 
    } 

    public static ICommand GetItemClickCommand(DependencyObject d) 
    { 
     return (ICommand)d.GetValue(ItemClickCommandProperty); 
    } 

    static void onItemClickCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var listView = d as ListViewBase; 
     if (listView == null) 
      throw new Exception("Dependency object must be a ListViewBase"); 

     listView.ItemClick -= onItemClick; 
     listView.ItemClick += onItemClick; 
    } 

    static void onItemClick(object sender, ItemClickEventArgs e) 
    { 
     var listView = sender as ListViewBase; 
     var command = GetItemClickCommand(listView); 
     if (command != null && command.CanExecute(e.ClickedItem)) 
      command.Execute(e.ClickedItem); 
    } 

    #endregion 
} 

XAML不需要MVVM模式中使用,這意味着有很多「缺失」的功能,你需要編寫自己的代碼才能使MVVM更加容易(比如上面的ItemClick附加屬性)。也許模板10已經爲你提供了一些行爲?我不熟悉它。

+0

我不知道/意識到,我可以用這種方式來綁定事件(第一個例子)。這真的很好知道(分享沒有人提到過我)。我雖然這樣綁定一個方法,但我無法訪問這些數據。在這種情況下,它會做得很好,儘管我可能最終需要實現一些EventToCommand事情。非常感謝! – rancor1223

0

我的第一本能是檢查你的Set方法,以確保它真的發送正確的通知給視圖。我對Template10實現不熟悉,所以我覺得你並不需要用Set()提供一個屬性名。

除此之外,我建議您返回使用Click而不是SelectionChanged,因爲這是您實際感興趣的行爲。您應該閱讀一些關於附加屬性的信息,這是完成任務的好方法通常需要代碼隱藏而不實際使用代碼隱藏。他們讓MVVM變得更加實用,而且更少了黑客。

https://msdn.microsoft.com/en-us/library/ms749011(v=vs.110).aspx

附加屬性,或多或少,允許你定義一個DependencyProperty,你可以連接到任何元素在XAML,像你的GridView。因爲你可以訪問setter中的Element,所以你可以自由地附加到它的事件。因此,您可以使用委託類型創建附加屬性,該委派類型會將點擊等事件轉發給委託。回到視圖中,您將其綁定到ViewModel中的處理程序,如下所示:

<GridView something:MyAttachedProperties.ClickHandler="{Binding MyClickHandler}" /> 

希望這有助於您!

+0

'Set'正在使用['CallerMemberName'](https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute(v = vs.110).aspx)屬性從調用者推斷屬性名稱。 –

0

SelectedIndex = -1,跟在SelectedItem屬性的空集之後?所以是需要另一個屬性,或者確保該頁面的緩存禁用。

相關問題