microsoft / Win2D

Win2D is an easy-to-use Windows Runtime API for immediate mode 2D graphics rendering with GPU acceleration. It is available to C#, C++ and VB developers writing apps for the Windows Universal Platform (UWP). It utilizes the power of Direct2D, and integrates seamlessly with XAML and CoreWindow.
http://microsoft.github.io/Win2D
Other
1.81k stars 285 forks source link

CanvasVirtualControl won't invalidate regions if situated inside RelativePanel #427

Closed octav84 closed 8 years ago

octav84 commented 8 years ago

Hi, I have a CanvasVirtualControl inside a RelativePanel XAML (UWP) control. Well, the exact structure is more complicated, but the only thing I noticed is the RelativePanel has something to do with it. The CanvasVirtualControl won't invalidate regions. Previously, there was a Grid instead of the RelativePanel and everithing worked fine. I happen to need the RelativePanel because it fixes another bug.

This is the XAML of the page:

 <Page x:Class="Cerner.Pulse.UI.Views.ReviewViews.LabResultsPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
  xmlns:converters="using:Cerner.Pulse.UI.Converters"
  xmlns:core="using:Microsoft.Xaml.Interactions.Core"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:data="using:Cerner.Pulse.UI.Util.ReviewUtil"
  xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:uc="using:Cerner.Pulse.UI.UserControls"
  xmlns:utils="using:Cerner.Pulse.UI.Util"
  DataContext="{Binding LabResultsViewModel,
                        Source={StaticResource locator}}"
  Loaded="Page_Loaded"
  mc:Ignorable="d">
<Page.Resources>
    <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    <converters:BooleanToInvisibilityConverter x:Key="BooleanToInvisibilityConverter" />
</Page.Resources>
<!--<Grid x:Name="MainGrid">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>-->

<RelativePanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <Popup x:Name="LabResultsPopup"
           HorizontalOffset="{Binding LabResultPopupPosition.X}"
           IsLightDismissEnabled="True"
           VerticalOffset="{Binding LabResultPopupPosition.Y}">
        <uc:LabResultsDetailsPopup x:Name="LabResultsDetailsUserControl" />
    </Popup>

    <uc:PageHeader x:Name="LabResultsPageHeader"
                   HasLeftSideButtonSet="True"
                   HasLeftSideGlyphButton="True"
                   HasLeftSideTextButton="True"
                   HasRightSideButtonSet="False"
                   LeftSideButtonCommand="{Binding NavigateBackCommand}"
                   LeftSideButtonGlyphCode="&#xE973;"
                   LeftSideButtonText="{Binding LeftSideButtonText}"
                   PageTitle="{Binding PageTitle}"
                   RelativePanel.AlignLeftWithPanel="True"
                   RelativePanel.AlignRightWithPanel="True"
                   RelativePanel.AlignTopWithPanel="True" />

    <!--  Filters  -->

    <Border Name="FiltersBorder"
            Height="{StaticResource DefaultPageTitleHeight}"
            Background="{StaticResource LabResultsCategoriesOddRowBackground}"
            BorderBrush="{StaticResource DividerLineBrush}"
            BorderThickness="0,0,0,1"
            RelativePanel.AlignLeftWithPanel="True"
            RelativePanel.AlignRightWithPanel="True"
            RelativePanel.Below="LabResultsPageHeader">
        <RelativePanel Margin="15,0,15,0"
                       HorizontalAlignment="Stretch"
                       VerticalAlignment="Stretch">
            <!--
                a weird bug appears if opening popup from viewmodel: open Lab Results, go back, open Lab Results
                again and now open a filters popup: BANG - 2 popups show instead of 1
                Open popup from page instead and it's ok
            -->
            <RelativePanel Width="430" RelativePanel.AlignHorizontalCenterWithPanel="True">
                <Button Name="SectionsFilterButton"
                        Margin="100,0,0,0"
                        RelativePanel.AlignLeftWithPanel="true"
                        Style="{StaticResource DefaultTextButton}"
                        Tapped="SectionsFilterButton_Tapped">
                    <!--<interactivity:Interaction.Behaviors>
                    <core:EventTriggerBehavior EventName="Tapped">
                        <core:InvokeCommandAction Command="{Binding ShowSectionsFilterCommand, Mode=OneWay}" />
                    </core:EventTriggerBehavior>
                </interactivity:Interaction.Behaviors>-->
                    <StackPanel Orientation="Horizontal">
                        <TextBlock FontSize="{StaticResource SmallTextSize}"
                                   Style="{StaticResource DefaultButtonTextBlockStyle}"
                                   Text="{Binding SectionsFilterButtonText}" />
                        <TextBlock Margin="3,6,0,0"
                                   FontWeight="Bold"
                                   Style="{StaticResource SmallButtonGlyphBlockStyle}"
                                   Text="&#xE936;" />
                    </StackPanel>
                </Button>

                <Popup x:Name="SectionsFilterPopup"
                       Width="300"
                       Closed="Popup_Closed"
                       IsLightDismissEnabled="True"
                       IsOpen="{Binding IsOpenSectionsFilterPopup,
                                        Mode=TwoWay}"
                       Opened="Popup_OnOpened"
                       RelativePanel.AlignLeftWithPanel="True"
                       RelativePanel.Below="SectionsFilterButton">
                    <uc:LabResultsSectionsFilterPopup x:Name="LabResultsSectionsFilter" />
                </Popup>

                <Button Name="NormalcyFilterButton"
                        Margin="0,0,100,0"
                        RelativePanel.AlignRightWithPanel="True"
                        Style="{StaticResource DefaultTextButton}"
                        Tapped="NormalcyFilterButton_Tapped">
                    <!--<interactivity:Interaction.Behaviors>
                    <core:EventTriggerBehavior EventName="Tapped">
                        <core:InvokeCommandAction Command="{Binding ShowNormalcyFilterCommand, Mode=OneWay}"
                                                  CommandParameter="{Binding RelativeSource={RelativeSource Self }, Path=Parent}" />
                    </core:EventTriggerBehavior>
                </interactivity:Interaction.Behaviors>-->
                    <StackPanel Orientation="Horizontal">
                        <TextBlock FontSize="{StaticResource SmallTextSize}"
                                   Style="{StaticResource DefaultButtonTextBlockStyle}"
                                   Text="{Binding NormalcyFilterButtonText}" />
                        <TextBlock Margin="3,6,0,0"
                                   FontWeight="Bold"
                                   Style="{StaticResource SmallButtonGlyphBlockStyle}"
                                   Text="&#xE936;" />
                    </StackPanel>
                </Button>

                <Popup x:Name="NormalcyFilterPopup"
                       Width="300"
                       Closed="Popup_Closed"
                       IsLightDismissEnabled="True"
                       IsOpen="{Binding IsOpenNormalcyFilterPopup,
                                        Mode=TwoWay}"
                       Opened="Popup_OnOpened"
                       RelativePanel.AlignRightWithPanel="True"
                       RelativePanel.Below="NormalcyFilterButton">
                    <uc:LabResultsNormalcyFilterPopup x:Name="LabResultsNormalcyFilterPopup" />
                </Popup>

            </RelativePanel>

            <Button Name="ResetFiltersButton"
                    IsEnabled="{Binding IsResetFilterButtonEnabled}"
                    RelativePanel.AlignHorizontalCenterWithPanel="true"
                    RelativePanel.AlignRightWithPanel="True"
                    Style="{StaticResource DefaultTextButton}">
                <interactivity:Interaction.Behaviors>
                    <core:EventTriggerBehavior EventName="Tapped">
                        <core:InvokeCommandAction Command="{Binding ResetButtonCommand, Mode=OneWay}" />
                    </core:EventTriggerBehavior>
                </interactivity:Interaction.Behaviors>
                <TextBlock x:Uid="reset"
                           FontSize="{StaticResource SmallTextSize}"
                           Style="{StaticResource DefaultButtonTextBlockStyle}" />
            </Button>
        </RelativePanel>
    </Border>

    <!--USING THIS GRID MAKES THE CANVAS VIRTUAL CONTROL WORK-->
    <!--<Grid RelativePanel.Below="FiltersBorder" Visibility="{Binding IsLoading, Converter={StaticResource BooleanToInvisibilityConverter}}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>-->

    <!--USING THIS RELATIVE PANEL MAKES THE ON_REGIONS_INVALIDATED NOT FIRE-->
    <RelativePanel RelativePanel.Below="FiltersBorder" Visibility="{Binding IsLoading, Converter={StaticResource BooleanToInvisibilityConverter}}">

        <!--  Categories & "Most recent result" column  -->
        <ListView x:Name="CategoriesPanel"
                  Margin="0, 0, 0, 0"
                  Background="Transparent"
                  IsItemClickEnabled="True"
                  ItemContainerStyle="{StaticResource LabResultsCategoriesListViewItemStyle}"
                  ItemTemplate="{StaticResource CategoriesItemTemplate}"
                  ItemsSource="{x:Bind Path=LabResultsViewModel.LabResultsDetailsCollection.View, Mode=OneWay}"
                  RelativePanel.AlignLeftWithPanel="True"
                  ScrollViewer.VerticalScrollBarVisibility="Hidden">
            <ListView.GroupStyle>
                <GroupStyle HeaderContainerStyle="{StaticResource LabResultsCategoriesHeaderStyle}" HeaderTemplate="{StaticResource CategoriesHeaderTemplate}" />
            </ListView.GroupStyle>
            <interactivity:Interaction.Behaviors>
                <core:EventTriggerBehavior EventName="Loaded">
                    <core:InvokeCommandAction Command="{Binding BindListViewCommand, Mode=OneWay}" CommandParameter="{Binding ElementName=CategoriesPanel}" />
                </core:EventTriggerBehavior>
                <core:EventTriggerBehavior EventName="ItemClick">
                    <core:InvokeCommandAction Command="{Binding CategoriesPanelItemClick}" />
                </core:EventTriggerBehavior>
            </interactivity:Interaction.Behaviors>
        </ListView>

        <!--  Values table  -->
        <ScrollViewer HorizontalScrollBarVisibility="Auto"
                      ManipulationMode="All"
                      RelativePanel.AlignRightWithPanel="True"
                      RelativePanel.RightOf="CategoriesPanel"
                      Style="{StaticResource CanvasScrollViewerStyle}"
                      VerticalScrollBarVisibility="Disabled">
            <!--<Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>-->

            <RelativePanel>
                <ListView x:Name="ValuesHeaderListView"
                          Margin="0"
                          ItemContainerStyle="{StaticResource LabResultsValuesListHeaderItemTemplate}"
                          ItemTemplate="{StaticResource ValuesHeaderTemplate}"
                          ItemsSource="{Binding HospitalizationDates}"
                          Padding="0"
                          RelativePanel.AlignLeftWithPanel="True"
                          RelativePanel.AlignRightWithPanel="True">
                    <ListView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <ItemsStackPanel Margin="0" Orientation="Horizontal" />
                        </ItemsPanelTemplate>
                    </ListView.ItemsPanel>
                </ListView>

                <ScrollViewer x:Name="CanvasScroll"
                              HorizontalScrollBarVisibility="Disabled"
                              RelativePanel.AlignLeftWithPanel="True"
                              RelativePanel.AlignRightWithPanel="True"
                              VerticalScrollBarVisibility="Auto"
                              VerticalScrollMode="Enabled"
                              ZoomMode="Disabled">
                    <!--  Tapped="LabResultsCanvas_OnTapped"  -->
                    <canvas:CanvasVirtualControl x:Name="LabResultsCanvas"
                                                 ClearColor="White"
                                                 CreateResources="LabResultsCanvas_CreateResources"
                                                 DataContext="{Binding CanvasMatrixChanged,
                                                                       Mode=OneWay}"
                                                 DataContextChanged="LabResultsCanvas_DataContextChanged"
                                                 Loaded="LabResultsCanvas_OnLoaded"
                                                 RegionsInvalidated="OnRegionsInvalidated"
                                                 Unloaded="LabResultsCanvas_OnUnloaded" />
                </ScrollViewer>
                <!--</Grid>-->
            </RelativePanel>
        </ScrollViewer>
    </RelativePanel>
    <!--</Grid>-->

    <ProgressBar Grid.Row="2"
                 Margin="7"
                 VerticalAlignment="Center"
                 Foreground="{StaticResource DividerLineBrushDark}"
                 IsIndeterminate="True"
                 Visibility="{Binding IsLoading,
                                      Converter={StaticResource BooleanToVisibilityConverter}}" />
    <!--</Grid>-->
</RelativePanel>

This is the code behind:

using Cerner.Pulse.Common.Enums; using Cerner.Pulse.UI.Util; using Cerner.Pulse.UI.Util.ReviewUtil; using Cerner.Pulse.UI.ViewModels.LabResults; using GalaSoft.MvvmLight.Ioc; using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.Brushes; using Microsoft.Graphics.Canvas.UI; using Microsoft.Graphics.Canvas.UI.Xaml; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Windows.Foundation; using Windows.UI; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace Cerner.Pulse.UI.Views.ReviewViews { ///

/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>

public sealed partial class LabResultsPage : Page
{
    public LabResultsViewModel LabResultsViewModel { get; set; }
    private static bool isDirty;
    private bool isCanvasLoaded = false;        

    ScrollViewer categoriesListScroll;
    private LabResultRectangleGraphicProcessor labResultsGraphicProcessor;
    private Dictionary<int, CanvasBitmap> IconsDictionary { get; set; }
    //private double exactItemWidthToComplyWithHeader = 150;
    private List<Point> tableHeaderItemsCoordinates;

    private const double OPACITY_FACTOR = 0.3;
    private const double NO_OPACITY = 1;

    public LabResultsPage()
    {
        InitializeComponent();

        LabResultsViewModel = SimpleIoc.Default.GetInstance<LabResultsViewModel>();
        labResultsGraphicProcessor = new LabResultRectangleGraphicProcessor();
        IconsDictionary = new Dictionary<int, CanvasBitmap>();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        //keep filters if navigated back from Details view or from Phone Filters pages
        if (e.NavigationMode == NavigationMode.Back)
            return;

        LabResultsViewModel.SelectedResultCategoryName = e.Parameter.ToString();                        
        LabResultsViewModel.Filters = new Common.Models.LabResultsFilter { FlagFilter = null, GroupIds = null }; // to reset filtering
    }

    private ScrollViewer GetScrollViewer(DependencyObject depObj)
    {
        if (depObj is ScrollViewer) return depObj as ScrollViewer;

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            var child = VisualTreeHelper.GetChild(depObj, i);

            var result = GetScrollViewer(child);
            if (result != null) return result;
        }
        return null;
    }

    private void Page_Loaded(object sender, RoutedEventArgs e)
    {
        categoriesListScroll = GetScrollViewer(CategoriesPanel);

        categoriesListScroll.RegisterPropertyChangedCallback(ScrollViewer.VerticalOffsetProperty, (s, dp) =>
        {
            CanvasScroll.ChangeView(CanvasScroll.HorizontalOffset,
                categoriesListScroll.VerticalOffset, CanvasScroll.ZoomFactor, true);
        });

        CanvasScroll.RegisterPropertyChangedCallback(ScrollViewer.VerticalOffsetProperty, (s, dp) =>
        {
            categoriesListScroll.ChangeView(categoriesListScroll.HorizontalOffset,
                CanvasScroll.VerticalOffset, categoriesListScroll.ZoomFactor, true);
        });

        LabResultsCanvas?.Invalidate();
    }

    private void Popup_Closed(object sender, object e)
    {
        Background = new SolidColorBrush(Colors.Transparent);
        Opacity = NO_OPACITY;
        LabResultsViewModel.IsOpenLabResultPopup = false;
        LabResultsViewModel.IsOpenNormalcyFilterPopup = false;
    }

    private void SectionsPopup_Closed(object sender, object e)
    {
        Background = new SolidColorBrush(Colors.Transparent);
        LabResultsViewModel.IsOpenSectionsFilterPopup = false;
        Opacity = NO_OPACITY;
    }

    private void NormalciesPopup_Closed(object sender, object e)
    {
        Background = new SolidColorBrush(Colors.Transparent);
        LabResultsViewModel.IsOpenNormalcyFilterPopup = false;
        Opacity = NO_OPACITY;
    }

    private void LabResultsCanvas_CreateResources(CanvasVirtualControl sender, CanvasCreateResourcesEventArgs args)
    {
        args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
    }

    async Task CreateResourcesAsync(ICanvasResourceCreator sender)
    {
        await LabResultsViewModel.LoadLabResults();

        var bitmap = await CanvasBitmap.LoadAsync(sender, new Uri("ms-appx:///Assets/high.png", UriKind.Absolute));
        IconsDictionary.Add((int)AbnormalFlagType.AboveHighNormal, bitmap);
        bitmap = await CanvasBitmap.LoadAsync(sender, new Uri("ms-appx:///Assets/low.png", UriKind.Absolute));
        IconsDictionary.Add((int)AbnormalFlagType.BelowLowNormal, bitmap);
        bitmap = await CanvasBitmap.LoadAsync(sender, new Uri("ms-appx:///Assets/criticalHigh.png", UriKind.Absolute));
        IconsDictionary.Add((int)AbnormalFlagType.CriticalHigh, bitmap);
        bitmap = await CanvasBitmap.LoadAsync(sender, new Uri("ms-appx:///Assets/criticalLow.png", UriKind.Absolute));
        IconsDictionary.Add((int)AbnormalFlagType.CriticalLow, bitmap);
    }

    private void CalculateCanvasDimmensions()
    {
        //to ensure compliance with the header - XAML does some smart calculations and comes up with unexpected resultst   
        //LabResultsCanvas.Width = ValuesHeaderListView.ActualWidth;

        LabResultsCanvas.Width = LabResultsViewModel.HospitalizationDates.Count * LabResultsConstants.LabResultCellWidth;
        if (LabResultsViewModel.CanvasMatrix != null)
            LabResultsCanvas.Height = LabResultsViewModel.CanvasMatrix.GetLength(0) * LabResultsConstants.LabResultCellHeight;
    }

    private void OnRegionsInvalidated(CanvasVirtualControl sender, CanvasRegionsInvalidatedEventArgs args)
    {
        if (!isDirty)
        {
            CalculateCanvasDimmensions();

            tableHeaderItemsCoordinates = GetExactHeaderItemsCoordinates().ToList();

            isDirty = true;
        }

        foreach (var region in args.InvalidatedRegions)
        {
            DrawRegion(sender, region);
        }
        LabResultsCanvas.VerticalAlignment = VerticalAlignment.Top;
        LabResultsCanvas.HorizontalAlignment = HorizontalAlignment.Left;

        Thickness margin = LabResultsCanvas.Margin;
        margin.Top = -1 * LabResultsConstants.LabResultCellHeight;
        LabResultsCanvas.Margin = margin;

        CanvasScroll.ChangeView(CanvasScroll.HorizontalOffset,
                categoriesListScroll.VerticalOffset, CanvasScroll.ZoomFactor, true);

    }

    private void DrawRegion(CanvasVirtualControl sender, Rect region)
    {
        if (LabResultsViewModel.CanvasMatrix == null)
            return;

        using (var ds = sender.CreateDrawingSession(region))
        {
            ds.Antialiasing = CanvasAntialiasing.Aliased;

            int left, right, top, bottom;

            labResultsGraphicProcessor.CalculateRegionBounds(region, LabResultsConstants.LabResultCellWidth,
                out left, out right, out top, out bottom);

            for (int x = left; x <= right; x++)
            {
                if (x < 0 || x >= LabResultsViewModel.CanvasMatrix[0].Length) //fail-safe - ensure only valid regions are drawn
                    continue;

                var exactXToAlignWithHeader = tableHeaderItemsCoordinates[x].X;

                for (int y = top; y <= bottom; y++)
                {
                    if (!AreCoordinatesInsideCanvas(x * LabResultsConstants.LabResultCellWidth, y * LabResultsConstants.LabResultCellHeight))
                        continue;

                    //skip header row - it's redundant - it would be hidden behind ListView header 
                   // and would cause visual issues when scrolling on a touch screen
                    if (y == 0)
                        continue;

                    var labResultCellDrawingModel = LabResultsViewModel.CanvasMatrix[y][x];

                    labResultCellDrawingModel.SetDrawingParameters
                        (
                            exactXToAlignWithHeader,
                            y * LabResultsConstants.LabResultCellHeight,
                            LabResultsConstants.LabResultCellWidth,
                            ds
                        );

                    if (labResultCellDrawingModel.HasIcon)
                    {
                        labResultCellDrawingModel.Icon.Image = IconsDictionary[labResultCellDrawingModel.LabResult.AbnormalFlag];
                    }

                    if (labResultCellDrawingModel.Canvas == null)
                        labResultCellDrawingModel.Canvas = sender;

                    if (labResultCellDrawingModel.Border != null && labResultCellDrawingModel.Type == LabResultCellType.Value)
                    {
                        labResultCellDrawingModel.Border.CustomBorderBrush = new BorderBrush
                        {
                            Right = GetRightBorderBrush(sender)
                        };
                        labResultCellDrawingModel.BorderOffset = new BorderOffset { Right = 7 };
                    }

                    labResultsGraphicProcessor.DrawIconAndTextRectangleCell(labResultCellDrawingModel);
                }
            }
        }
    }

    private bool AreCoordinatesInsideCanvas(double x, double y)
    {
        int matrixHeight = LabResultsViewModel.CanvasMatrix.GetLength(0);
        int matrixWidth = LabResultsViewModel.CanvasMatrix[0].Length;

        return
            y / LabResultsConstants.LabResultCellHeight >= 0 &&
            y / LabResultsConstants.LabResultCellHeight < matrixHeight &&
            x / LabResultsConstants.LabResultCellWidth >= 0 &&
            x / LabResultsConstants.LabResultCellWidth < matrixWidth;
    }       

    private void LabResultsCanvas_OnUnloaded(object sender, RoutedEventArgs e)
    {
        isDirty = false;
        LabResultsCanvas.RemoveFromVisualTree();
        LabResultsCanvas = null;
        isCanvasLoaded = false;
    }

    private IEnumerable<Point> GetExactHeaderItemsCoordinates()
    {
        double offset = 0;
        var pointsToReturn = new List<Point>();

        for (int i = 0; i < ValuesHeaderListView.Items.Count; i++)
        {
            var headerItem = ValuesHeaderListView.ContainerFromIndex(i) as ListViewItem;

            if (headerItem == null)
                throw new Exception("Unexpected page rendering exception");

            var ttv = headerItem.TransformToVisual(Window.Current.Content);
            Point screenCoords = ttv.TransformPoint(new Point(0, 0));

            if (i == 0)
                offset = screenCoords.X;

            screenCoords.X = screenCoords.X - offset;
            pointsToReturn.Add(screenCoords);
        }

        return pointsToReturn;
    }

    private CanvasLinearGradientBrush GetRightBorderBrush(ICanvasResourceCreator canvas)
    {
        return new CanvasLinearGradientBrush(canvas, new CanvasGradientStop[]
        {
                new CanvasGradientStop
                {
                    Color = Colors.White,
                    Position = 0
                },
                new CanvasGradientStop
                {
                    Color = LabResultsConstants.BorderColor,
                    Position = 0.333f
                },
                new CanvasGradientStop
                {
                    Color = LabResultsConstants.BorderColor,
                    Position = 0.667f
                },
                new CanvasGradientStop
                {
                    Color = Colors.White,
                    Position = 1
                }
        });
    }

    private void LabResultsCanvas_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
    {
        if (LabResultsViewModel?.CanvasMatrix != null && LabResultsViewModel.CanvasMatrix.Any() && LabResultsCanvas != null && isCanvasLoaded)
        {
            isDirty = false;
            LabResultsCanvas.Invalidate();
        }
    }

    private void Popup_OnOpened(object sender, object e)
    {
        Opacity = OPACITY_FACTOR;
    }

    private void LabResultsCanvas_OnLoaded(object sender, RoutedEventArgs e)
    {
        isCanvasLoaded = true;
    }

    private void NormalcyFilterButton_Tapped(object sender, TappedRoutedEventArgs e)
    {
        NormalcyFilterPopup.IsOpen = true;
    }

    private void SectionsFilterButton_Tapped(object sender, TappedRoutedEventArgs e)
    {
        SectionsFilterPopup.IsOpen = true;
    }
}

}

Thank you

shawnhar commented 8 years ago

Please share a (simplified as far as possible) repro app that we can debug to understand the problem you are seeing.

Thanks,

octav84 commented 8 years ago

Problem solved. The grid assigned space to the canvas because it was in a row with height set to "*". To make the RelativePanel assign space to the canvas, I simply wrote: RelativePanel.AlignBottomWithPanel = "True". Now the canvas had vertical space and OnRegionsInvalidated fired.

Thank you