1

I'm trying to make a collection of tabs move to where ever I click on a canvas. I managed to get it working with fixed values, but cannot get it to work with a left mouse button click.

Here's my code:

public partial class MainWindow : Window
{
    User Player = new User();
    ThicknessConverter perimeter = new ThicknessConverter();
    Inventory Inventory = new Inventory();
    BreadCrumb Crumb = new BreadCrumb();
    Locations Locations = new Locations();
    PointAnimation myPointAnimation = new PointAnimation();
    ThicknessAnimation myThicknessAnimation = new ThicknessAnimation();
    DoubleAnimation da = new DoubleAnimation();
    Point p = new Point();

    private void Hansel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        da.From = Canvas.GetLeft(Hansel);
        da.From = Canvas.GetTop(Hansel);
        p.X = Mouse.GetPosition(PlayArea);

        da.To = p.X; //Convert.ToDouble(PointToScreen(Mouse.GetPosition(this.)));
        da.Duration = new Duration(TimeSpan.FromSeconds(2));
        Hansel.BeginAnimation(Canvas.LeftProperty, da);
    }
}

So, how would I go about getting the mouse position and converting those points to double coordinates?

Mo Patel
  • 2,321
  • 4
  • 22
  • 37
ZeroPhase
  • 649
  • 4
  • 21
  • I see you have tried to use PointToScreen method. isn't there another one called PointToClient? I know WinForms have it. – Mo Patel Apr 19 '13 at 18:21
  • @MPatel I'm having issue with converting points to doubles. – ZeroPhase Apr 19 '13 at 18:24
  • @ZeroPhase How come [You already asked this and I already gave you the solution](http://stackoverflow.com/questions/15864948/wpf-game-with-click-to-move-written-in-c-sharp) and now you're still trying to force WPF to a winforms mentality? – Federico Berasategui Apr 19 '13 at 18:26
  • @HighCore I'd have to redesign the rest of the code. Since, certain controls I have won't work with 'ItemsControl'. By the way, how would I go about adding multiple movable objects to the list? I tried adding a second one and it won't move. – ZeroPhase Apr 19 '13 at 18:29
  • @HighCore Yeah, I can't just drag and drop additional controls with 'ItemsControl'. I recieve this error when I drop in additional items 'InvalidOperationException: A style intended for type 'ContentPresenter' cannot be applied to type 'Rectangle'.' – ZeroPhase Apr 19 '13 at 18:34
  • drag and drop?? what are you talking about? I don't know what that means (irony). If you need different types of objects why don't you put different `DataTemplate`s? Also, how do you decide which object to move when clicking? If there's a `SelectedItem`, then you could change the `ItemsControl` for a `ListBox`. – Federico Berasategui Apr 19 '13 at 18:43
  • @ZeroPhase If you keep trying to force WPF to a winforms way, you will fail miserably. – Federico Berasategui Apr 19 '13 at 18:44
  • @MPatel is PointFromScreen what you're thinking of? – ZeroPhase Apr 19 '13 at 18:44
  • I just give the object a name, and manipulate the properties that name represents. – ZeroPhase Apr 19 '13 at 18:49
  • @ZeroPhase That's not what I'm asking. I'm asking `HOW` do you `DECIDE` What object you want to move when the user clicks the screen? Or you move all objects at the same time? – Federico Berasategui Apr 19 '13 at 18:57
  • They all move at once to keep the same shape. – ZeroPhase Apr 19 '13 at 18:59
  • @ZeroPhase I don't understand. If these objects are supposed to be together. Why don't you put them together in the same `DataTemplate`.?? – Federico Berasategui Apr 19 '13 at 19:01
  • I did put the second rectangle in the same data template, but it doesn't move when I add it to the list. I can't drag and drop new ui elements into place with the fromat you gave me. is there a way to convert doubles to points? – ZeroPhase Apr 19 '13 at 19:05
  • I don't know dude, I don't use the Visual Studio Designer. Why do you care about that? Just do the XAML yourself and you'll be happy. And Points are just a struct with 2 doubles. I don't understand your question. Of course you can convert between 2 doubles and 2 doubles. – Federico Berasategui Apr 19 '13 at 19:11
  • So how do I got about converting point to double? I get a conversion error when I assign the mouse location to the double animation. – ZeroPhase Apr 19 '13 at 19:15

1 Answers1

1
<Window x:Class="MiscSamples.ClickToMove"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ClickToMove" Height="300" Width="300">
    <ItemsControl ItemsSource="{Binding}" PreviewMouseDown="ItemsControl_PreviewMouseDown"
                  Background="#05FFFFFF">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="{Binding X}"/>
                <Setter Property="Canvas.Top" Value="{Binding Y}"/>
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Rectangle Stroke="Black" StrokeThickness="2" Fill="Blue"
                           Height="20" Width="20"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>

Code Behind:

 public partial class ClickToMove : Window
    {
        public List<MovableObject> Objects { get; set; } 

        public ClickToMove()
        {
            InitializeComponent();

            Objects = new List<MovableObject>
                {
                    new MovableObject() {X = 100, Y = 100}
                };

            DataContext = Objects;
        }

        private void ItemsControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            var position = e.GetPosition(this);
            Objects.First().MoveToPosition(position.X, position.Y);
        }
    }

ViewModel:

   public class MovableObject: INotifyPropertyChanged
    {
        private double _x;
        public double X
        {
            get { return _x; }
            set
            {
                _x = value;
                OnPropertyChanged("X");
            }
        }

        private double _y;
        public double Y
        {
            get { return _y; }
            set
            {
                _y = value;
                OnPropertyChanged("Y");
            }
        }

        private System.Threading.Timer MoveTimer;

        private double DestinationX;
        private double DestinationY;

        public void MoveToPosition(double x, double y)
        {
            DestinationX = x;
            DestinationY = y;

            if (MoveTimer != null)
                MoveTimer.Dispose();

            MoveTimer = new Timer(o => MoveStep(), null, 0, 10);
        }

        private void MoveStep()
        {
            if (Math.Abs(X - DestinationX) > 5)
            {
                if (X < DestinationX)
                    X = X+5;
                else if (X > DestinationX)
                    X = X-5;    
            }

            if (Math.Abs(Y - DestinationY) > 5)
            {
                if (Y < DestinationY)
                    Y = Y + 5;
                else if (Y > DestinationY)
                    Y = Y - 5;    
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            Application.Current.Dispatcher.BeginInvoke((Action)(() =>
                {
                    PropertyChangedEventHandler handler = PropertyChanged;
                    if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));        
                }));

        }
    }
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • 1
    You can get a very nice transition if the speed of the object is a function of the distance from the target, i.e. X+=vX*(DestinationX-X).Note that in this way you don't need any conditional; the speed will decrease to zero as the object moves towards the target _and_ the sign is set accordingly – BlackBear Apr 19 '13 at 18:33