Search code examples
wpfuser-controlsattached-properties

How to get the X,Y position of a UserControl within a Canvas


I have a simple UserControl as below - that I place in a Canvas. I move it using Multi-touch and I want to be able to read its new X,Y postion using procedural C# code. Ideally I would like to have X and Y as two properties or as a Point (X,Y).

<UserControl x:Class="TouchControlLibrary.myControl"
             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" 
             mc:Ignorable="d" 
             d:DesignHeight="64" d:DesignWidth="104">
    <Border Name="ControlBorder" BorderThickness="1" BorderBrush="Black">
        <DockPanel Margin="1" Height="60 " Width="100">
            <StackPanel  DockPanel.Dock="Left" Background="Gray"  Width="20" >
                <Button Background="#FFDEDE53" Padding="0">In</Button>
            </StackPanel>
            <StackPanel  DockPanel.Dock="Right" Background="Gray"  Width="20" >
                <Button Background="#FFE8B48F" Padding="0">Out</Button>
            </StackPanel>
        </DockPanel>  
    </Border>
</UserControl>

I expected to create an attached property for each of 'X' and 'Y' and fill them from Canvas.Left and Canvas.Top, using binding or some form of attached property or ???. I have spent quite some time searching for a solution, but everything I find seems to be 'not quite what is needed'.


Solution

  • You can use two properties like this in your userControl,

        public double Top
        {
            get
            {
                if (double.IsNaN(Canvas.GetTop(this)))
                {
                    return (double)0;
                }
                return Canvas.GetTop(this);
            }
    
            set
            {
                Canvas.SetTop(this, value);
            }
        }
    

    The check for "NotANumber" is not realy necessary, but I use it to prevent errors.