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 } }