无法在MVVM UWP中取消选择ListView项

时间:2016-11-19 23:17:47

标签: c# mvvm uwp template10

我希望能够点击ListView项目,然后将我带到适当的页面。但由于ClickedItem不存在与ItemClick一起存在的任何内容,我必须使用SelectedItem(以获取用户点击的对象)和{ {1}}捕获它何时发生(因为这是以用户点击时的方式设置,他进行选择,触发此操作)。

因为在MVVM中我不能使用事件,所以我将事件绑定到我的ViewModel中的方法。

SelectionChanged

我在ViewModel中填写了我的列表。我正在使用INOifyPropertyChanged的Template10实现。

<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}"
>

当用户点击某个项目时,这个简单的方法会将我推到下一页。

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); } } 上的后退按钮时,我会在我离开时返回此列表,并且仍然会选中所单击的项目。因此,再次点击它实际上并没有做出选择并触发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); }属性的TextBlock被更改(或者更确切地说是清空)。

我想知道为什么没有这项工作,可能还有如何修复它。我的MVVM可能不完美,我还在学习。虽然它可能不完美,但我并不是在寻找如何正确编写MVVM的建议。我想知道为什么这不起作用,因为在我看来,它应该可以正常工作。

3 个答案:

答案 0 :(得分:2)

似乎GridView不喜欢在SelectionChanged处理程序中更改SelectedItem属性(如果不使用防护,则可能导致无限循环)。您可以在该页面的OnNavigatedTo处理程序中将SelectedItem设置为null(或者与模板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方法签名感到不安,那么您可以使用命令的参数绑定到单击的项目来创建自己的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已经为你提供了一些行为?我不熟悉它。

答案 1 :(得分:0)

我的第一直觉是检查您的Set方法,以确保它确实向视图发送了正确的通知。我不熟悉Template10的实现,所以我觉得你不需要提供一个带有Set()的属性名称。

除此之外,我建议您回到使用Click而不是SelectionChanged,因为这是您实际感兴趣的行为。您应该阅读一些关于附加属性的内容,这是完成任务的好方法。通常需要代码隐藏而不实际使用代码隐藏。它们使MVVM变得更加实用,而且不那么苛刻。

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

附加属性或多或少允许您定义可以附加到XAML中任何元素的DependencyProperty,如GridView。因为您可以访问setter中的Element,所以您可以自由附加到其事件。因此,您可以使用委托类型创建附加属性,该属性会将单击事件转发给委托。回到视图中,将它绑定到ViewModel中的处理程序,如下所示:

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

希望这有帮助!

答案 2 :(得分:0)

SelectedIndex = -1,在您的SelectedItem属性的空集后面?所以是的,需要另一个属性,或者确保也禁用该页面的缓存。