【问题标题】:When do items get reloaded in listview when navigating back using mvvm使用 mvvm 导航返回时,何时在列表视图中重新加载项目
【发布时间】:2015-12-28 13:44:07
【问题描述】:

我正在开发 UWP Windows 10 应用。它包含一个列表视图,当我点击一个项目时将您重定向到另一个页面我试图在导航回到上一页时重新选择最后一个项目。

我的列表视图的 ItemSource 绑定到 ObservableCollection 并按预期加载我的项目,但是当我返回导航时,它会保持项目处于选中状态但不可见。

我读过各种文章:

Make ListView.ScrollIntoView Scroll the Item into the Center of the ListView

ListViewBase.ScrollIntoView methods

Windows 10 ScrollIntoView() is not scrolling to the items in the middle of a listview

还有很多其他人,我尝试使用上面提到的上一篇文章中的扩展,它为Listview 提供了各种扩展,我认为我会很好,但无济于事!

在调查和尝试各种事情时,我想我应该打个电话

protected async override void OnNavigatedTo(NavigationEventArgs e)

并调用以下代码:

if (e.NavigationMode == NavigationMode.Back)
  {
    if (GetViewModel.SelectedChannel != null)
      {
        await this.lvwChannels.ScrollToIndex
              (GetViewModel.SelectedIndex);
      }
  }

if (e.NavigationMode == NavigationMode.Back)
  {
    if (GetViewModel.SelectedChannel != null)
      {
        await this.lvwChannels.ScrollToItem
              (GetViewModel.SelectedItem);
      }
  }

但它仍然无法正常工作。

这是当我注意到我的 Listview.Items.count 返回 0 并且该项目已重新加载时,但我认为它们将在稍后阶段重新加载,所以我的问题是:

但我注意到以下内容:

  1. 单步执行扩展程序时,

    public async static Task ScrollToIndex(this ListViewBase listViewBase, int index)

我的listViewBase.Items.Count 是 0??为什么?

  1. 尝试在 ListView 中查找 ScrollViewer 时,找不到?

  2. 调用时

    var selectorItem = listViewBase.ContainerFromIndex(index) as SelectorItem;

selectorItem 为空,因为它没有根据索引找到任何内容。索引是唯一似乎设置正确的东西,即 10、23、37

有人可以指出正确的方向吗?我认为这是一个时间问题,并且我的 ObservableCollection 在此阶段尚未重新绑定。我可以在调用 ScrollIntoView 之前重新绑定,但这仍然无法解决我的 listViewBase 为空的事实。

有什么想法吗?

谢谢。

【问题讨论】:

  • 我已经尝试按照本文中的建议附加一个属性:stackoverflow.com/questions/18019425/…,虽然我的列表视图包含数据,并且它调用了 ScrollIntoView,但它仍然没有显示相关项目!!!

标签: c# listview mvvm win-universal-app


【解决方案1】:

这似乎是一个时间问题,虽然我不能 100% 确定这是解决问题的正确方法,但它似乎已经通过在 Loaded 事件中调用 ScrollIntoView 来解决它:

    private void Page_Loaded(object sender, RoutedEventArgs e)
    {
        if (GetViewModel.SelectedChannel != null)
            lvwChannels.ScrollIntoView(GetViewModel.SelectedChannel);
    }

我想我也没有违反任何 MVVM 规则,因为它只在这个阶段处理 UI。

当从 Loaded 事件调用时,我的 ObservableCollection 都已自动重新加载,因为它已绑定,并且 SelectedChannel 也已正确设置,一切似乎都按预期工作。

正如我在下面的回复中提到的,默认情况下,所选项目现在突出显示并显示在列表顶部,我希望它居中。

如果有更好的方法可以做到这一点,请告诉我,但现在必须这样做。

谢谢

【讨论】:

    【解决方案2】:

    您在哪里将数据添加到 ObservableCollection?我不确定你是怎么做到的。对我来说,以下方法效果很好:

    public sealed partial class MainPage : Page
    {
        ObservableCollection<listText> list = new ObservableCollection<listText>();
        static int selectedcount = -1;
    
    
    public MainPage()
    {
        this.InitializeComponent();
        mylist.ItemsSource = list;
    }
    
    class listText
    {
        public string listtxt { get; set; }
    }
    
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        list.Clear();
        list.Add(new listText { listtxt = "Item1" });
        list.Add(new listText { listtxt = "Item2" });
    
        mylist.SelectedIndex = selectedcount;
    }
    
    private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        switch (mylist.SelectedIndex)
        {
            case 0:
                selectedcount = 0;
                this.Frame.Navigate(typeof(Item1));                    
                break;
    
            case 1:
                selectedcount = 1;
                this.Frame.Navigate(typeof(Item2));
                break;
    
            default:
                selectedcount = 0;
                this.Frame.Navigate(typeof(Item1));
                break;
        }
    }
    }
    

    而我在 App.xaml.cs 中编写的 NavigateBack 代码如下:

            private void App_BackRequested(object sender, BackRequestedEventArgs e)
            {
                Frame rootFrame = Window.Current.Content as Frame;
                if (rootFrame == null)
                    return;
    
                // Navigate back if possible, and if the event has not 
                // already been handled .
                if (rootFrame.CanGoBack && e.Handled == false)
                {
                    e.Handled = true;
                    rootFrame.GoBack();
                }
            }
    
            /// <summary>
            /// Invoked when the application is launched normally by the end user.  Other entry points
            /// will be used such as when the application is launched to open a specific file.
            /// </summary>
            /// <param name="e">Details about the launch request and process.</param>
            protected override void OnLaunched(LaunchActivatedEventArgs e)
            {
    
    //#if DEBUG
    //            if (System.Diagnostics.Debugger.IsAttached)
    //            {
    //                this.DebugSettings.EnableFrameRateCounter = true;
    //            }
    //#endif
    
                Frame rootFrame = Window.Current.Content as Frame;
                Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested += App_BackRequested;
                // Do not repeat app initialization when the Window already has content,
                // just ensure that the window is active
                if (rootFrame == null)
                {
                    // Create a Frame to act as the navigation context and navigate to the first page
                    rootFrame = new Frame();
    
                    rootFrame.NavigationFailed += OnNavigationFailed;
    
                    if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                    {
                        //TODO: Load state from previously suspended application
                    }
    
                    // Place the frame in the current Window
                    Window.Current.Content = rootFrame;
                }
    
                if (rootFrame.Content == null)
                {
                    // When the navigation stack isn't restored navigate to the first page,
                    // configuring the new page by passing required information as a navigation
                    // parameter
                    rootFrame.Navigate(typeof(MainPage), e.Arguments);
                }
                // Ensure the current window is active
                Window.Current.Activate();
            }
    

    我将我的数据添加到OnNavigatedTo 中的ObservableCollection,这个OnNavigatedTo 将在导航返回时被调用,所以我的列表视图的计数不会为0。 希望对您有所帮助。

    【讨论】:

    • 嗨,我的 ObservableCollection 是在特定页面的 ViewModel 中设置的,我可以清楚地看到它被调用,但如上所述,这是一个时间问题。几分钟前,我通过从 Loaded 事件中调用内置的 ScrollIntoView 设法解决了这个问题。在这个阶段调用时,似乎我的收藏已完全重新加载。我将查看上面提到的一篇文章,当它重新选择它时,它会将项目放在页面的最顶部,如果它位于列表的中间,我更喜欢它。
    猜你喜欢
    • 2011-04-14
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 1970-01-01
    • 2018-05-22
    相关资源
    最近更新 更多