创建新窗口时,GridView.ItemsSource中断

时间:2018-11-30 19:05:39

标签: c# uwp uwp-xaml

在导航到新页面时运行代码:

this.Frame.Navigate(typeof(BlankPage1), pages);

当代码连接到BlankPage1.xaml.cs中的以下代码时,代码运行正常并产生正确的输出

protected override void OnNavigatedTo(NavigationEventArgs e)
{
        _thumbnails = e.Parameter as ObservableCollection<ThumbnailImage>;
        FileView.ItemsSource = _thumbnails;
}

但是,当我运行

CoreApplicationView newView = CoreApplication.CreateNewView();
int newViewId = 0;
await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
                Frame frame = new Frame();
                frame.MinHeight = 800;
                frame.MaxWidth = 400;
                frame.MinWidth = 200;
                frame.Navigate(typeof(BlankPage1), pages);
                Window.Current.Content = frame;
                Window.Current.Activate();
                newViewId = ApplicationView.GetForCurrentView().Id;
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);

要创建一个新的View并导航到相同的xaml文件,它将引发异常:“抛出异常:Viewer.exe中的'System.Exception''”

但是,当OnNavigatedTo更改为

protected override void OnNavigatedTo(NavigationEventArgs e)
{
        _thumbnails = e.Parameter as ObservableCollection<ThumbnailImage>;
        //FileView.ItemsSource = _thumbnails;
}

没有错误,但未填充GridView。

班级是

public class ThumbnailImage
{
    public BitmapImage Source { get; set; }
    public StorageFile File { get; set; }

    public ThumbnailImage(BitmapImage source, StorageFile file)
    {
        Source = source;
        File = file;
    }
}

xaml是

<Page Width="300" Height="850"
x:Class="Viewer.BlankPage1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Viewer"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
    <GridView x:Name="FileView" Width="256" Height="850" Margin="0,20,0,0">
        <GridView.ItemTemplate>
            <DataTemplate x:DataType="local:ThumbnailImage">
                <Grid>
                    <Button FontFamily="Segoe MDL2 Assets" Content="&#xE894;" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                    <Image CanDrag="True" Stretch="Uniform" Source="{x:Bind Source}" Height="100" Margin="10,40"/>
                    <Border Opacity=".8" Background="Black" VerticalAlignment="Bottom"/>
                </Grid>
            </DataTemplate>
        </GridView.ItemTemplate>
        <GridView.ItemsPanel>
            <ItemsPanelTemplate>
                <ItemsWrapGrid Orientation="Horizontal" ScrollViewer.VerticalScrollBarVisibility="Visible"/>
            </ItemsPanelTemplate>
        </GridView.ItemsPanel>
    </GridView>
</ScrollViewer>
</Page>

2 个答案:

答案 0 :(得分:1)

不建议在UWP中的两个不同视图之间传递ObservableCollection(或任何其他基于INotifyPropertyChanged-或INotifyCollectionChanged的模型),不推荐

原因是UWP中的每个视图都有其自己的UI线程,这也是您需要使用新创建的视图的Dispatcher导航到页面的原因。但是,当您使用数据绑定时,对集合的任何更改都将执行CollectionChanged,这将针对两个应用视图运行。这将不可避免地导致应用崩溃,因为CollectionChangedPropertyChanged影响UI,因此必须在特定视图的UI线程上运行-在这种情况下,每个视图都有自己的UI线程。

因此,为确保避免出现这些问题,请创建一个新集合,以确保每个视图都有自己的ObservableCollection实例:

var secondaryViewPages = new ObservableCollection<ThumbnailImage>(pages);
frame.Navigate(typeof(BlankPage1), secondaryViewPages);

注意:如果ThumbnailImage实现了INotifyPropertyChanged,则还必须为集合中的每个图像创建一个“副本”。但是,在这种情况下,ThumbnailImage是POCO是没有必要的,并且不会将其更改通知UI。

也请注意::不建议将集合用作参数Navigate,因为它会阻止您在应用暂停期间序列化应用状态,请参见docs

  

应用通常在应用暂停时使用GetNavigationState序列化框架的状态。您可以直接在应用程序代码中执行此操作,也可以使用Visual Studio模板生成的SuspensionManager类间接执行此操作。要使用GetNavigationState启用帧状态序列化,必须仅对导航参数使用基本类型,例如字符串,字符,数字和GUID类型。否则,当应用程序挂起时,GetNavigationState将引发异常。如果不使用GetNavigationState,则参数可以具有其他类型。

相反,您可以以不同的方式在视图之间共享数据,例如拥有两个视图都可以访问的单例服务。

答案 1 :(得分:0)

存在两个潜在问题:

  1. 您可能必须将呼叫延迟到frame.Navigate,直到应用程序加载完毕。在您的代码示例中,您尝试在将框架分配给Window.Current.Content之前进行导航。您可以尝试将其移动为lambda块的最后一行。您甚至可能需要同步运行导航,或者至少在UI线程上运行导航。

  2. RunAsync可能引起问题。您可以使用Dispatcher.Invoke进行测试,看看它是否仍然存在相同的问题。