XAML Page:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Microsoft.AspNet.SignalR.Client;
namespace SignalRDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
HubConnection _connection;
IHubProxy _hub;
// Keep track of when fake "drag and drop" mode is enabled.
private bool isDragging = false;
// Store the location where the user clicked the control.
private double clickOffsetX, clickOffsetY;
private void window_Loaded(object sender, RoutedEventArgs e)
{
Start();
}
void label_MouseDown(object sender, MouseButtonEventArgs e)
{
isDragging = true;
var position = e.GetPosition(window);
var label = sender as Label;
var l = (double)label.GetValue(Canvas.LeftProperty);
var t = (double)label.GetValue(Canvas.TopProperty);
clickOffsetX = l - position.X;
clickOffsetY = t - position.Y;
}
void label_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging == true)
{
// The control coordinates are converted into form coordinates
// by adding the label position offset.
// The offset where the user clicked in the control is also
// accounted for. Otherwise, it looks like the top-left corner
// of the label is attached to the mouse.
var label = sender as Label;
var position = e.GetPosition(window);
var x = position.X + clickOffsetX;
var y = position.Y + clickOffsetY;
SetShapePosition(label, x, y);
_hub.Invoke("MoveShape", int.Parse(label.Name.Replace("shape", "")), x, y);
}
}
void label_MouseUp(object sender, MouseButtonEventArgs e)
{
isDragging = false;
}
private void Start()
{
_connection = new HubConnection("http://localhost/SignalRChat/myhubs/hubs");
_hub = _connection.CreateHubProxy("SignalRHub");
_connection.Start().Wait();
_hub.On<int>("usersConnected", (count) =>
{
this.Dispatcher.Invoke(() =>
UpdateUserCount(count)
);
});
_hub.On<List<Common.Shape>>("shapeList", (list) =>
{
this.Dispatcher.Invoke(() =>
{
canvas.Children.Clear();
list.ForEach(q =>
{
var label = new Label();
label.Name = string.Format("shape{0}", q.Id);
label.Content = q.Name;
label.Height = 100;
label.Width = 100;
label.Padding = new Thickness(10, 10, 0, 0);
label.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(q.Color));
SetShapePosition(label, q.X, q.Y);
label.FontSize = 20;
label.MouseDown += label_MouseDown;
label.MouseMove += label_MouseMove;
label.MouseUp += label_MouseUp;
canvas.Children.Add(label);
});
});
});
_hub.On<Common.Shape>("shapeMoved", (shape) =>
{
this.Dispatcher.Invoke(() =>
UpdatePosition(shape)
);
});
_hub.Invoke("GetShapeList");
}
private void SetShapePosition(Label label, double x, double y)
{
if (label != null)
{
label.SetValue(Canvas.LeftProperty, x);
label.SetValue(Canvas.TopProperty, y);
}
}
private void UpdateUserCount(int count)
{
lblCount.Content = count;
}
private void UpdatePosition(Common.Shape shape)
{
var label = UIHelper.FindChild<Label>(Application.Current.MainWindow, string.Format("shape{0}", shape.Id));
SetShapePosition(label, shape.X, shape.Y);
}
}
public class UIHelper
{
/// <summary>
/// Finds a Child of a given item in the visual tree.
/// </summary>
/// <param name="parent">A direct parent of the queried item.</param>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="childName">x:Name or Name of child. </param>
/// <returns>The first parent item that matches the submitted type parameter.
/// If not matching item can be found,
/// a null parent is being returned.</returns>
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
}
}
SignalR Hub Page :
using Microsoft.AspNet.SignalR;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Common;
namespace SignalRChat
{
public class SignalRHub : Hub
{
public SignalRHub()
{
}
#region Moveable Shape
public async Task GetShapeList() // this method will be called from the client, when the user drag/move the shape
{
await Clients.Caller.shapeList(ShapeHandler.Instance.ShapeList); // this method will send the coord x, y to the other users but the user draging the shape
}
public async Task MoveShape(int id, double x, double y) // this method will be called from the client, when the user drag/move the shape
{
var shape = ShapeHandler.Instance.GetShape(id, x, y);
if (shape.X != x || shape.Y != y) await Clients.Caller.shapeMoved(shape);
await Clients.Others.shapeMoved(shape); // this method will send the coord x, y to the other users but the user draging the shape
}
public override Task OnConnected() //override OnConnect, OnReconnected and OnDisconnected to know if a user is connected or disconnected
{
ShapeHandler.Instance.ConnectedIds.Add(Context.ConnectionId); //add a connection id to the list
Clients.All.usersConnected(ShapeHandler.Instance.ConnectedIds.Count()); //this will send to ALL the clients the number of users connected
return base.OnConnected();
}
public override Task OnReconnected()
{
ShapeHandler.Instance.ConnectedIds.Add(Context.ConnectionId);
Clients.All.usersConnected(ShapeHandler.Instance.ConnectedIds.Count());
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
ShapeHandler.Instance.ConnectedIds.Remove(Context.ConnectionId);
Clients.All.usersConnected(ShapeHandler.Instance.ConnectedIds.Count());
return base.OnDisconnected(stopCalled);
}
#endregion
}
}