Search code examples
c#canvaswindows-store-appswindows-8.1

Access a Canvas inside an ItemsSource in a UserControl, from the MainPage


I have a FlipView in my MainPage. It's ItemTemplate binded to a UserControl called landscapeControl. It's ItemsSource is binded to a List of a class called MyLandscape.

landscapeControl:

<Grid>
    <ScrollViewer x:Name="LScrollViewer" MaxZoomFactor="2.0" MinZoomFactor="1.0" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" DoubleTapped="LScrollViewer_DoubleTapped" >
        <Canvas x:Name="inkCanvas" Background="Transparent">
            <StackPanel x:Name="LStackPanel" Orientation="Horizontal" Margin="0,0,0,0">
                <Image x:Name="LImage0" HorizontalAlignment="Right" Source="{Binding firstImage}" Width="570"/>
                <Image x:Name="LImage1" HorizontalAlignment="Left"  Source="{Binding nextImage}" Width="570"/>
            </StackPanel>
        </Canvas>
    </ScrollViewer>
</Grid>

MyLandscape class:

    public class MyLandscape
    {
        public ImageSource firstImage { get; set; }
        public ImageSource nextImage { get; set; }
        public Canvas inkCanvas { get; set; }
    }

My images are showing perfectly. All I want is 3 things:

1) I want to access my Canvas from my MainPage. I am trying to do this in flipView_SelectionChanged event:

        landscapeControl pc = flipView1.SelectedItem as landscapeControl;

        if (flipView1.Items.Count > 0)
        {
            var myCanvas = pc.getCanvas();
            m_CanvasManager = new CanvasManager(myCanvas);
        }

But the pc variable is always null! I want to bind my Canvas, so I have a Canvas for every two images? Is that possible?


Solution

  • One way is to use a Command to pass an UIElement back to your model.

    Basically your inkCanvas element will be attached with a CanvasLoadedCommand like this. Note this command is only called when the inkCanvas is fully loaded.

        <Canvas x:Name="inkCanvas" Background="Transparent">
            <Interactivity:Interaction.Behaviors>
                <Core:EventTriggerBehavior>
                    <Core:InvokeCommandAction Command="{Binding CanvasLoadedCommand}" CommandParameter="{Binding ElementName=inkCanvas}" />
                </Core:EventTriggerBehavior>
            </Interactivity:Interaction.Behaviors>
    

    I have created a simple DelegateCommand for this little demo (working source code) here. When the inkCanvas is loaded,

    this.inkCanvas = (Canvas)canvas;

    will be called and the inkCanvas property will then be filled.

        private DelegateCommand _canvasLoadedCommand;
        public DelegateCommand CanvasLoadedCommand
        {
            get
            {
                if (_canvasLoadedCommand == null)
                {
                    _canvasLoadedCommand = new DelegateCommand((canvas) =>
                    {
                        this.inkCanvas = (Canvas)canvas;
                    }, 
                    (canvas) => canvas != null);
                }
    
                return _canvasLoadedCommand;
            }
        }
    

    Hope this helps!