Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create an XY Controller like UI in WPF

Tags:

wpf

I am looking for something like this.

I should be able to drag the co-ordinate around inside the XY graph with a mouse. The position of the co-ordinate determines the X and Y values.

Is there a readily available control I can reuse? If not, how do I go about writing one?

I am looking for something like this

like image 303
ashwnacharya Avatar asked Oct 15 '11 12:10

ashwnacharya


1 Answers

I haven't seen any control like this, i guess you'll have to code it yourself. There's a few things here to implement, and I'll talk about the graph portion only. First, you should define a checklist of how this control is supposed to behave (i.e. move lines with cursor only when mousebutton is down), after that is done...well, that's the fun part!

EDIT : OK, now here's a rough Version, and when I say rough, I mean it. I put it into a window rather than a user control, you can just copy paste it into your control. This has many flaws and should be used productively only after fixing all issues that occur.Also, you have to be careful when mixing pixel design with flexible/relative design like Stretch-Alignment. I restricted this to pixel precision by making the window non-resizable.

<Window x:Class="graphedit.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" 
    x:Name="window"
    MouseMove="Window_MouseMove"
    Height="400" Width="400"
    ResizeMode="NoResize">
<Canvas x:Name="canvas"
        HorizontalAlignment="Stretch"
        VerticalAlignment="Stretch">
    <Canvas.Background>
        <RadialGradientBrush>
            <GradientStop Color="#333333" Offset="1"></GradientStop>
            <GradientStop Color="#666666" Offset="0"></GradientStop>
        </RadialGradientBrush>
    </Canvas.Background>
    <Border BorderThickness="0,0,1,1"
            BorderBrush="White"
            Margin="0,0,0,0"
            Width="{Binding Path=Point.X}"
            Height="{Binding Path=Point.Y}"></Border>

    <Border BorderThickness="1,1,0,0"
            BorderBrush="White"
            Margin="{Binding Path=BottomRightBoxMargin}"
            Width="{Binding Path=BottomRightBoxDimensions.X}"
            Height="{Binding Path=BottomRightBoxDimensions.Y}"></Border>
    <Border BorderThickness="1"
            BorderBrush="White"
            Margin="{Binding Path=GripperMargin}"
            Background="DimGray"
            CornerRadius="4"               
            Width="10"
            x:Name="gripper"
            MouseDown="gripper_MouseDown"
            MouseUp="gripper_MouseUp"
            Height="10"></Border>
    <TextBox Text="{Binding Path=Point.X}" Canvas.Left="174" Canvas.Top="333" Width="42"></TextBox>
    <TextBox Text="{Binding Path=Point.Y}" Canvas.Left="232" Canvas.Top="333" Width="45"></TextBox>
    <TextBlock Foreground="White" Canvas.Left="162" Canvas.Top="336">X</TextBlock>
    <TextBlock Canvas.Left="222" Canvas.Top="336" Foreground="White" Width="13">Y</TextBlock>
</Canvas>

The code-behind looks like the following:

using System.ComponentModel;
using System.Windows;

namespace graphedit
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
    private bool isDragging;

    private Point mousePositionBeforeMove;

    private Point point;

    public Point Point
    {
        get { return this.point; }
        set
        {
            this.point = value;
            this.InvokePropertyChanged(null);
        }
    }

    public Thickness BottomRightBoxMargin
    {
        get
        {
            Thickness t = new Thickness()
                          {
                              Left = this.Point.X,
                              Top = this.Point.Y
                          };
            return t;
        }
    }

    public Thickness GripperMargin
    {
        get
        {
            Thickness t = new Thickness()
            {
                Left = this.Point.X - 5,
                Top = this.Point.Y - 5
            };
            return t;
        }
    }

    public Point BottomRightBoxDimensions
    {
        get
        {
            return new Point(this.Width - this.Point.X,
                             this.Height - this.Point.Y);
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        this.Point = new Point(100, 80);
        this.DataContext = this;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void InvokePropertyChanged(string name)
    {
        PropertyChangedEventArgs args = new PropertyChangedEventArgs(name);
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, args);
        }
    }

    private void gripper_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        this.isDragging = true;
        this.mousePositionBeforeMove = e.GetPosition( this.canvas );
    }

    private void gripper_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        this.isDragging = false;
    }

    private void Window_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if(this.isDragging)
        {
            Point currentMousePosition = e.GetPosition( this.canvas );
            double deltaX = currentMousePosition.X - this.mousePositionBeforeMove.X;
            double deltaY = currentMousePosition.Y - this.mousePositionBeforeMove.Y;

            double newPointX = (this.Point.X + deltaX < 0 ? 0 : (this.Point.X + deltaX > this.Width ? this.Width : this.Point.X + deltaX)) ;
            double newPointY = (this.Point.Y + deltaY < 0 ? 0 : (this.Point.Y + deltaY > this.Width ? this.Width : this.Point.Y + deltaY)) ;

            this.Point = new Point(newPointX,newPointY);
            this.mousePositionBeforeMove = currentMousePosition;
        }
    }
}
}
like image 70
Sebastian Edelmeier Avatar answered Sep 27 '22 19:09

Sebastian Edelmeier