Lars12345
Lars12345

Reputation: 11

How to access a Canvas inside a WPF UserControl?

I am a new to using WPF but very much like the idea of writing view code in xaml and backing code in a view-model. What I would want to do is extend use of the Canvas by associating it with a status bar that displays status text based on the contents of the Canvas and the mouse position (the stylized code below doesn't include this).

My approach has been to create a UserControl that contains the Canvas and put a ContentPresenter inside it, per https://www.codeproject.com/Articles/82464/How-to-Embed-Arbitrary-Content-in-a-WPF-Control.

I have two problems to solve: 1) What do I need to do to allow more than one child control in the same way that the Canvas allows more than one child control? 2) How do I access properties of the Canvas, such as Canvas.Left, from the main window code?

Thanks in advance for any suggestions you may have.

UserControl xaml code, UserControl code behind, and main window xaml code:

<UserControl x:Class="SO.CanvasUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:SO"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
  <UserControl.Template>
    <ControlTemplate TargetType="{x:Type local:CanvasUserControl}">
      <Canvas Width="200" Height="100" Background="Green">
        <ContentPresenter/>
      </Canvas>
    </ControlTemplate>
  </UserControl.Template>
</UserControl>

Code behind:

  public partial class CanvasUserControl : UserControl
  {
    public CanvasUserControl()
    {
      InitializeComponent();
    }
  }

Main window:

<Window x:Class="SO.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SO"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>

    <!--   works as expected
      <Canvas Width="200" Height="100" Background="Green">
      <Line X1="0" Y1="0" X2="200" Y2="100" Stroke="Red"/>
      <Line X1="200" Y1="0" X2="0" Y2="100" Stroke="Red"/>
    </Canvas>
  -->

    <!-- works as expected
     <Canvas Width="200" Height="100" Background="Green" x:Name="MyCanvas">
      <Line X1="{Binding ElementName=MyCanvas, Path=Left}" Y1="{Binding ElementName=MyCanvas, Path=Top}" X2="{Binding ElementName=MyCanvas, Path=ActualWidth}" Y2="{Binding ElementName=MyCanvas, Path=ActualHeight}" Stroke="Red"/>
      <Line X1="{Binding ElementName=MyCanvas, Path=ActualWidth}" Y1="{Binding ElementName=MyCanvas, Path=Top}" X2="{Binding ElementName=MyCanvas, Path=Left}" Y2="{Binding ElementName=MyCanvas, Path=ActualHeight}" Stroke="Red"/>
    </Canvas>
     -->


    <!-- How do I add more than one child control as nested content for the Canvas?
    <local:CanvasUserControl x:Name="MyCanvasUserControl">
      <Line X1="0" Y1="0" X2="200" Y2="100" Stroke="Red"/>
      <Line X1="200" Y1="0" X2="0" Y2="100" Stroke="Green"/>
    </local:CanvasUserControl>
    -->

    <!-- How do I access dependency properties of the Canvas?
    <local:CanvasUserControl x:Name="MyCanvasUserControl">
      <Line X1="{Binding ElementName=MyCanvasUserControl, Path=Left}" Y1="{Binding ElementName=MyCanvasUserControl, Path=Top}" X2="{Binding ElementName=MyCanvasUserControl, Path=ActualWidth}" Y2="{Binding ElementName=MyCanvasUserControl, Path=ActualHeight}" Stroke="Red"/>
    </local:CanvasUserControl>
    -->

  </Grid>
</Window>

Upvotes: 1

Views: 2122

Answers (2)

Vlad Marţian
Vlad Marţian

Reputation: 11

Just wanted to add that the MouseMove issue in the https://stackoverflow.com/a/42558704/9916025 answer above is due to the Background color not being set for the Canvas.

So to solve the problem with MouseMove you should add


<ItemsPanelTemplate>
    <local:CustomCanvas Background="Transparent"
                />
</ItemsPanelTemplate>

Upvotes: 1

Karmacon
Karmacon

Reputation: 3190

Maybe I'm not fully understanding your problem, but it sounds like you just want to have a Canvas that has a predefined status bar inside of it. You can do this very easily by extending Canvas instead of UserControl. Here's a custom component that extends Canvas and has a status bar.

<Canvas x:Class="SO.CanvasUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:SO"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Border Width="525" Height="30" Background="Black" Canvas.Bottom="0">
        <TextBlock Foreground="White" Text="Hello world" FontSize="16" />
    </Border>
</Canvas>

Now add it to your main window and assign any children you like along with it. You will see the status bar is displayed along with all the children. Since the component extends Canvas, you can add as many children as you want and you can bind to Canvas dependency properties.

<Window x:Class="SO.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SO"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

    <local:CanvasUserControl x:Name="MyCanvasUserControl" >
        <Line X1="0" Y1="0" X2="200" Y2="100" Stroke="Red"/>
        <Line X1="200" Y1="0" X2="0" Y2="100" Stroke="Green"/>
        <Line X1="{Binding ElementName=MyCanvasUserControl, Path=Left}" Y1="{Binding ElementName=MyCanvasUserControl, Path=Top}" X2="{Binding ElementName=MyCanvasUserControl, Path=ActualWidth}" Y2="{Binding ElementName=MyCanvasUserControl, Path=ActualHeight}" Stroke="Red"/>
    </local:CanvasUserControl>
</Window>

Upvotes: 1

Related Questions