Display the angles of each joint of the skeleton in kinect c# - kinect
How to display the angles of Kinect skeleton joints?
This is the programm you are looking for:
namespace Microsoft.Samples.Kinect.SkeletonBasics
{
using System.IO;
using System.IO.Ports;
using System.Threading;
using System;
using System.Windows;
using System.Windows.Media;
using Microsoft.Kinect;
using Microsoft.Kinect.Toolkit.Fusion;
using System.Windows.Media.Media3D;
public class Angles
{
public double AngleBetweenTwoVectors(Vector3D vectorA, Vector3D vectorB)
{
double dotProduct;
vectorA.Normalize();
vectorB.Normalize();
dotProduct = Vector3D.DotProduct(vectorA, vectorB);
return (double)Math.Acos(dotProduct)/Math.PI*180;
}
public byte[] GetVector(Skeleton skeleton)
{
Vector3D ShoulderCenter = new Vector3D(skeleton.Joints[JointType.ShoulderCenter].Position.X, skeleton.Joints[JointType.ShoulderCenter].Position.Y, skeleton.Joints[JointType.ShoulderCenter].Position.Z);
Vector3D RightShoulder = new Vector3D(skeleton.Joints[JointType.ShoulderRight].Position.X, skeleton.Joints[JointType.ShoulderRight].Position.Y, skeleton.Joints[JointType.ShoulderRight].Position.Z);
Vector3D LeftShoulder = new Vector3D(skeleton.Joints[JointType.ShoulderLeft].Position.X, skeleton.Joints[JointType.ShoulderLeft].Position.Y, skeleton.Joints[JointType.ShoulderLeft].Position.Z);
Vector3D RightElbow = new Vector3D(skeleton.Joints[JointType.ElbowRight].Position.X, skeleton.Joints[JointType.ElbowRight].Position.Y, skeleton.Joints[JointType.ElbowRight].Position.Z);
Vector3D LeftElbow = new Vector3D(skeleton.Joints[JointType.ElbowLeft].Position.X, skeleton.Joints[JointType.ElbowLeft].Position.Y, skeleton.Joints[JointType.ElbowLeft].Position.Z);
Vector3D RightWrist = new Vector3D(skeleton.Joints[JointType.WristRight].Position.X, skeleton.Joints[JointType.WristRight].Position.Y, skeleton.Joints[JointType.WristRight].Position.Z);
Vector3D LeftWrist = new Vector3D(skeleton.Joints[JointType.WristLeft].Position.X, skeleton.Joints[JointType.WristLeft].Position.Y, skeleton.Joints[JointType.WristLeft].Position.Z);
Vector3D UpVector = new Vector3D(0.0, 1.0, 0.0);
double AngleRightElbow = AngleBetweenTwoVectors(RightElbow - RightShoulder, RightElbow - RightWrist);
double AngleRightShoulder = AngleBetweenTwoVectors(UpVector, RightShoulder - RightElbow);
double AngleLeftElbow = AngleBetweenTwoVectors(LeftElbow - LeftShoulder, LeftElbow - LeftWrist);
double AngleLeftShoulder = AngleBetweenTwoVectors(UpVector, LeftShoulder - LeftElbow);
byte[] Angles = {Convert.ToByte(AngleRightElbow), Convert.ToByte(AngleRightShoulder),Convert.ToByte(AngleLeftElbow),Convert.ToByte(AngleLeftShoulder)};
return Angles;
}
}
/// Interaction logic for MainWindow.xaml
public partial class MainWindow : Window
{
SerialPort ArduinoPort;
/// Width of output drawing
private const float RenderWidth = 640.0f;
/// Height of our output drawing
private const float RenderHeight = 480.0f;
/// Thickness of drawn joint lines
private const double JointThickness = 3;
/// Thickness of body center ellipse
private const double BodyCenterThickness = 10;
/// Thickness of clip edge rectangles
private const double ClipBoundsThickness = 10;
/// Brush used to draw skeleton center point
private readonly Brush centerPointBrush = Brushes.Blue;
/// Brush used for drawing joints that are currently tracked
private readonly Brush trackedJointBrush = new SolidColorBrush(Color.FromArgb(255, 68, 192, 68));
/// Brush used for drawing joints that are currently inferred
private readonly Brush inferredJointBrush = Brushes.Yellow;
/// Pen used for drawing bones that are currently tracked
private readonly Pen trackedBonePen = new Pen(Brushes.Green, 6);
/// Pen used for drawing bones that are currently inferred
private readonly Pen inferredBonePen = new Pen(Brushes.Gray, 1);
/// Active Kinect sensor
private KinectSensor sensor;
/// Drawing group for skeleton rendering output
private DrawingGroup drawingGroup;
/// Drawing image that we will display
private DrawingImage imageSource;
/// Initializes a new instance of the MainWindow class.
public MainWindow()
{
InitializeComponent();
}
private static void RenderClippedEdges(Skeleton skeleton, DrawingContext drawingContext)
{
if (skeleton.ClippedEdges.HasFlag(FrameEdges.Bottom))
{
drawingContext.DrawRectangle(
Brushes.Red,
null,
new Rect(0, RenderHeight - ClipBoundsThickness, RenderWidth, ClipBoundsThickness));
}
if (skeleton.ClippedEdges.HasFlag(FrameEdges.Top))
{
drawingContext.DrawRectangle(
Brushes.Red,
null,
new Rect(0, 0, RenderWidth, ClipBoundsThickness));
}
if (skeleton.ClippedEdges.HasFlag(FrameEdges.Left))
{
drawingContext.DrawRectangle(
Brushes.Red,
null,
new Rect(0, 0, ClipBoundsThickness, RenderHeight));
}
if (skeleton.ClippedEdges.HasFlag(FrameEdges.Right))
{
drawingContext.DrawRectangle(
Brushes.Red,
null,
new Rect(RenderWidth - ClipBoundsThickness, 0, ClipBoundsThickness, RenderHeight));
}
}
private void WindowLoaded(object sender, RoutedEventArgs e)
{
// Create the drawing group we'll use for drawing
this.drawingGroup = new DrawingGroup();
// Create an image source that we can use in our image control
this.imageSource = new DrawingImage(this.drawingGroup);
// Display the drawing using our image control
Image.Source = this.imageSource;
// Look through all sensors and start the first connected one.
// This requires that a Kinect is connected at the time of app startup.
// To make your app robust against plug/unplug,
// it is recommended to use KinectSensorChooser provided in Microsoft.Kinect.Toolkit (See components in Toolkit Browser).
foreach (var potentialSensor in KinectSensor.KinectSensors)
{
if (potentialSensor.Status == KinectStatus.Connected)
{
this.sensor = potentialSensor;
break;
}
}
if (null != this.sensor)
{
// Turn on the skeleton stream to receive skeleton frames
this.sensor.SkeletonStream.Enable();
// Add an event handler to be called whenever there is new color frame data
this.sensor.SkeletonFrameReady += this.SensorSkeletonFrameReady;
// Start the sensor!
try
{
this.sensor.Start();
}
catch (IOException)
{
this.sensor = null;
}
}
if (null == this.sensor)
{
this.statusBarText.Text = Properties.Resources.NoKinectReady;
}
}
private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (null != this.sensor)
{
//ArduinoPort.Close();
this.sensor.Stop();
}
}
private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
Skeleton[] skeletons = new Skeleton[0];
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null)
{
skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
skeletonFrame.CopySkeletonDataTo(skeletons);
}
}
using (DrawingContext dc = this.drawingGroup.Open())
{
// Draw a transparent background to set the render size
dc.DrawRectangle(Brushes.Black, null, new Rect(0.0, 0.0, RenderWidth, RenderHeight));
if (skeletons.Length != 0)
{
foreach (Skeleton skel in skeletons)
{
RenderClippedEdges(skel, dc);
if (skel.TrackingState == SkeletonTrackingState.Tracked)
{
this.DrawBonesAndJoints(skel, dc);
Angles MyAngles = new Angles();
byte[] ReadyAngles = MyAngles.GetVector(skel);
RightElbow.Text = ReadyAngles[0].ToString();
RightShoulder.Text = ReadyAngles[1].ToString();
LeftElbow.Text = ReadyAngles[2].ToString();
LeftShoulder.Text = ReadyAngles[3].ToString();
byte[] SequenceStart = {255};
if (ArduinoPort.IsOpen)
{
ArduinoPort.Write(SequenceStart,0,1);
ArduinoPort.Write(ReadyAngles, 0, 4);
}
}
else if (skel.TrackingState == SkeletonTrackingState.PositionOnly)
{
dc.DrawEllipse(
this.centerPointBrush,
null,
this.SkeletonPointToScreen(skel.Position),
BodyCenterThickness,
BodyCenterThickness);
}
}
}
// prevent drawing outside of our render area
this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, RenderWidth, RenderHeight));
}
}
private void DrawBonesAndJoints(Skeleton skeleton, DrawingContext drawingContext)
{
// Render Torso
this.DrawBone(skeleton, drawingContext, JointType.Head, JointType.ShoulderCenter);
this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderLeft);
this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderRight);
this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.Spine);
this.DrawBone(skeleton, drawingContext, JointType.Spine, JointType.HipCenter);
this.DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipLeft);
this.DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipRight);
// Left Arm
this.DrawBone(skeleton, drawingContext, JointType.ShoulderLeft, JointType.ElbowLeft);
this.DrawBone(skeleton, drawingContext, JointType.ElbowLeft, JointType.WristLeft);
this.DrawBone(skeleton, drawingContext, JointType.WristLeft, JointType.HandLeft);
// Right Arm
this.DrawBone(skeleton, drawingContext, JointType.ShoulderRight, JointType.ElbowRight);
this.DrawBone(skeleton, drawingContext, JointType.ElbowRight, JointType.WristRight);
this.DrawBone(skeleton, drawingContext, JointType.WristRight, JointType.HandRight);
// Left Leg
this.DrawBone(skeleton, drawingContext, JointType.HipLeft, JointType.KneeLeft);
this.DrawBone(skeleton, drawingContext, JointType.KneeLeft, JointType.AnkleLeft);
this.DrawBone(skeleton, drawingContext, JointType.AnkleLeft, JointType.FootLeft);
// Right Leg
this.DrawBone(skeleton, drawingContext, JointType.HipRight, JointType.KneeRight);
this.DrawBone(skeleton, drawingContext, JointType.KneeRight, JointType.AnkleRight);
this.DrawBone(skeleton, drawingContext, JointType.AnkleRight, JointType.FootRight);
// Render Joints
foreach (Joint joint in skeleton.Joints)
{
Brush drawBrush = null;
if (joint.TrackingState == JointTrackingState.Tracked)
{
drawBrush = this.trackedJointBrush;
}
else if (joint.TrackingState == JointTrackingState.Inferred)
{
drawBrush = this.inferredJointBrush;
}
if (drawBrush != null)
{
drawingContext.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(joint.Position), JointThickness, JointThickness);
}
}
}
private Point SkeletonPointToScreen(SkeletonPoint skelpoint)
{
// Convert point to depth space.
// We are not using depth directly, but we do want the points in our 640x480 output resolution.
DepthImagePoint depthPoint = this.sensor.CoordinateMapper.MapSkeletonPointToDepthPoint(skelpoint, DepthImageFormat.Resolution640x480Fps30);
return new Point(depthPoint.X, depthPoint.Y);
}
private void DrawBone(Skeleton skeleton, DrawingContext drawingContext, JointType jointType0, JointType jointType1)
{
Joint joint0 = skeleton.Joints[jointType0];
Joint joint1 = skeleton.Joints[jointType1];
// If we can't find either of these joints, exit
if (joint0.TrackingState == JointTrackingState.NotTracked ||
joint1.TrackingState == JointTrackingState.NotTracked)
{
return;
}
// Don't draw if both points are inferred
if (joint0.TrackingState == JointTrackingState.Inferred &&
joint1.TrackingState == JointTrackingState.Inferred)
{
return;
}
// We assume all drawn bones are inferred unless BOTH joints are tracked
Pen drawPen = this.inferredBonePen;
if (joint0.TrackingState == JointTrackingState.Tracked && joint1.TrackingState == JointTrackingState.Tracked)
{
drawPen = this.trackedBonePen;
}
drawingContext.DrawLine(drawPen, this.SkeletonPointToScreen(joint0.Position), this.SkeletonPointToScreen(joint1.Position));
}
private void CheckBoxSeatedModeChanged(object sender, RoutedEventArgs e)
{
if (null != this.sensor)
{
if (this.checkBoxSeatedMode.IsChecked.GetValueOrDefault())
{
this.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated;
}
else
{
this.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Default;
}
}
}
private void CheckBoxConnectArduino(object sender, RoutedEventArgs e)
{
if (this.checkArduinoConnected.IsChecked.GetValueOrDefault())
{
string MyCOM = "COM10";
ArduinoPort = new SerialPort(MyCOM, 9600);
ArduinoPort.Open();
}
else {
ArduinoPort.Close();
}
}
}
}
You also need to add the xaml:
<Window x:Class="Microsoft.Samples.Kinect.SkeletonBasics.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Skeleton Basics" Height="735" Width="770" Loaded="WindowLoaded" Closing="WindowClosing">
<Window.Resources>
<SolidColorBrush x:Key="MediumGreyBrush" Color="#ff6e6e6e"/>
<SolidColorBrush x:Key="KinectPurpleBrush" Color="#ff52318f"/>
<SolidColorBrush x:Key="KinectBlueBrush" Color="#ff00BCF2"/>
<Style TargetType="{x:Type Image}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
</Style>
<Style TargetType="{x:Type CheckBox}" x:Key="SquareCheckBox" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<StackPanel Orientation="Horizontal" Background="Transparent">
<Grid x:Name="SquareCheckBoxChecked">
<Image x:Name="CheckedNormal" Source="Images\CheckedNormal.png" Stretch="None" HorizontalAlignment="Center"/>
<Image x:Name="CheckedHover" Source="Images\CheckedHover.png" Stretch="None" HorizontalAlignment="Center" Visibility="Collapsed"/>
</Grid>
<Grid x:Name="SquareCheckBoxUnchecked" Visibility="Collapsed">
<Image x:Name="UncheckedNormal" Source="Images\UncheckedNormal.png" Stretch="None" HorizontalAlignment="Center"/>
<Image x:Name="UncheckedHover" Source="Images\UncheckedHover.png" Stretch="None" HorizontalAlignment="Center" Visibility="Collapsed"/>
</Grid>
<TextBlock x:Name="SquareCheckBoxText" Text="{TemplateBinding Content}" TextAlignment="Left" VerticalAlignment="Center" Foreground="{StaticResource KinectPurpleBrush}" FontSize="15" Margin="9,0,0,0"/>
</StackPanel>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="false">
<Setter Property="Visibility" Value="Collapsed" TargetName="SquareCheckBoxChecked"/>
<Setter Property="Visibility" Value="Visible" TargetName="SquareCheckBoxUnchecked"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Visibility" Value="Collapsed" TargetName="CheckedNormal"/>
<Setter Property="Visibility" Value="Collapsed" TargetName="UncheckedNormal"/>
<Setter Property="Visibility" Value="Visible" TargetName="CheckedHover"/>
<Setter Property="Visibility" Value="Visible" TargetName="UncheckedHover"/>
<Setter Property="Foreground" Value="{StaticResource KinectBlueBrush}" TargetName="SquareCheckBoxText"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Name="layoutGrid" Margin="10 0 10 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Margin="0 0 0 20">
<Image DockPanel.Dock="Left" Source="Images\Logo.png" Stretch="Fill" Height="32" Width="81" Margin="0 10 0 5"/>
<TextBlock DockPanel.Dock="Right" Margin="0 0 -1 0" VerticalAlignment="Bottom" Foreground="{StaticResource MediumGreyBrush}" FontFamily="Segoe UI" FontSize="18">Skeleton Basics</TextBlock>
<Image Grid.Column="1" Source="Images\Status.png" Stretch="None" HorizontalAlignment="Center" Margin="0 0 0 5"/>
</DockPanel>
<Viewbox Grid.Row="1" Stretch="Uniform" HorizontalAlignment="Center">
<Image Name="Image" Width="640" Height="480"/>
</Viewbox>
<CheckBox Grid.Row="2" Style="{StaticResource SquareCheckBox}" Content="Connect Arduino" Height="Auto" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0 10 10 10" Name="checkArduinoConnected" Checked="CheckBoxConnectArduino" Unchecked="CheckBoxConnectArduino"/>
<CheckBox Grid.Row="2" Style="{StaticResource SquareCheckBox}" Content="Seated Mode" Height="Auto" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0 10 10 10" Name="checkBoxSeatedMode" Checked="CheckBoxSeatedModeChanged" Unchecked="CheckBoxSeatedModeChanged"/>
<StatusBar Grid.Row="3" HorizontalAlignment="Stretch" Name="statusBar" VerticalAlignment="Bottom" Background="White" Foreground="{StaticResource MediumGreyBrush}">
<StatusBarItem Padding="0 0 0 10">
<TextBlock Name="statusBarText" Margin="-1 0 0 0">Click 'Seated' to change skeletal pipeline type!</TextBlock>
</StatusBarItem>
</StatusBar>
<TextBox Name="RightShoulder" HorizontalAlignment="Left" Height="23" Margin="150,12,0,0" Grid.Row="2" TextWrapping="Wrap" VerticalAlignment="Top" Width="100"/>
<TextBox Name="RightElbow" HorizontalAlignment="Left" Height="23" Margin="250,12,0,0" Grid.Row="2" TextWrapping="Wrap" VerticalAlignment="Top" Width="100"/>
<TextBox Name="LeftShoulder" HorizontalAlignment="Left" Height="23" Margin="350,12,0,0" Grid.Row="2" TextWrapping="Wrap" VerticalAlignment="Top" Width="100"/>
<TextBox Name="LeftElbow" HorizontalAlignment="Left" Height="23" Margin="450,12,0,0" Grid.Row="2" TextWrapping="Wrap" VerticalAlignment="Top" Width="100"/>
</Grid>
</Window>
Of course you can not use the images, but that is not necessary. If this doesn't work right away just send me your e-mail and I will send you the complete source code :)
You can try Kinect Angles # http://drenton72.wordpress.com/2012/05/23/kinect-angles-v2-4/
I created Kinect Angles all I do is read the X,Y positions of the joints and then work out difference between the two positions as you would with vectors (just subtract one vector from the other one). Then I use simple trig to work out the angle of the vector. My Kinect Angles is open source so you should be able to figure it out from my source code.
Related
UWP: how to reflow controls based on grid width
I have two buttons placed horizontally. They are inside a grid. This grid containing two buttons has width 370. When the text on the button becomes large, it needs width more than 370. So what I want to do is, instead of placing then horizontally, I want to place them vertically dynamically when text will start cropping. Basically, I want auto-reflow behavior inside this grid for these two buttons based on width of the grid (not based on width of main window). So I want them to fit in 370 width and if they cannot, I want them to place themselves vertically. How can I achieve this? I explored GridView but it will show buttons inside the box that comes with GridView so I do not want extra UI that comes with GridView unless we have an option to hide it? I checked AdaptiveTrigger but that is based on width of window not of the control (grid in this case) <Grid Grid.Row="2" Margin="0,36,0,28" Width="370" HorizontalAlignment="Left" VerticalAlignment="Bottom"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid Grid.Column="0" CornerRadius="3"> <Button MinWidth="118" MinHeight="30" HorizontalAlignment="Left" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" AutomationProperties.Name="{x:Bind ViewModel.PrimaryActionAutomationName, Mode=OneWay}" BorderThickness="1" Click="{x:Bind ViewModel.InvokePrimaryAction}" Content="{x:Bind ViewModel.PrimaryAction, Mode=OneWay}" CornerRadius="3" Style="{StaticResource AccentButtonStyle}" /> </Grid> <Grid Grid.Column="1" CornerRadius="3" Margin="32,0,0,0"> <HyperlinkButton AutomationProperties.Name="{x:Bind ViewModel.SecondaryLinkAutomationName, Mode=OneWay}" AutomationProperties.AutomationId="{Binding AutomationId, ConverterParameter=HyperlinkButton, Converter={StaticResource AutomationIdConverter}}" Content="{x:Bind ViewModel.SecondaryText, Mode=OneWay}" FontSize="14" Margin="0,0,0,0" Style="{StaticResource HyperlinkButtonStyle}" NavigateUri="{x:Bind ViewModel.SecondaryLink, Mode=OneWay}" /> </Grid> </Grid>
For your scenario, I'd suggest you custom a StateTrigger based on the StateTriggerBase Class to monitor the width of the Grid and apply visual states based on the width. I've made a simple sample that you could refer to. ControlSizeTrigger: public class ControlSizeTrigger : StateTriggerBase { //private variables private double _minHeight, _minWidth = -1; private FrameworkElement _targetElement; private double _currentHeight, _currentWidth; //public properties to set from XAML public double MinHeight { get { return _minHeight; } set { _minHeight = value; } } public double MinWidth { get { return _minWidth; } set { _minWidth = value; } } public FrameworkElement TargetElement { get { return _targetElement; } set { if (_targetElement != null) { _targetElement.SizeChanged -= _targetElement_SizeChanged; } _targetElement = value; _targetElement.SizeChanged += _targetElement_SizeChanged; } } //Handle event to get current values private void _targetElement_SizeChanged(object sender, SizeChangedEventArgs e) { _currentHeight = e.NewSize.Height; _currentWidth = e.NewSize.Width; UpdateTrigger(); } //Logic to evaluate and apply trigger value private void UpdateTrigger() { //if target is set and either minHeight or minWidth is set, proceed if (_targetElement != null && (_minWidth > 0 || _minHeight > 0)) { //if both minHeight and minWidth are set, then both conditions must be satisfied if (_minHeight > 0 && _minWidth > 0) { SetActive((_currentHeight >= _minHeight) && (_currentWidth >= _minWidth)); } //if only one of them is set, then only that condition needs to be satisfied else if (_minHeight > 0) { SetActive(_currentHeight >= _minHeight); } else { SetActive(_currentWidth >= _minWidth); bool bbb = _currentWidth >= _minWidth; Debug.WriteLine("Widthtrigger :" + bbb); } } else { SetActive(false); } } } MainPage.xaml: <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="ControlSizeStates"> <VisualState x:Name="SizeChange"> <VisualState.StateTriggers> <local:ControlSizeTrigger MinWidth="800" TargetElement="{x:Bind Path=MyStackPanel}" /> <!--<AdaptiveTrigger MinWindowHeight="500" />--> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="MyStackPanel.Background" Value="Red" /> <Setter Target="MyStackPanel.Orientation" Value="Horizontal" /> <Setter Target="MyButton.Foreground" Value="Black" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <StackPanel x:Name="MyStackPanel" Width="100" Height="200" Background="AliceBlue" Orientation="Vertical"> <Button x:Name="MyButton" Foreground="Red" Content="Click" Click="Button_Click"/> <Button x:Name="MyButton2" Foreground="Red" Content="Click" /> </StackPanel> </Grid> MainPage.cs: public MainPage() { this.InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { MyStackPanel.Width = 1100; }
Edit Text MotionEventActions when 'IsEnabled=False'
I have that show/hide pass feature and it works just fine. One of my views ilustrated below has a security code that effect is also applied on Entry Text that has property 'IsEnabled=False'. Right now when I click on an eye nothing happens. Is there any way to get it working when text entry is not enabled? <StackLayout Grid.Row="1" IsVisible="{Binding IsPINSectionVisible}"> <Label Style="{StaticResource MessageLabelStyle}" Text="{i18n:Translate Pin_Text}"> </Label> </StackLayout> <StackLayout Grid.Row="2" IsVisible="{Binding IsPINSectionVisible}"> <Entry Text="{Binding PIN.Value, Mode=TwoWay}" IsEnabled="False" IsPassword="True" Placeholder="{i18n:Translate Pin_Title}"> <Entry.Style> <OnPlatform x:TypeArguments="Style" Android="{StaticResource EntryStyle}" /> </Entry.Style> <Entry.Behaviors> <behaviors:EventToCommandBehavior EventName="TextChanged" Command="{Binding ValidatePINCommand}" /> </Entry.Behaviors> <Entry.Effects> <effects:ShowHidePassEffect /> </Entry.Effects> <Entry.Triggers> <DataTrigger TargetType="Entry" Binding="{Binding PIN.IsValid}" Value="False"> <Setter Property="behaviors:LineColorBehavior.LineColor" Value="{StaticResource ErrorColor}" /> <Setter Property="Entry.PlaceholderColor" Value="{StaticResource ErrorColor}" /> </DataTrigger> </Entry.Triggers> </Entry> And Android Effect class: public class ShowHidePassEffect : PlatformEffect { protected override void OnAttached() { ConfigureControl(); } protected override void OnDetached() { } private void ConfigureControl() { EditText editText = ((EditText)Control); editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.pass_show_24, 0); editText.SetOnTouchListener(new OnDrawableTouchListener()); } } public class OnDrawableTouchListener : Java.Lang.Object, Android.Views.View.IOnTouchListener { public bool OnTouch(Android.Views.View v, MotionEvent e) { if (v is EditText && e.Action == MotionEventActions.Up) { EditText editText = (EditText)v; if (e.RawX >= (editText.Right - editText.GetCompoundDrawables()[2].Bounds.Width())) { if (editText.TransformationMethod == null) { editText.TransformationMethod = PasswordTransformationMethod.Instance; editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.pass_show_24, 0); } else { editText.TransformationMethod = null; editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.pass_hide_24, 0); } return true; } } return false; } } And picture to ilustrate the view:
xamarin Forms: Move the view Upward according to keyboard height
I am using xamarin forms. I have designed a login form page in xaml. I want to shift the login form view upward when the keyboard appears, so that both the text field and login button is visible in case of both the platform Android and IOS. How to calculate the keyboard height and shift the Login form view upward by dynamically calculating the keyboard height. Below is my xaml code : <ContentPage> <ScrollView> <AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"> <Grid Padding="20, 30, 20, 20" RowSpacing="20" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Image Grid.Row="0" Source="login.png" HorizontalOptions="Center" VerticalOptions="Center"/> <Entry Grid.Row="2" x:Name="entryUserName" HorizontalOptions="Fill" Placeholder="Username" PlaceholderColor="#707070" Text="{Binding UserName,Mode=TwoWay}" Margin="5"/> <BoxView Grid.Row="2" HeightRequest="1" HorizontalOptions="Fill" BackgroundColor="#707070" VerticalOptions="End"/> <Entry Grid.Row="3" x:Name="entryPassword" Text="{Binding Password,Mode=TwoWay}" Placeholder="Password" PlaceholderColor="#707070" Margin="5" HorizontalOptions="Fill" IsPassword="True"/> <BoxView Grid.Row="3" HeightRequest="1" HorizontalOptions="Fill" BackgroundColor="#707070" VerticalOptions="End"/> <Button Grid.Row="5" HorizontalOptions="Center" VerticalOptions="Center" Text="Login" Command="{Binding doLoginCommand}" CommandParameter="entryUserName,entryPassword" /> </Grid> </AbsoluteLayout> </ScrollView> </ContentPage> I don't want to perform any kind of custom rendering of the page. Is there any resource through which I can write the dependency service to calculate the keyboard height of different mobile view cross platform. I gone through this but it has some kind of custom rendering which I don't want.
Option 1: Android: Add this to your manifest: <activity //Your MainActivity android:windowSoftInputMode="stateVisible|adjustResize" ... > ... </activity> Ios: Add this nuget package: https://www.nuget.org/packages/Xam.Plugins.Forms.KeyboardOverlap/ and init it: Xamarin.Forms.Init();//platform specific init KeyboardOverlapRenderer.Init (); Option 2: Add this code to your Page class: protected override void OnAppearing() { base.OnAppearing(); entryUserName.Focused += InputFocused; entryPassword.Focused += InputFocused; entryUserName.Unfocused += InputUnfocused; entryPassword.Unfocused += InputUnfocused; } protected override void OnDisappearing() { base.OnDisappearing(); entryUserName.Focused -= InputFocused; entryPassword.Focused -= InputFocused; entryUserName.Unfocused -= InputUnfocused; entryPassword.Unfocused -= InputUnfocused; } void InputFocused(object sender, EventArgs args){ Content.LayoutTo(new Rectangle(0,-360, Content.Bounds.Width, Content.Bounds.Height)); } void InputUnfocused(object sender, EventArgs args){ Content.LayoutTo(new Rectangle(0,0, Content.Bounds.Width, Content.Bounds.Height)); }
Here is a Entry renderer to force the SoftInputMode on Android, Hope this helps: using System; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; using Android.Widget; using Android.Util; using Android.OS; using Android.Views.InputMethods; using System.Threading; using Android.Views; using Android.App; [assembly: ExportRenderer(typeof(FormsEntry), typeof(DroidEntryRenderer))] namespace XXX { public class DroidEntryRenderer : EntryRenderer, IEntryMessages { private bool _inititialized = false; EditText editText; protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (e.OldElement != null) { // unhook old events } if (e.NewElement != null) { // hook new events editText = (EditText)Control; var entry = e.NewElement as FormsEntry; (this.Element as FormsEntry).OnShowKeyboard += DroidEntryRenderer_showKeyboard; (this.Element as FormsEntry).OnChangeIme += DroidEntryRenderer_changeIme; if(entry.KeyboardInputMode == SoftInputMode.AdjustNothing) (Forms.Context as Activity).Window.SetSoftInputMode(SoftInput.AdjustNothing ); else if(entry.KeyboardInputMode == SoftInputMode.AdjustResize) (Forms.Context as Activity).Window.SetSoftInputMode(SoftInput.AdjustResize ); else (Forms.Context as Activity).Window.SetSoftInputMode(SoftInput.AdjustPan ); if(entry.SetImeToNext){ Control.ImeOptions = Android.Views.InputMethods.ImeAction.Next; Control.SetImeActionLabel("Next", Android.Views.InputMethods.ImeAction.Next); switch(entry.CustomImeAction){ case ImeAction.Email: editText.EditorAction += (object sender, TextView.EditorActionEventArgs args) => { MessagingCenter.Send<IEntryMessages>(this, "Email"); }; break; case ImeAction.Password: editText.EditorAction += (object sender, TextView.EditorActionEventArgs args) => { MessagingCenter.Send<IEntryMessages>(this, "Password"); }; break; } } if (entry.HasBorder) { editText.SetBackgroundResource(Resource.Drawable.BorderEntry); } // edit properties if (entry.Font != Font.Default) { RendererHelper.SetTextViewFont(editText, entry.Font); } if (entry.PlaceholderColor != Color.Default) editText.SetHintTextColor(entry.PlaceholderColor.ToAndroid()); switch (entry.XAlign) { case Xamarin.Forms.TextAlignment.Start: editText.Gravity = Android.Views.GravityFlags.CenterVertical | Android.Views.GravityFlags.Left; break; case Xamarin.Forms.TextAlignment.Center: editText.Gravity = Android.Views.GravityFlags.Center; break; case Xamarin.Forms.TextAlignment.End: editText.Gravity = Android.Views.GravityFlags.CenterVertical | Android.Views.GravityFlags.Right; editText.SetPadding(0, editText.PaddingTop, 0, editText.PaddingBottom); break; } if (entry.ReturnKeyType == KeyboardType.Done) editText.ImeOptions = global::Android.Views.InputMethods.ImeAction.Done; else if (entry.ReturnKeyType == KeyboardType.Next) editText.ImeOptions = global::Android.Views.InputMethods.ImeAction.Next; } } void DroidEntryRenderer_showKeyboard() { ShowKeyboard(); } void DroidEntryRenderer_changeIme() { ChangeIme(); } public void ChangeIme(){ Control.ImeOptions = Android.Views.InputMethods.ImeAction.Next; Control.SetImeActionLabel("Next", Android.Views.InputMethods.ImeAction.Next); } public void ShowKeyboard() { Device.BeginInvokeOnMainThread(() => { this.Control.RequestFocus(); InputMethodManager inputMethodManager = this.Control.Context. GetSystemService(Android.Content.Context.InputMethodService) as InputMethodManager; inputMethodManager.ShowSoftInput(this.Control, ShowFlags.Forced); inputMethodManager.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.ImplicitOnly); }); } } }
MVVM binding cutom property to view model
I am new in MVVVM so please forgive me if it is stupid question. I am using this example http://www.codeproject.com/Articles/36848/WPF-Image-Pixel-Color-Picker-Element and included there library to get color of indicated by user pixel of image. it looks nice and dipsalys in rectangle selected color but i neeed to bind the selecteed value to viewmodel. here is my xaml code: <Window x:Class="MovieEditor.View.PixelSelector" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ctrls="clr-namespace:ColorPickerControls;assembly=ColorPickerControls" xmlns:local="clr-namespace:MovieEditor.MVVMCommon" Title="FilterDesigner" Height="550" Width="550" Icon="..\Resources\Images\icon.ico" xmlns:VM="clr-namespace:MovieEditor.ViewModel"> <Window.DataContext> <VM:PixelSelectorVM/> </Window.DataContext> <Window.Resources> <local:ColorToBrushConverter x:Key="ColorToBrushConverter"/> </Window.Resources> <Grid Background="#FF191919" > <DockPanel> <Grid Margin="10,10,10,1"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="Auto" MinHeight="38"/> </Grid.RowDefinitions> <Border BorderBrush="White" BorderThickness="5" Margin="0,39,0,11"> <ctrls:ImageColorPicker Binding.XmlNamespaceManager="{Binding p PixelSelectorVM.MyImageColorPicker, UpdateSourceTrigger=PropertyChanged}" x:Name="image" Source ="{Binding Frame}" Margin="0,36,0,0" /> </Border> <Border Width="77" HorizontalAlignment="Center" BorderBrush="White" BorderThickness="1" Margin="263,2,182,435"> <Rectangle Fill="{Binding ElementName=image, Path=SelectedColor, Converter={StaticResource ColorToBrushConverter}}" RenderTransformOrigin="0.549,0.429" Margin="1"/> </Border> <Button Content="Save" Command="{Binding Save}" Margin="165,0,0,4" Grid.Row="1" HorizontalAlignment="Left" Width="60"/> <Label Content="Selected pixel color:" HorizontalAlignment="Left" Height="18" Margin="140,11,0,0" VerticalAlignment="Top" Width="110"/> <Button Content="Cancel" Command="{Binding Cancel}" Margin="0,1,165,4" HorizontalAlignment="Right" Width="60" RenderTransformOrigin="0.5,0.5" Grid.Row="1"> </Button> </Grid> </DockPanel> </Grid> </Window> </code> And here is my view model: public class PixelSelectorVM : ViewModelBase { private BitmapImage frame; public MainWindowVM parentMainWindowVM; private ImageColorPicker imageColorPicker; public ImageColorPicker MyImageColorPicker { get { return this.imageColorPicker; } set { this.imageColorPicker = value; OnPropertyChanged("MyImageColorPicker"); } } public BitmapImage Frame { get { return this.frame; } set { this.frame = value; OnPropertyChanged("Frame"); } } public PixelSelectorVM(BitmapImage image, MainWindowVM mainWindowVM) { this.frame = image; this.parentMainWindowVM = mainWindowVM; this.imageColorPicker = new ImageColorPicker(); this.imageColorPicker.Source = image; } public PixelSelectorVM() { } public ICommand Save { get { return new RelayCommand(SaveExecute); } } public ICommand Cancel { get { return new RelayCommand(CancelExecute); } } private void SaveExecute() { } private void CancelExecute() { } } Please suggest me solution how can i pass the selected color to view model
You should be able to bind ImageColorPicker's SelectedColor to ViewModel's Property. So in XAML add the binding: SelectedColor="{Binding MySelectedColor, Mode=TwoWay}" And in VM add the MySelectedColor property: private Color selectedColor; public Color MySelectedColor { get { return this.selectedColor; } set { this.selectedColor = value; OnPropertyChanged("MySelectedColor"); } } When control's SelectedColor changes, it should automatically update the MySelectedColor in your VM.
Changing the orientation of a user control (ProgressBar) in WP7?
I'm using a progress bar in my app, this progress bar is defined inside the user control, e.g.: UserControl x:Class="StirLibrary.ProgressBarControl" 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" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="480"> <Grid x:Name="LayoutRoot" Height="800"> <Border BorderThickness="2" BorderBrush="Transparent" Background="Transparent" Margin="50,522,50,158"> <StackPanel> <TextBlock Text="Loading..." Name="loading" Grid.Row="1" HorizontalAlignment="Center" Height="30" Foreground="Green"> </TextBlock> <ProgressBar Background="Transparent" Margin="10, 0, 0, 10" Height="80" HorizontalAlignment="Center" Name="progressBar1" VerticalAlignment="Top" Width="380" Grid.Row="2" HorizontalContentAlignment="Left" IsHitTestVisible="True" VerticalContentAlignment="Top" Value="0" Maximum="100"> </ProgressBar> </StackPanel> </Border> </Grid> </UserControl> My problem is when the orientation of my app changes to landscape the progress bar's orientation doesn't change and this makes the app look ugly. Any suggestions how to avoid this and make the progress bar displayed as per orientation are welcome.
As Matt has mentioned above it is not possible to orient a pop up in user control because User control doesn't have any room for supported orientation. but since it was very crucial requirement for our App i found a work around and made few changes in the Main Page's class file and the user control's class file.. the changes are: private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e) { if ((e.Orientation & PageOrientation.Portrait) == PageOrientation.Portrait) { ProgressBarControl.getInstance().ProgressBarControl_LayoutUpdated(this, e,e.Orientation.ToString()); } else if ((e.Orientation & PageOrientation.Landscape) == PageOrientation.Landscape) { ProgressBarControl.getInstance().ProgressBarControl_LayoutUpdated(this, e, e.Orientation.ToString()); } } These are the changes in MainPage.xaml.cs public partial class ProgressBarControl : UserControl { private static ProgressBarControl instance = null; public static Popup popup; private ProgressBarControl() { InitializeComponent(); } public static ProgressBarControl getInstance() { if (instance == null) { instance = new ProgressBarControl(); popup = new Popup(); popup.Child = instance; popup.IsOpen = false; } return instance; } public void ProgressBarControl_LayoutUpdated(object sender, EventArgs e,string orientation) { if (orientation == "LandscapeRight") { ProgressPanel.RenderTransformOrigin = new Point(0.5, 0.5); ProgressPanel.RenderTransform = new CompositeTransform { Rotation = 270 }; } else if(orientation == "LandscapeLeft") { ProgressPanel.RenderTransformOrigin = new Point(0.5, 0.5); ProgressPanel.RenderTransform = new CompositeTransform { Rotation = 90 }; } else { ProgressPanel.RenderTransformOrigin = new Point(0, 0); ProgressPanel.RenderTransform = new CompositeTransform { Rotation = 0 }; } } public static void displayProgressBar(int requestId, int status, string msg) { System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => { if (instance == null) { instance = new ProgressBarControl(); popup = new Popup(); popup.Child = instance; } popup.IsOpen = true; instance.loading.Text = msg; instance.progressBar1.IsIndeterminate = true; instance.progressBar1.Value = status; }); } public static void dismissProgressBar() { System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => { if(popup!=null) { popup.IsOpen = false; } }); } } and this what i have done in my ProgressBarControl.cs file (this is the user control's class file) Xaml file: <UserControl x:Class="StirLibrary.ProgressBarControl" 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" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="480"> <Grid x:Name="LayoutRoot" Height="800"> <!--<Border BorderThickness="2" BorderBrush="Black" Background="Transparent" Margin="54,406,50,320"></Border>--> <StackPanel x:Name="ProgressPanel" Background="Black" Margin="54,406,50,320"> <TextBlock Text="Loading..." Name="loading" Grid.Row="1" HorizontalAlignment="Center" Height="32" Foreground="White"></TextBlock> <ProgressBar Background="Green" Margin="10, 0, 0, 10" Height="33" Foreground="White" HorizontalAlignment="Center" Name="progressBar1" VerticalAlignment="Top" Width="351" Grid.Row="2" HorizontalContentAlignment="Left" IsHitTestVisible="True" VerticalContentAlignment="Top" Value="0" Maximum="100"></ProgressBar> </StackPanel> </Grid> </UserControl>
I could enable the orientation for my popup UserControl by simply adding to the Children of the main screen on top of which the Popup is being displayed as: popUp = new Popup(); loginControl = new LoginPopup(); // this is the custom UserControl popUp.Child = loginControl; LayoutRoot.Children.Add(popUp);
The Popup class does not support orientation so you can't use this and expect it to handle orientation changes. This is regardless of whether the control displayed in the popup is in the same assembly or not. Instead of using a Popup a simple alternative would be to put the control directly on top of all other content on the page. You could include this inside another control (such as a grid or a panel) if you wish. Manually adding a RotateTransform to the control will give you the ability to add extra control over adjusting the orientation but I'd recommend not going down this route if you can avoid it.