Need to draw rectangles on top of image in FlipView, but FlipView loads 3 images at a time

54 Views Asked by At

I have a collection of images i want to show with FlipView. On each image I want to draw multiple rectangles, but to do this I need the current dimensions for the image after it has been rendered. I have the coordinates for the rectangles in the same list as my images. I get the dimensions from the images via ImageOpened event, but the problem is the FlipView event loads three images at the same time causing the different rectangles all to be drawn on the first image. Any suggestions?

    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        itemList = e.Parameter as List<TableData>;

        foreach (var blobImage in itemList)
        {
            var request = (HttpWebRequest)WebRequest.Create($"http://localhost:58941/api/image?id={blobImage.ImageBlobName}");
            request.Method = "GET";
            request.ContentType = "application/json";
            WebResponse response = await request.GetResponseAsync();

            if (response != null)
            {
                string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

                var myDict = JsonConvert.DeserializeObject<BlobImage>(responseString);

                var jj = new MyImage(blobImage.ImageDescription, myDict.Uri, blobImage.GpsLatitude, blobImage.GpsLongitude, blobImage.GpsAltitude, blobImage.DateTime, blobImage.ObjectsDetected);

                MyImages.Add(jj);

            }
        }

        MyFlipView.ItemsSource = MyImages;

    }

    private void Image_ImageOpened(object sender, RoutedEventArgs e)
    {
        Image currentImageDimensions = sender as Image;

        currentWidth = currentImageDimensions.ActualWidth;
        currentHeight = currentImageDimensions.ActualHeight;

        foreach (var imageRectangle in itemList)
        {
            for (int i = 0; i < imageRectangle.ObjectsDetected.Count; i++)
            {
                rectangle = new Rectangle();

                var xMinConvert = Convert.ToDouble(imageRectangle.ObjectsDetected[i].xMin);
                var yMinConvert = Convert.ToDouble(imageRectangle.ObjectsDetected[i].yMin);
                var xMaxConvert = Convert.ToDouble(imageRectangle.ObjectsDetected[i].xMax);
                var yMaxConvert = Convert.ToDouble(imageRectangle.ObjectsDetected[i].yMax);

                var xMin = xMinConvert * currentWidth;
                var yMin = yMinConvert * currentHeight;
                var xMax = xMaxConvert * currentWidth;
                var yMax = yMaxConvert * currentHeight;

                rectangle.Height = yMax - yMin;
                rectangle.Width = xMax - xMin;

                var left = ((bgWidth - currentWidth) / 2) + xMin;
                var top = ((bgHeight - currentHeight) / 2) + yMin;

                rectangle.Margin = new Thickness(left, top, 0, 0);
                rectangle.Stroke = new SolidColorBrush(Windows.UI.Colors.Red);
                rectangle.StrokeThickness = 1;

                layoutRoot.Children.Add(rectangle);
            }

        }

    }

Xaml:

        <ScrollViewer DoubleTapped="scrollViewer_DoubleTapped" MinZoomFactor="1" ZoomMode="Enabled" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">

            <Grid x:Name="cGrid" Width="{Binding ElementName=gridbg, Path=ActualWidth}" Height="{Binding ElementName=gridbg, Path=ActualHeight}">

                    <FlipView SelectionChanged="MyFlipView_SelectionChanged" Name="MyFlipView" Width="{Binding ElementName=gridbg, Path=ActualWidth}" Height="{Binding ElementName=gridbg, Path=ActualHeight}">

                        <FlipView.ItemTemplate>
                            <DataTemplate x:DataType="local:MyImage">

                                    <Image Source="{Binding Image}" Stretch="Uniform" Height="{Binding ElementName=gridbg, Path=ActualHeight}"  ImageOpened="Image_ImageOpened" />

                            </DataTemplate>
                        </FlipView.ItemTemplate>
                    </FlipView>

                </Border>

                    <Canvas x:Name="layoutRoot">
                    </Canvas>

            </Grid>

        </ScrollViewer>
1

There are 1 best solutions below

0
Sunteen Wu On

but FlipView loads 3 images at a time

FlipView control supports virtualization at default, load three items at one time is as expected. If disabled the virtualization, all the items will be loaded into the FlipView at one time.

You have several ways to resolve your issue. Since you only need the Rectangle drawing when one FlipViewItem selected, you could put the drawing relative code snippet inside SelectionChanged event handle of FlipView. By doing this you may encounter the issue for getting the Image height and width. Actually you should be able to know the image metadata by getting StorageFile object from uri of the image. If you just want to get the Image control for getting the Height and Width, you may use VisualTreeHelper to get the Image control from FlipView.

Or you could consider to force load only one item to the FlipView each time. For this you could use ISupportIncrementalLoading for incremental loading.

I'm not sure what you are drawing these rectangles for, consider to draw these rectangles to the image before you binding the images to the FlipView if possible.