简体   繁体   中英

Xamarin Forms - set an image size in C# based on the original source file size

In Xamarin Forms I want to set the size of images based on the size of the original source file - taller if originally portrait.

On the pages OnAppearing I loop through a list of the images and use each images on successful load to work out the size I need then set the size on the page.

This works fine on ios for phone and tablet, but on Android I get the error

System.NullReferenceException: Object reference not set to an instance of an object

and the stack trace tells me it happened while trying:

Grid.CalculateAutoCells (System.Double width, System.Double height)

Which I think means the image hasn't had time to load, so doesn't have a width or height.

Based on the code, can anyone suggest any edit to get it to work?

EDIT:

Just noticed that it crashes intermittently, I can open the page from a carousel and it's fine, then I'll go back, open a different page, go back again and open the same page and it crashes.

 if (v.ContentType == Models.ContentType.Image)
                    {
                        CachedImage img = new CachedImage() { CacheType = FFImageLoading.Cache.CacheType.Memory };
                        var h = 0;
                        var w = 0;
                        img.Source = GetNextImage();

                        img.Success += (sender, e) =>
                        {
                            h = e.ImageInformation.OriginalHeight;
                            w = e.ImageInformation.OriginalWidth;

                            if (Device.Idiom == TargetIdiom.Phone)
                                {
                                    if (h > w)
                                        {
                                            img.HeightRequest = 350;
                                        }
                                        else
                                        {
                                            img.HeightRequest = 200;
                                        }
                                        retry = false;
                                   }
                            if (Device.Idiom == TargetIdiom.Tablet)
                            {
                                if (h > w)
                                {
                                    img.HeightRequest = 800;
                                }
                                else
                                {
                                    img.HeightRequest = 500;
                                }
                            }
                        };

In Android "OnAppearing" not grant that the page is fully loaded, so maybe you're calling an image that is not alredy "drawn" by android, that's why the errore is "intermittent"... there are many possible solution on the web but are more code-dependent.... maybe you can try something similar to that:

public YourPage()
        {
            InitializeComponent();

            my_image_resize_function();
        }

or maybe overriding it as Async:

protected override async void OnAppearing()
{
    base.OnAppearing();
    await Task.Delay(1000);
    my_image_resize_function();
}

Based on Legion's idea, maybe a better way to ensure the page is loaded first using a time delay is something like this? This stops OnAppearing() from blocking functions working on the page if OnAppearing() is run in an asynchronous manner (ie, as await OnAppearing() ):

protected override async void OnAppearing()
{
    base.OnAppearing();
    asynchronous_image_resize_function()
}

private async void asynchronous_image_resize_function()
{
    await Task.Delay(1000);
    my_image_resize_function();
}

In any case, a time delay approach isn't very robust anyways, so maybe it would be better to have a named element on the page that you can check for null to see if the page is completely loaded yet, eg replacing the time delay in the latter function with this:

private async void asynchronous_image_resize_function()
{
    while (test_element == null)
        await Task.Delay(50); //delay until it is loaded
    my_image_resize_function();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM