UWP InkCanvas内存不足 [英] UWP InkCanvas Out Of Memory

查看:87
本文介绍了UWP InkCanvas内存不足的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用MVVMLight来创建调查表,并在渲染InkCanvas控件时遇到内存问题.这是我正在使用的示例的简化示例:

I'm using MVVMLight to create a questionnaire and running into memory issues when rendering the InkCanvas controls. Here's a watered down example of what I am working with:

QuestionVm

public Question Question { get; set; }
public HandwritingControl HandwritingControl { get; set; }

QuestionnaireVm

public List<QuestionVm> currentQuestions;
public List<QuestionVm> CurrentQuestions
{
    get { return currentQuestions; }
    set
    {
        currentQuestions = value;
        RaisePropertyChanged();
    }
}

Questionnaire.xaml.cs

//Clear form & iterate questions
questionnaireForm.Children.Clear();
foreach (var questionVm in questionnaireVm.CurrentQuestions)
{ 
  questionnaireForm.Children.Add(questionVm.Question);
  if(questionVm.HandwritingControl != null)
    questionnaireForm.Children.Add(new InkCanvas());
}

每次页面加载时RAM都会增加,并且很明显分配给InkCanvas的内存永远不会被释放.在第三页左右的页面上,当大约渲染了约125个InkCanvas控件时,该应用程序将引发System.OutOfMemoryException.

The RAM spikes on each page load and it's clear the memory allocated to the InkCanvas is never being deallocated. On the third or so page when roughly ~125 InkCanvas controls are rendered, the app throws a System.OutOfMemoryException.

我的问题是,为什么不取消分配这些控件?以及如何手动释放内存?如果我将InkCanvas注释掉,则问卷调查很好,而Children.Clear()似乎正在清理TextBlocks或其他任何控件.

My question is, why aren't these controls being deallocated? And how can I manually free up the memory? If I comment out the InkCanvas, the questionnaire is fine and Children.Clear() appears to be cleaning up the TextBlocks or any other controls without issue.

更新

因此,在与@Grace Feng合作之后,我尝试重构我的方法,并使用带有数据模板的ListView,而不是从xaml.cs创建网格.

So after working with @Grace Feng I tried to refactor my approach and use a ListView with a data template rather than creating a grid from my xaml.cs.

Questionnaire.xaml

                <ListView Name="questionnaireListView" ItemsSource="{Binding CurrentQuestions, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Question.Text}" />
                            <TextBlock Text="{Binding Question.Description}" />
                            <InkCanvas/>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

Questionnaire.xaml.cs

    private void buttonNext_Click(object sender, RoutedEventArgs e)
    {
        //Validate & goto next page
        if (questionnaireVm.CurrentPageIsValid())
        {
            questionnaireVm.CurrentQuestions.Clear();
            questionnaireVm.LoadNextPage();
        }
    }

不幸的是,即使使用ListView数据模板方法,我仍然遇到相同的内存不足错误.有想法吗?

Unfortunately I am still experiencing the same out of memory error even using the ListView data template method. Thoughts?

推荐答案

在大约大约125个InkCanvas控件呈现的第三页左右,应用程序引发System.OutOfMemoryException.

On the third or so page when roughly ~125 InkCanvas controls are rendered, the app throws a System.OutOfMemoryException.

我只是重现了这个问题,是的,您对此是正确的.

I just reproduced this problem, and yes you are right about this.

我的问题是,为什么不取消分配这些控件?

My question is, why aren't these controls being deallocated?

从Questionnaire.xaml.cs中的代码中,我认为您正在动态地将questionVm.QuestionInkCanvas的新实例添加到名为"questionnaireForm"的父控件中,并且在执行此操作之前,先清除了此父控件.加载数据时没有取消分配"操作,因此这些控件都不会被释放.

From the code in your Questionnaire.xaml.cs, I think you are dynamic adding questionVm.Question and a new instance of InkCanvas to the parent control named "questionnaireForm", and before doing this, you clear the children of this parent control. There is no "deallocating" action during you load your data, so none of these controls will be deallocated.

该如何手动释放内存?如果我将InkCanvas注释掉,则问卷调查很好,而Children.Clear()似乎正在清理TextBlocks或任何其他控件而没有问题.

And how can I manually free up the memory? If I comment out the InkCanvas, the questionnaire is fine and Children.Clear() appears to be cleaning up the TextBlocks or any other controls without issue.

如果手动释放内存,则需要删除其中一些InkCanvas,或者我认为对于这种情况,您可以正确地使用UI虚拟化来减少加载数据时的内存丢失.

If you manually free up the memory, you will need to remove some of these InkCanvas, or I think what you can do right is for this scenario is using UI virtualization to reduce the memory loss when you load data.

在UWP APP中,已经有两个具有UI虚拟化功能的控件,

In an UWP APP, there are two controls which have UI virtualization function already, ListView and GridView. I just test these two controls with over 125 instance of empty InkCnavas. The Item's size of GridView is adaptive to its layout in the item, so when the InkCanvas is empty, it will still load all data at once, the out of memory error will still happen. But the ListView control by default will take one row to hold its items, the UI Virtualization works fine here.

我看到您在questionVm.HandwritingControl != null的基础上添加了InkCanvas,因此这是一种解决方法,例如,您可以像这样设计Questionnaire.xaml:

And I saw that you add InkCanvas based on the questionVm.HandwritingControl != null, so here is a workaround, you can for example design your Questionnaire.xaml like this:

<Page.Resources>
    <DataTemplate x:Key="NoInkCanvasDataTemplate">
        <TextBlock Text="{Binding Questions}" />
    </DataTemplate>
    <DataTemplate x:Key="InkCanvasDataTemplate">
        <StackPanel>
            <TextBlock Text="{Binding Questions}" />
            <InkCanvas></InkCanvas>
        </StackPanel>
    </DataTemplate>
    <local:CustomDataTemplateSelector x:Key="InkCanvasDataTemplateSelector" NoInkCanvas="{StaticResource NoInkCanvasDataTemplate}" InkCanvas="{StaticResource InkCanvasDataTemplate}"></local:CustomDataTemplateSelector>
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView x:Name="listView" ItemTemplateSelector="{StaticResource InkCanvasDataTemplateSelector}" />
</Grid>

在后面的代码中,例如:

And in the code behind for example:

private ObservableCollection<CurrentQuestions> questions = new ObservableCollection<CurrentQuestions>();

public MainPage()
{
    this.InitializeComponent();
    listView.ItemsSource = questions;
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    questions.Clear();
    foreach (var questionVm in questionnaireVm.CurrentQuestions)
    {
        //Add your data here
    }
}

并创建一个CustomDataTemplateSelector类,如下所示:

And create a CustomDataTemplateSelector class like this:

public class CustomDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate NoInkCanvas
    {
        get;
        set;
    }

    public DataTemplate InkCanvas
    {
        get;
        set;
    }

    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        var canvas = item as HandwritingControl;
        if (canvas == null)
        {
            return this.NoInkCanvas;
        }
        else
        {
            return InkCanvas;
        }
    }
}

简而言之,您可以使用ListView控件及其ItemTemplateSelector来执行此操作,因为我没有您的所有代码,因此上述代码只是示例,并非100%正确地适合您的情况.

In a few words, you can do this with a ListView control and its ItemTemplateSelector, since I don't have all your code, the above code is just a sample, not 100% correctly for your case.

这篇关于UWP InkCanvas内存不足的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆