2016-11-19 78 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属性的空集之后?所以是需要另一个属性,或者确保该页面的缓存禁用。

相关问题