My problem is the drag and drop of border become not workin when I wrap the canvas inside the scrollviewer.
1200x1200 canvas put in the 500x500 scrollviewer. I want the canvas is scrollable (touch slide) in the scrollviewer. The drag and drop in canvas is working perfectly before I insert in the scrollviewer.
MainWindow.xaml
<Grid ClipToBounds="True">
<ScrollViewer Name="scbb" Width="500" Height="500" HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden" HorizontalAlignment="Left"
VerticalAlignment="Top" Background="LightBlue" ScrollViewer.CanContentScroll="True">
<Canvas x:Name="canvas" Width="1200" Height="1200"
MouseLeftButtonDown="CanvasMouseLeftButtonDown"
MouseLeftButtonUp="CanvasMouseLeftButtonUp"
MouseMove="CanvasMouseMove">
</Canvas>
</ScrollViewer>
<Button x:Name="btnEnable" Content="Enable" Height="50" Width="50" Margin="0,0,115,10" VerticalAlignment="Bottom"
HorizontalAlignment="Right" Click="btnEnable_Click"/>
<Button Content="Add Image" Width="100" Height="100" VerticalAlignment="Bottom"
HorizontalAlignment="Right" Click="AddButtonClick" Margin="0,0,10,10"/>
</Grid>
MainWindow.xaml.cs
private void AddButtonClick(object sender, RoutedEventArgs e)
{
int iNum = SETTING.GetTableRunningNumber();
var borderWrap = new Border();
borderWrap.Width = 100;
borderWrap.Height = 100;
borderWrap.Background = Brushes.Green;
var label1 = new Label();
label1.VerticalAlignment = VerticalAlignment.Center;
label1.HorizontalAlignment = HorizontalAlignment.Center;
label1.Content = "Table " + iNum.ToString();
label1.Name = "Table" + iNum.ToString();
label1.Foreground = Brushes.White;
label1.FontWeight = FontWeights.Bold;
borderWrap.Child = label1;
borderWrap.MouseDown += TableMouseDown;
Canvas.SetLeft(borderWrap, 10);
Canvas.SetTop(borderWrap, 10);
canvas.Children.Add(borderWrap);
iNum += 1;
SETTING.SetTableRunningNumber(iNum);
}
private Point mousePosition;
private Border draggedBorder;
private void TableMouseDown(object sender, MouseButtonEventArgs e)
{
if (!SETTING.GetEnableDrag())
{
var cLabel = e.Source as Label;
var bBorder = e.Source as Border;
if (cLabel != null)
{
MessageBox.Show(cLabel.Name.ToString());
}
}
}
private void CanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (SETTING.GetEnableDrag())
{
var dBorder = e.Source as Border;
var cLabel = e.Source as Label;
if (dBorder == null)
{
dBorder = (Border)cLabel.Parent;
}
if (dBorder != null && canvas.CaptureMouse())
{
mousePosition = e.GetPosition(canvas);
draggedBorder = dBorder;
Panel.SetZIndex(draggedBorder, 1);
}
}
}
async Task PutTaskDelay100()
{
await Task.Delay(100);
}
private async void CanvasMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (SETTING.GetEnableDrag())
{
await PutTaskDelay100();
if (draggedBorder != null)
{
canvas.ReleaseMouseCapture();
Panel.SetZIndex(draggedBorder, 0);
draggedBorder = null;
}
}
}
private void CanvasMouseMove(object sender, MouseEventArgs e)
{
if (SETTING.GetEnableDrag())
{
double canvasSize = 1200;
if (draggedBorder != null)
{
var position = e.GetPosition(canvas);
var offset = position - mousePosition;
mousePosition = position;
double newTop = Canvas.GetTop(draggedBorder) + offset.Y;
double newLeft = Canvas.GetLeft(draggedBorder) + offset.X;
if (newTop < 0)
{
newTop = 0;
}
else if (newTop + draggedBorder.ActualWidth > canvasSize)
newTop = canvasSize - draggedBorder.ActualWidth;
if (newLeft < 0)
{
newLeft = 0;
}
else if (newLeft + draggedBorder.ActualWidth > canvasSize)
newLeft = canvasSize - draggedBorder.ActualWidth;
Canvas.SetLeft(draggedBorder, newLeft);
Canvas.SetTop(draggedBorder, newTop);
}
}
}
I had the problem months ago and solved it in the code behind with these additions.
After the InitializeComponent in the WindowMain.xaml.cs add:
public WindowMain()
{
InitializeComponent();
// your code, etc.
scrollViewer.AllowDrop = true;
scrollViewer.PreviewDragEnter += scrollViewer_PreviewDragEnter;
scrollViewer.PreviewDragOver += scrollViewer_PreviewDragOver;
scrollViewer.Drop += scrollViewer_Drop;
}
void scrollViewer_PreviewDragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effects = DragDropEffects.Copy;
}
else
{
e.Effects = DragDropEffects.None;
}
}
void scrollViewer_PreviewDragOver(object sender, DragEventArgs e)
{
e.Handled = true;
}
bool IsDataAvailable = false;
void scrollViewer_Drop(object sender, DragEventArgs e)
{
// Get data object
var dataObject = e.Data as DataObject;
// Check for file list
if (dataObject.ContainsFileDropList())
{
// Process file names
StringCollection fileNames = dataObject.GetFileDropList();
bool isIsDataAvailable = false;
try
{
var uri = new Uri(fileNames[0]);
BitmapSource imageSource = new BitmapImage(uri);
isIsDataAvailable = true;
}
catch (Exception error)
{
string errorMessage = error.ToString();
}
finally
{
IsDataAvailable = isIsDataAvailable;
}
}
}
My program just loads a dropped file from the explorer file list I drop on the ScrollViewer . The scbb.AllowDrop=true in the ScrollViewer has to be set. And the routines to handle basic drag and drop. Your code should work once the ScrollViewer allows dropping.
Related
I want to draw area inside a container. For this i thought about using custom control.
My problem is that Canvas does not take up all the given space it gets. How to force it to use all available space?
What i have done is inherited from Canvas and created border element inside it:
public class DrawableCanvas : Canvas
{
private Border border;
static DrawableCanvas()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DrawableCanvas), new FrameworkPropertyMetadata(typeof(DrawableCanvas)));
}
public DrawableCanvas()
{
this.border = new Border();
border.Background = new SolidColorBrush(Colors.Blue);
border.BorderThickness = new Thickness(1);
border.Width = 0;
border.Visibility = Visibility.Hidden;
border.Opacity = 0.3;
this.Children.Add(border);
this.MouseLeftButtonDown += DrawableCanvas_MouseLeftButtonDown;
this.MouseLeftButtonUp += DrawableCanvas_MouseLeftButtonUp;
this.MouseMove += DrawableCanvas_MouseMove;
}
private void DrawableCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("Left mouse up");
// release mouse
Mouse.Capture(null);
border.Width = 0;
border.Height = 100;
startPosition = 0;
}
double startPosition = 0;
private void DrawableCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("Left mouse down");
border.Visibility = Visibility.Visible;
// capture mouse
Mouse.Capture(this);
var point = e.GetPosition(this);
startPosition = point.X;
SetLeft(border, point.X);
}
private void DrawableCanvas_MouseMove(object sender, MouseEventArgs e)
{
if(this.IsMouseCaptured)
{
var point = e.GetPosition(this);
Debug.WriteLine("Mouse move");
// set the position to far left
SetLeft(border, Math.Min(startPosition, point.X));
// width is the difference between two points
border.Width = Math.Abs(startPosition - point.X);
Debug.WriteLine(Math.Min(startPosition, point.X));
Debug.WriteLine(border.Width);
}
}
}
And for view:
<DockPanel>
<local:DrawableCanvas>
<Rectangle Height="500" Width="500" Fill="Transparent" />
</local:DrawableCanvas>
</DockPanel>
I want something like this:
What I wanted to do is to create this control to enable selection on ui.
For this i needed a border/rectangle that will span only in width and use up all the height it gets
I ended up with this:
View:
<Window x:Class="Wpf.Test01.Stack_43281567"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wpf.Test01.Controls"
mc:Ignorable="d"
Title="Stack_43281567" Height="300" Width="300">
<Grid>
<local:DrawableCanvas />
</Grid>
</Window>
DrawableCanvas.cs:
public class DrawableCanvas : Canvas
{
private Border border;
static DrawableCanvas()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DrawableCanvas), new FrameworkPropertyMetadata(typeof(DrawableCanvas)));
}
// when selection is done expose event to notify the user of selection change
public DrawableCanvas()
{
this.border = new Border();
border.Background = new SolidColorBrush(Colors.Blue);
border.BorderThickness = new Thickness(1);
border.Visibility = Visibility.Hidden;
border.Opacity = 0.3;
border.Height = this.ActualHeight;
this.Children.Add(border);
this.Background = new SolidColorBrush(Colors.Transparent);
this.MouseLeftButtonDown += DrawableCanvas_MouseLeftButtonDown;
this.MouseLeftButtonUp += DrawableCanvas_MouseLeftButtonUp;
this.MouseMove += DrawableCanvas_MouseMove;
this.SizeChanged += DrawableCanvas_SizeChanged;
}
private void DrawableCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
{
border.Height = e.NewSize.Height;
}
private void DrawableCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("Left mouse up");
// release mouse
Mouse.Capture(null);
border.Width = 0;
startPosition = 0;
}
double startPosition = 0;
private void DrawableCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("Left mouse down");
border.Visibility = Visibility.Visible;
// capture mouse
Mouse.Capture(this);
var point = e.GetPosition(this);
startPosition = point.X;
SetLeft(border, point.X);
}
private void DrawableCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (this.IsMouseCaptured)
{
var point = e.GetPosition(this);
Debug.WriteLine("Mouse move");
// set the position to far left
SetLeft(border, Math.Min(startPosition, point.X));
// width is the difference between two points
border.Width = Math.Abs(startPosition - point.X);
Debug.WriteLine(Math.Min(startPosition, point.X));
Debug.WriteLine(border.Width);
}
}
}
I want to move the label by using the Mouse_Move/Mouse_Down events.
I tried to do it like this:
private void control_MouseDown(object sender, MouseButtonEventArgs e)
{
Label l = e.Source as Label;
if (l != null)
{
l.CaptureMouse();
moving = true;
PositionInLabel = e.GetPosition(l);
}
}
private void control_MouseMove(object sender, MouseEventArgs e)
{
if (moving)
{
Point p = e.GetPosition(null);
DeltaX = p.X - BasePoint.X - PositionInLabel.X;
DeltaY = p.Y - BasePoint.Y - PositionInLabel.Y;
RaisePropertyChanged("XPosition");
RaisePropertyChanged("YPosition");
}
}
Suppose your label is on a Canvas:
public MainWindow()
{
InitializeComponent();
this.label.MouseLeftButtonDown += control_MouseLeftButtonDown;
this.label.MouseMove += control_MouseMove;
this.label.MouseLeftButtonUp += control_MouseLeftButtonUp;
}
// Keep track of the Canvas where this element is placed.
private Canvas canvas;
// Keep track of when the element is being dragged.
private bool isDragging = false;
// When the element is clicked, record the exact position
// where the click is made.
private Point mouseOffset;
private void control_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Label l = e.Source as Label;
if (l == null)
return;
// Find the Canvas.
if (canvas == null)
canvas = (Canvas)VisualTreeHelper.GetParent(l);
// Dragging mode begins.
isDragging = true;
// Get the position of the click relative to the element
// (so the top-left corner of the element is (0,0).
mouseOffset = e.GetPosition(l);
// Capture the mouse. This way you'll keep receiving
// the MouseMove event even if the user jerks the mouse
// off the element.
l.CaptureMouse();
}
private void control_MouseMove(object sender, MouseEventArgs e)
{
Label l = e.Source as Label;
if (l == null)
return;
if (isDragging)
{
// Get the position of the element relative to the Canvas.
Point point = e.GetPosition(canvas);
// Move the element.
l.SetValue(Canvas.TopProperty, point.Y - mouseOffset.Y);
l.SetValue(Canvas.LeftProperty, point.X - mouseOffset.X);
}
}
private void control_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Label l = e.Source as Label;
if (l == null)
return;
if (isDragging)
{
l.ReleaseMouseCapture();
isDragging = false;
}
}
Let containerCanvas be a Canvas which contains the Label; then you can utilize the _MouseMove(object sender, MouseEventArgs e) to move the label along with your mouse pointer:
Xaml code:
<Canvas Name="containerCanvas" MouseMove="containerCanvas_MouseMove" Background="Aqua" Width="525" Height="350" >
<Label Name="floatingLabel" Height="28" Width="161" Background="AliceBlue"></Label>
</Canvas>
C# code:
private void containerCanvas_MouseMove(object sender, MouseEventArgs e)
{
Point p = Mouse.GetPosition(Application.Current.MainWindow);
floatingLabel.Margin = new Thickness(p.X, p.Y, 0, 0);
}
I have done a sample code. Check this. It should work.
XAML :
<UserControl HorizontalAlignment="Left" x:Class="WPFDiagramDesignerControl.Components.TestApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="100" Width="100" IsEnabled="True">
<Grid >
<Canvas x:Name="MyDesigner">
<TextBox x:Name="txtBox" IsEnabled="True" Background="AntiqueWhite" Margin="10,10,10,10" TextWrapping="Wrap"> </TextBox>
</Canvas>
</Grid>
Code Behind :
public TestApp()
{
InitializeComponent();
txtBox.MouseDoubleClick+=new MouseButtonEventHandler(control_MouseDoubleClick);
txtBox.MouseMove+=new MouseEventHandler(control_MouseMove);
txtBox.PreviewMouseDown+=new MouseButtonEventHandler(control_PreviewMouseDown);
txtBox.PreviewMouseUp+=new MouseButtonEventHandler(control_PreviewMouseUp);
txtBox.Cursor = Cursors.SizeAll;
}
private void control_MouseMove(object sender, RoutedEventArgs e)
{
if (isClicked)
{
Point mousePos = Mouse.GetPosition(parentCanvas);
parentItem = this.Parent as DesignerItem;
parentCanvas = parentItem.Parent as DesignerCanvas;
Point relativePosition = Mouse.GetPosition(parentCanvas);
DesignerCanvas.SetLeft(this, DesignerCanvas.GetLeft(this) - (startPoint.X - mousePos.X));
DesignerCanvas.SetTop(this, DesignerCanvas.GetTop(this) - (startPoint.Y - mousePos.Y));
}
}
private void control_PreviewMouseDown(object sender, RoutedEventArgs e)
{
if (!isClicked)
{
isClicked = true;
parentItem = this.Parent as DesignerItem;
parentCanvas = parentItem.Parent as DesignerCanvas;
startPoint = Mouse.GetPosition(parentCanvas);
}
}
private void control_PreviewMouseUp(object sender, RoutedEventArgs e)
{
isClicked = false;
}
I'm trying to move a rectangle drawn in Canvas by mouse (drag and drop).
When I click on the Rectangle and move the mouse (keep clicking) to a new position it's OK:
But when I click on it again and move the mouse just a bit the Rectangle move to old position:
I don't know why it is. Can anybody give me some explaination?
Here is my code (all parameters have been assigned and initialized).
Thanks in advance!
private void MyCanvas_MouseMove_1(object sender, MouseEventArgs e)
{
if (e.RightButton == MouseButtonState.Pressed && e.OriginalSource is Shape)
{
p2 = e.GetPosition(MyCanvas);
TranslateTransform tf = new TranslateTransform(p2.X - p1.X, p2.Y - p1.Y);
_MyTestRect.RenderTransform = tf;
}
}
private void MyCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is Shape)
{
p1 = e.GetPosition(MyCanvas);
}
}
Mvvm Behavior Approach add the refference to:
System.Windows.Interactivity.
In XAML:
<Canvas x:Name="MyCanvas" Background="#00FFFFFF">
<i:Interaction.Behaviors>
<!--soSandBox is the reffrence to the behavior-->
<soSandBox:MoveElementsInCanvasBehavior/>
</i:Interaction.Behaviors>
<Rectangle x:Name="_MyTestRect1" Fill="Tomato" Width="50" Height="50"/>
<Rectangle x:Name="_MyTestRect2" Fill="Tomato" Width="50" Height="50"/>
<Rectangle x:Name="_MyTestRect3" Fill="Tomato" Width="50" Height="50"/></Canvas>
Behavior code:
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.MouseLeftButtonDown += AssociatedObjectOnMouseLeftButtonDown;
AssociatedObject.MouseLeftButtonUp += AssociatedObjectOnMouseLeftButtonUp;
AssociatedObject.MouseMove += AssociatedObjectOnMouseMove;
}
private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs e)
{
if (_shape != null && _shape.IsMouseCaptured)
{
_p2 = e.GetPosition(AssociatedObject);
_shape.SetValue(Canvas.TopProperty, _p2.Y - _originalOffsetFromTop);
_shape.SetValue(Canvas.LeftProperty, _p2.X - _originalOffsetFromLeft);
}
}
private void AssociatedObjectOnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_shape == null) return;
_shape.ReleaseMouseCapture();
_shape = null;
}
private double GetDist(double originalValue, double newValue)
{
if (double.IsNaN(originalValue) || double.IsInfinity(originalValue))
return Math.Abs(newValue - 0);
return Math.Abs(newValue - originalValue);
}
private void AssociatedObjectOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_shape = e.OriginalSource as Shape;
if (_shape != null)
{
_p1 = e.GetPosition(AssociatedObject);
_shape.CaptureMouse();
_originalOffsetFromTop = GetDist((double)_shape.GetValue(Canvas.TopProperty), _p1.Y);
_originalOffsetFromLeft = GetDist((double)_shape.GetValue(Canvas.LeftProperty), _p1.X);
}
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.MouseLeftButtonDown -= AssociatedObjectOnMouseLeftButtonDown;
AssociatedObject.MouseLeftButtonUp -= AssociatedObjectOnMouseLeftButtonUp;
AssociatedObject.MouseMove -= AssociatedObjectOnMouseMove;
}
Summary:
This way you can put inside the canvas as much elements as you wish, and when you click the element (and when this element is a shape) you will be able to move it.
Translate Transform XAML:
<Canvas x:Name="MyCanvas" Background="#00FFFFFF">
<i:Interaction.Behaviors>
<!--convert event to command mechanism-->
<soSandBox:CanvasMouseEventObservingBehavior
OnMouseMoveAction="{Binding OnMouseMoveAction, UpdateSourceTrigger=PropertyChanged}"
OnMouseRightButtonDownAction="{Binding OnMouseRightButtonDownAction, UpdateSourceTrigger=PropertyChanged}"
OnMouseRightButtonUpAction="{Binding OnMouseRightButtonUpAction, UpdateSourceTrigger=PropertyChanged}"/>
</i:Interaction.Behaviors>
<Rectangle x:Name="_MyTestRect1" Fill="Tomato" Width="50" Height="50">
<Rectangle.RenderTransform>
<TransformGroup>
<TranslateTransform X="{Binding TranslateTransformX, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Y="{Binding TranslateTransformY, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></TranslateTransform>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle></Canvas>
Translate Transform view model (translation related code):
private void RightMouseUp(Point obj)
{
_originalPoint = obj;
_currentOffsetByX = GetDist(_currentOffsetByX, obj.X);
_currentOffsetByY = GetDist(_currentOffsetByY, obj.Y);
}
private void RightMouseDown(Point obj)
{
_originalPoint = obj;
_currentOffsetByX = GetDist(_currentOffsetByX, obj.X);
_currentOffsetByY = GetDist(_currentOffsetByY, obj.Y);
}
private void MouseMoved(Point obj)
{
TranslateTransformX = obj.X - _currentOffsetByX;
TranslateTransformY = obj.Y - _currentOffsetByY;
}
private double GetDist(double originalValue, double newValue)
{
if (double.IsNaN(originalValue) || double.IsInfinity(originalValue))
return Math.Abs(newValue - 0);
return Math.Abs(newValue - originalValue);
}
public double TranslateTransformY
{
get { return _translateTransformY; }
set
{
_translateTransformY = value;
OnPropertyChanged();
}
}
public double TranslateTransformX
{
get { return _translateTransformX; }
set
{
_translateTransformX = value;
OnPropertyChanged();
}
}
Regards
You should not create the transform every time otherwise you reset the translation.
Create a TranslateTransform if none exist.
Then cumulate the translations inside.
Regards
Try just using the Canvas.SetTop and Canvas.SetLeft.
Rectangle myRectangle = new Rectangle();
myRectangle += myRectangle_MouseLeftButtonDown;
void myRectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
myRectangle.MouseMove += origin_MouseMove;
}
void myRectangle_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
Point p = new Point()
{
// Just round the coordinates
X = Math.Round(e.GetPosition(canvas).X, 0, MidpointRounding.AwayFromZero),
Y = Math.Round(e.GetPosition(canvas).Y, 0, MidpointRounding.AwayFromZero),
};
Canvas.SetTop(myRectangle, p.Y);
Canvas.SetLeft(myRectangle, p.X);
myRectangle.MouseLeftButtonUp += myRectangle_MouseLeftButtonUp;
}
void myRectangle_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
myRectangle.MouseMove -= origin_MouseMove;
myRectangle.MouseLeftButtonUp -= origin_MouseLeftButtonUp;
}
I have created a button programmatically and i have passed it into a listbutton
I am trying to get the hover method to work on it but it does not work. when i make the button manually and pass it through the button list it works.
Design
<Window x:Class="KinectButton.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:Coding4Fun.Kinect.Wpf.Controls;assembly=Coding4Fun.Kinect.Wpf"
Title="MainWindow" Height="700" Width="1000" Background="#FFAD4747" Loaded="Window_Loaded">
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="261*" />
<ColumnDefinition Width="717*" />
</Grid.ColumnDefinitions>
<Canvas Background="#FF371780" Name="canvas" Grid.ColumnSpan="2">
<Controls:HoverButton Margin="0" Padding="0" x:Name="kinectButton" ImageSize="50"
ImageSource="/Images/RightHand.png"
ActiveImageSource="/Images/RightHand.png"
TimeInterval="2000" Panel.ZIndex="1000" Canvas.Left="0" Canvas.Top="0" />
<Button x:Name="button1" Content="Button1" Height="152" Canvas.Left="128" Canvas.Top="162" Width="320" Background="#FF64C02F" FontSize="53.333" Click="button1_Click" BorderThickness="4" Foreground="White" />
<Button x:Name="button2" Content="Button2" Height="152" Canvas.Left="514" Canvas.Top="162" Width="320" Background="#FFFFF600" FontSize="53.333" Click="button2_Click" BorderThickness="4" Foreground="Black" />
<Label Canvas.Left="322" Canvas.Top="34" Content="Kinect Buttons Demo" Height="58" Name="label1" FontSize="28" Width="302" Foreground="White" />
<Label Canvas.Left="38" Canvas.Top="524" Content="" Height="66" Name="message" Width="530" Foreground="White" FontSize="40" />
<Button Canvas.Left="804" Canvas.Top="23" Content="Quit" Height="91" Name="quitButton" Width="137" FontSize="28" Background="#FFFF3838" Foreground="White" Click="quitButton_Click" />
<Controls:HoverButton ActiveImageSource="/Images/RightHand.png" Canvas.Left="71" Canvas.Top="6" ImageSize="50" ImageSource="/Images/RightHand.png" Name="kinectButton2" Padding="0" Panel.ZIndex="1000" TimeInterval="2000" />
<StackPanel Height="621" Name="stackPanel1" Width="935" Canvas.Left="71" Canvas.Top="70" />
</Canvas>
<Image Height="128" HorizontalAlignment="Left" Margin="489,500,0,0" Name="videoStream" Stretch="Fill" VerticalAlignment="Top" Width="191" Grid.Column="1" />
</Grid>
</Window>
Code:
namespace KinectButton
{
public partial class MainWindow : Window
{
System.Windows.Controls.Button newBtn = new Button();
private KinectSensor _Kinect;
private WriteableBitmap _ColorImageBitmap;
private Int32Rect _ColorImageBitmapRect;
private int _ColorImageStride;
private Skeleton[] FrameSkeletons;
List<Button> buttons;
static Button selected;
float handX;
float handY;
float handX2;
float handY2;
public MainWindow()
{
InitializeComponent();
InitializeButtons();
kinectButton.Click += new RoutedEventHandler(kinectButton_Click);
this.Loaded += (s, e) => { DiscoverKinectSensor(); };
this.Unloaded += (s, e) => { this.Kinect = null; };
}
private void InitializeButtons()
{
newBtn.Content = "Hello";
newBtn.Width = 500;
newBtn.Height = 500;
newBtn.Click += new RoutedEventHandler(newBtn_Click);
buttons = new List<Button> { button1, button2, quitButton,newBtn};
}
private void DiscoverKinectSensor()
{
KinectSensor.KinectSensors.StatusChanged += KinectSensors_StatusChanged;
this.Kinect = KinectSensor.KinectSensors.FirstOrDefault(x => x.Status == KinectStatus.Connected);
}
private void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e)
{
switch (e.Status)
{
case KinectStatus.Connected:
if (this.Kinect == null)
{
this.Kinect = e.Sensor;
}
break;
case KinectStatus.Disconnected:
if (this.Kinect == e.Sensor)
{
this.Kinect = null;
this.Kinect = KinectSensor.KinectSensors.FirstOrDefault(x => x.Status == KinectStatus.Connected);
if (this.Kinect == null)
{
MessageBox.Show("Sensor Disconnected. Please reconnect to continue.");
}
}
break;
}
}
public KinectSensor Kinect
{
get { return this._Kinect; }
set
{
if (this._Kinect != value)
{
if (this._Kinect != null)
{
UninitializeKinectSensor(this._Kinect);
this._Kinect = null;
}
if (value != null && value.Status == KinectStatus.Connected)
{
this._Kinect = value;
InitializeKinectSensor(this._Kinect);
}
}
}
}
private void UninitializeKinectSensor(KinectSensor kinectSensor)
{
if (kinectSensor != null)
{
kinectSensor.Stop();
kinectSensor.ColorFrameReady -= Kinect_ColorFrameReady;
kinectSensor.SkeletonFrameReady -= Kinect_SkeletonFrameReady;
}
}
private void InitializeKinectSensor(KinectSensor kinectSensor)
{
if (kinectSensor != null)
{
ColorImageStream colorStream = kinectSensor.ColorStream;
colorStream.Enable();
this._ColorImageBitmap = new WriteableBitmap(colorStream.FrameWidth, colorStream.FrameHeight,
96, 96, PixelFormats.Bgr32, null);
this._ColorImageBitmapRect = new Int32Rect(0, 0, colorStream.FrameWidth, colorStream.FrameHeight);
this._ColorImageStride = colorStream.FrameWidth * colorStream.FrameBytesPerPixel;
videoStream.Source = this._ColorImageBitmap;
kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters()
{
Correction = 0.5f,
JitterRadius = 0.05f,
MaxDeviationRadius = 0.04f,
Smoothing = 0.5f
});
kinectSensor.SkeletonFrameReady += Kinect_SkeletonFrameReady;
kinectSensor.ColorFrameReady += Kinect_ColorFrameReady;
kinectSensor.Start();
this.FrameSkeletons = new Skeleton[this.Kinect.SkeletonStream.FrameSkeletonArrayLength];
}
}
private void Kinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
using (ColorImageFrame frame = e.OpenColorImageFrame())
{
if (frame != null)
{
byte[] pixelData = new byte[frame.PixelDataLength];
frame.CopyPixelDataTo(pixelData);
this._ColorImageBitmap.WritePixels(this._ColorImageBitmapRect, pixelData, this._ColorImageStride, 0);
}
}
}
private void Kinect_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
using (SkeletonFrame frame = e.OpenSkeletonFrame())
{
if (frame != null)
{
frame.CopySkeletonDataTo(this.FrameSkeletons);
Skeleton skeleton = GetPrimarySkeleton(this.FrameSkeletons);
if (skeleton == null)
{
kinectButton.Visibility = Visibility.Collapsed;
}
else
{
Joint primaryHand = GetPrimaryHand(skeleton);
TrackHand(primaryHand);
}
}
}
}
//track and display hand
private void TrackHand(Joint hand)
{
if (hand.TrackingState == JointTrackingState.NotTracked)
{
kinectButton.Visibility = System.Windows.Visibility.Collapsed;
}
else
{
kinectButton.Visibility = System.Windows.Visibility.Visible;
DepthImagePoint point = this.Kinect.MapSkeletonPointToDepth(hand.Position, DepthImageFormat.Resolution640x480Fps30);
handX = (int)((point.X * LayoutRoot.ActualWidth / this.Kinect.DepthStream.FrameWidth) - (kinectButton.ActualWidth / 2.0));
handY = (int)((point.Y * LayoutRoot.ActualHeight / this.Kinect.DepthStream.FrameHeight) - (kinectButton.ActualHeight / 2.0));
handX2 = (int)((point.X * LayoutRoot.ActualWidth / this.Kinect.DepthStream.FrameWidth) - (kinectButton2.ActualWidth / 2.0));
handY2 = (int)((point.Y * LayoutRoot.ActualHeight / this.Kinect.DepthStream.FrameHeight) - (kinectButton2.ActualHeight / 2.0));
Canvas.SetLeft(kinectButton, handX);
Canvas.SetTop(kinectButton, handY);
Canvas.SetLeft(kinectButton2, handX2);
Canvas.SetTop(kinectButton2, handY2);
if (isHandOver(kinectButton, buttons)) kinectButton.Hovering();
else kinectButton.Release();
kinectButton.ImageSource = "/Images/RightHand.png";
kinectButton.ActiveImageSource = "/Images/RightHand.png";
kinectButton.ImageSource = "/Images/LeftHand.png";
kinectButton.ActiveImageSource = "/Images/LeftHand.png";
}
}
//detect if hand is overlapping over any button
private bool isHandOver(FrameworkElement hand, List<Button> buttonslist)
{
var handTopLeft = new Point(Canvas.GetLeft(hand), Canvas.GetTop(hand));
var handX = handTopLeft.X + hand.ActualWidth / 2;
var handY = handTopLeft.Y + hand.ActualHeight / 2;
foreach (Button target in buttonslist)
{
Point targetTopLeft = new Point(Canvas.GetLeft(target), Canvas.GetTop(target));
if (handX > targetTopLeft.X &&
handX < targetTopLeft.X + target.Width &&
handY > targetTopLeft.Y &&
handY < targetTopLeft.Y + target.Height)
{
selected = target;
return true;
}
}
return false;
}
//get the hand closest to the Kinect sensor
private static Joint GetPrimaryHand(Skeleton skeleton)
{
Joint primaryHand = new Joint();
if (skeleton != null)
{
primaryHand = skeleton.Joints[JointType.HandLeft];
Joint rightHand = skeleton.Joints[JointType.HandRight];
if (rightHand.TrackingState != JointTrackingState.NotTracked)
{
if (primaryHand.TrackingState == JointTrackingState.NotTracked)
{
primaryHand = rightHand;
}
else
{
if (primaryHand.Position.Z > rightHand.Position.Z)
{
primaryHand = rightHand;
}
}
}
}
return primaryHand;
}
//get the skeleton closest to the Kinect sensor
private static Skeleton GetPrimarySkeleton(Skeleton[] skeletons)
{
Skeleton skeleton = null;
if (skeletons != null)
{
for (int i = 0; i < skeletons.Length; i++)
{
if (skeletons[i].TrackingState == SkeletonTrackingState.Tracked)
{
if (skeleton == null)
{
skeleton = skeletons[i];
}
else
{
if (skeleton.Position.Z > skeletons[i].Position.Z)
{
skeleton = skeletons[i];
}
}
}
}
}
return skeleton;
}
void newButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Yay");
}
void kinectButton_Click(object sender, RoutedEventArgs e)
{
selected.RaiseEvent(new RoutedEventArgs(Button.ClickEvent, selected));
}
private void newBtn_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("hey");
}
private void button2_Click(object sender, RoutedEventArgs e)
{
message.Content = "Button 2 clicked!";
Window w = new Window();
Button b = new Button();
b.Content = "Button A";
canvas.Children.Add(newBtn);
// stackPanel1.Children.Add(newBtn);
stackPanel1.Children.Remove((UIElement)this.FindName("Button0"));
}
}
}
The follow code would recreate your first button in code:
Button btn = new Button
{
Name = "button1",
Content = "Button1",
Height = 152,
Width = 320,
Foreground = "#FF64C02F",
FontSize = 53.333,
BorderThickness = 4
};
btn.Click += button1_Click;
canvas.Children.Add(btn);
Canvas.SetLeft(btn, 128);
Canvas.SetTop(btn, 162);
That said... it is not preferable that you do this in code. If you have 20 buttons (as you mention in your question comments) you should create them in XAML.
If you truly want to deal with them strictly in code, you should set up an MVVM-style application. These types of models can be very robust, but are complex to learn at first.
I want to remove all children of a StackPanel except for a Label, but I can't get it to
remove a dynamically created Button.
<StackPanel Name="myStackPanel">
<Label Name="myLabel">Label text</Label>
<TextBlock Name="myTextBlock">TextBlock text</TextBlock>
</StackPanel>
private void button1_Click(object sender, RoutedEventArgs e)
{
Button buttonX= new Button();
buttonX.Name = "ButtonInstall";
buttonX.Content = "Click Me";
buttonX.Width = 150;
buttonX.HorizontalAlignment = HorizontalAlignment.Left;
buttonX.Click += new RoutedEventHandler(buttonX_Click);
myStackPanel.Children.Add(buttonX);
}
private void button2_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myStackPanel); i++)
{
Visual childVisual = (Visual)VisualTreeHelper.GetChild(myStackPanel, i);
string controlName = childVisual.GetValue(Control.NameProperty).ToString();
if (childVisual.GetType() != typeof(Label))
{
myStackPanel.Children.Remove((UIElement)childVisual);
}
}
For your example, it's not necessary to use the VisualTreeHelper:
List<UIElement> delItems=new List<UIElement>();
foreach(UIElement uiElement in myStackPanel.Children){
if(uiElement is Label) continue;
delItems.Add(uiElement);
}
foreach(UIElement delItem in delItems){
myStackPanel.Children.Remove(delItem);
}