I want to capture the text from the textbox when enter key is hit. I am using WPF/visual studio 2010/.NET 4. I dont know what event handler to be used in the tag ? I also want to do the same for maskedtextbox.
Either KeyDown or KeyUp.
TextBox tb = new TextBox();
tb.KeyDown += new KeyEventHandler(tb_KeyDown);
static void tb_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
//enter key is down
}
}
You can also use PreviewKeyDown in WPF:
<TextBox PreviewKeyDown="EnterClicked" />
or in C#:
myTextBox.PreviewKeyDown += EnterClicked;
And then in the attached class:
void EnterClicked(object sender, KeyEventArgs e) {
if(e.Key == Key.Return) {
DoSomething();
e.Handled = true;
}
}
The KeyDown event only triggered at the standard TextBox or MaskedTextBox by "normal" input keys, not ENTER or TAB and so on.
One can get special keys like ENTER by overriding the IsInputKey method:
public class CustomTextBox : System.Windows.Forms.TextBox
{
protected override bool IsInputKey(Keys keyData)
{
if (keyData == Keys.Return)
return true;
return base.IsInputKey(keyData);
}
}
Then one can use the KeyDown event in the following way:
CustomTextBox ctb = new CustomTextBox();
ctb.KeyDown += new KeyEventHandler(tb_KeyDown);
private void tb_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
//Enter key is down
//Capture the text
if (sender is TextBox)
{
TextBox txb = (TextBox)sender;
MessageBox.Show(txb.Text);
}
}
}
In WPF, TextBox element will not get opportunity to use "Enter" button for creating KeyUp Event until you will not set property: AcceptsReturn="True".
But, it would`t solve the problem with handling KeyUp Event in TextBox element. After pressing "ENTER" you will get a new text line in TextBox.
I had solved problem of using KeyUp Event of TextBox element by using Bubble event strategy. It's short and easy. You have to attach a KeyUp Event handler in some (any) parent element:
XAML:
<Window x:Class="TextBox_EnterButtomEvent.MainWindow"
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:TextBox_EnterButtomEvent"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid KeyUp="Grid_KeyUp">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height ="0.3*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="1" Grid.Column="1" Padding="0" TextWrapping="WrapWithOverflow">
Input text end press ENTER:
</TextBlock>
<TextBox Grid.Row="2" Grid.Column="1" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Row="4" Grid.Column="1" Padding="0" TextWrapping="WrapWithOverflow">
You have entered:
</TextBlock>
<TextBlock Name="txtBlock" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Stretch"/>
</Grid></Window>
C# logical part (KeyUp Event handler is attached to a grid element):
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Grid_KeyUp(object sender, KeyEventArgs e)
{
if(e.Key == Key.Enter)
{
TextBox txtBox = e.Source as TextBox;
if(txtBox != null)
{
this.txtBlock.Text = txtBox.Text;
this.txtBlock.Background = new SolidColorBrush(Colors.LightGray);
}
}
}
}
Result:
For those who struggle at capturing Enter key on TextBox or other input control, if your Form has AcceptButton defined, you will not be able to use KeyDown event to capture Enter.
What you should do is to catch the Enter key at form level. Add this code to the form:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((this.ActiveControl == myTextBox) && (keyData == Keys.Return))
{
//do something
return true;
}
else
{
return base.ProcessCmdKey(ref msg, keyData);
}
}
Related
When I use inkcanvas1.EditingMode is InkCanvasEditingMode.EraseByPoint it is erasing and also StrokeErased event firing.
but when I erase stroke through inkcanvas1.Strokes.Erase(); function then StrokeErased event is not firing. then how can I identify which stroke erased and which strokes are newly created. consider on my inkcanvas thousands of strokes. so I'm not able to maintain every added and removed strokes.
is there any other event or any solution.
I have a below sample WPF Inkcanvas code
XAML Code
<Window x:Class="MyWhiteBoard.MainWindow"
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:MyWhiteBoard"
mc:Ignorable="d"
WindowState="Maximized"
Title="MainWindow" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<InkCanvas x:Name="inkcanvas1" Grid.Row="0" StrokeErased="inkcanvas1_StrokeErased" MouseMove="inkcanvas1_MouseMove"></InkCanvas>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Width="100" Height="50" Background="WhiteSmoke" Content="Draw" Click="drawInkClick"></Button>
<Button Width="100" Height="50" Background="WhiteSmoke" Content="Erase by Point" Click="EraseByPointsClick"></Button>
<Button Width="100" Height="50" Background="WhiteSmoke" Content="Stroke Erase" Click="StrokeEraseClick"></Button>
<Button Width="100" Height="50" Background="WhiteSmoke" Content="clear all" Click="clearAllClick"></Button>
</StackPanel>
</Grid>
</Window>
Code Behind C# code
public partial class MainWindow : Window
{
private bool IsStrokeEraseCalled = false;
public MainWindow()
{
InitializeComponent();
}
private void inkcanvas1_StrokeErased(object sender, RoutedEventArgs e)
{
// why this event is not calling when I use
//inkcanvas1.Strokes.Erase
}
private void EraseByPointsClick(object sender, RoutedEventArgs e)
{
inkcanvas1.EditingMode = InkCanvasEditingMode.EraseByPoint;
}
private void StrokeEraseClick(object sender, RoutedEventArgs e)
{
inkcanvas1.EditingMode = InkCanvasEditingMode.Select;
IsStrokeEraseCalled = !IsStrokeEraseCalled;
}
private void clearAllClick(object sender, RoutedEventArgs e)
{
inkcanvas1.Strokes.Clear();
}
private void inkcanvas1_MouseMove(object sender, MouseEventArgs e)
{
if (IsStrokeEraseCalled)
{
Point currentPoint = e.GetPosition((IInputElement)sender);
List<Point> enumrator = new List<Point>();
enumrator.Add(new Point(currentPoint.X, currentPoint.Y));
StylusShape EraseShape = (StylusShape)new RectangleStylusShape(100, 100, 0);
inkcanvas1.Strokes.Erase(enumrator, EraseShape);
}
}
private void drawInkClick(object sender, RoutedEventArgs e)
{
inkcanvas1.EditingMode = InkCanvasEditingMode.Ink;
}
}
Replace your StrokeEraseClick event with following code:
private void StrokeEraseClick(object sender, RoutedEventArgs e)
{
inkcanvas1.EditingMode = InkCanvasEditingMode.EraseByPoint;
inkcanvas1.EraserShape = new RectangleStylusShape(100, 100);
var editMode = inkcanvas1.EditingMode;
inkcanvas1.EditingMode = InkCanvasEditingMode.None;
inkcanvas1.EditingMode = editMode;
}
It will leave the current mode to InkCanvasEditingMode.EraseByPoint and allow you to erase defined area stokes. StrokeErased event will be fired every time you erase strokes using this approach.
try this
public MainWindow()
{
InitializeComponent();
inkcanvas1.Strokes.StrokesChanged += Strokes_StrokesChanged;
}
private void Strokes_StrokesChanged(object sender, StrokeCollectionChangedEventArgs e)
{
StrokeCollection newlyAddedStroke = e.Added;
StrokeCollection oldRemovedStroke = e.Removed;
}
When you erase stroke through inkcanvas1.Strokes.Erase(); function then the StrokeErased event will not fire by default.
If you want to maintain added and removed strokes then you can handle it in inkcanvas1.Strokes.StrokesChanged event.
Or you should be in EraseByPoint Mode and use statement
inkcanvas1.EraserShape = new RectangleStylusShape(100, 100);
If you have bulk strokes on your inkcanvas then for maintaining every strokecollection every time is heavy then you have choice to add unique id to every stroke using ProperyData property.
I have an ellipse in the code below which has a mouse move event. Now everything is good unless I use mouse.capture on the element.
The mouse move event gets fired immediately I apply mouse.capture on the element even if I don't move my mouse, and also moving the position of the element by using setleft property also fires the mouse move event even if I don't move my mouse at all! Is this supposed to happen? And if there's a solution I badly need it..
The code below will generate the exact problem...
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace Test
{
public partial class MainWindow : Window
{
public Ellipse elp;
public Point clickPoint;
public MainWindow()
{
InitializeComponent();
testcanv.Background = Brushes.Transparent;
}
private void down(object sender, MouseButtonEventArgs e)
{
clickPoint = e.GetPosition(testcanv);
if (e.ChangedButton == MouseButton.Left)
{
elp = new Ellipse
{
Stroke = Brushes.Blue,
StrokeThickness = 2,
Width = 200,
Height = 200,
Margin = new Thickness(-250)
};
Canvas.SetLeft(elp, clickPoint.X);
Canvas.SetTop(elp, clickPoint.Y);
elp.MouseMove += circle_move;
testcanv.Children.Add(elp);
}
}
private void circle_move(object sender, MouseEventArgs e)
{
text.Text += "Moved,";
}
private async void click(object sender, RoutedEventArgs e)
{
Mouse.Capture(elp, CaptureMode.Element);
await Task.Delay(1000);
Canvas.SetLeft(elp, 100);
Canvas.SetTop(elp, 100);
await Task.Delay(500);
Mouse.Capture(null);
}
}
}
And here is my XAML
<Window x:Class="Test.MainWindow"
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:balchal"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Canvas x:Name="testcanv" Grid.Column="0" Grid.Row="0" MouseDown="down"/>
<Button Grid.Column="1" Grid.Row="1" Content="Button" Click="click"/>
<TextBox x:Name="text" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" Width="300" Margin="10"/>
</Grid>
</Window>
Thanks in advance... I really appreciate any kind of help...
I may be wrong, but I believe that the MouseMove event always fires when capturing
The simplest solution, if it's happening consistently, is probably just to store the state in the click event and check for it at the start of the move event: returning immediately and resetting the var.
bool CapturedFlag = false;
private void MoveEvent(object sender, MouseButtonEventArgs e)
{
if(CapturedFlag = true)
{
CapturedFlag = false;
return;
}
// other code
}
private async void CaptureEvent(object sender, RoutedEventArgs e)
{
CapturedFlag = true;
// other code
}
I'm using WPF
I want to auto-tab to the next texbox when 'MaxLength' is reached.
I found this code : XAML Trigger Auto-tab when MaxLength is Reached
And it's working. But the problem is, I can't delete text when the MaxLength is reached !
I can't change the actual text too.
Do you have an idea to allow me to modify, or delete text from a MaxLength reached textbox ?
My XAML :
<TextBox Grid.Column="0" Name="txtC1" Margin="5" MaxLength="7" PreviewKeyDown="txt1_PreviewKeyDown"></TextBox>
<TextBox Grid.Column="1" Name="txt2" Margin="5" MaxLength="12" PreviewKeyDown="txt2_PreviewKeyDown"></TextBox>
<TextBox Grid.Column="2" Name="txt3" Margin="5" MaxLength="12" PreviewKeyDown="txt3_PreviewKeyDown"></TextBox>
Code Behind
private void txt1_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
// Auto-tab when maxlength is reached
if (((TextBox)sender).MaxLength == ((TextBox)sender).Text.Length)
{
// move focus
var ue = e.OriginalSource as FrameworkElement;
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
The problem is that you are using the event on a keyDown and that means that when backspace or delete is pressed, the event is triggered but the text hasn't changed until the keyDown event is done, so the code will always validate with the same number of characters in the textBox and it will take one more character to type in the box to trigger the change of focus in your case.
You can do something like this instead
XAML
<TextBox Grid.Column="0" Name="txtC1" Margin="5" MaxLength="7" TextChanged="txt1_TextChanged"></TextBox>
<TextBox Grid.Column="1" Name="txt2" Margin="5" MaxLength="12" TextChanged="txt2_TextChanged"></TextBox>
<TextBox Grid.Column="2" Name="txt3" Margin="5" MaxLength="12" TextChanged="txt3_TextChanged"></TextBox>
Code
private void txt1_TextChanged(object sender, TextChangedEventArgs e)
{
if (((TextBox)sender).MaxLength == ((TextBox)sender).Text.Length)
{
// move focus
var ue = e.OriginalSource as FrameworkElement;
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
You can still do some keyDown event for something else e.g.: Allowing some key only like numbers or special numbers, but it is better to validate the text lenght with a textChanged event.
I resolved my own problem. Thanks to differents answers I got, I used them a little.
This is my new code behind :
private void txt1_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
// Auto-tab when maxlength is reached
if (((TextBox)sender).MaxLength == ((TextBox)sender).Text.Length)
{
if(e.Key != Key.Delete && e.Key != Key.Clear && e.Key != Key.Back && ((TextBox)sender).SelectionLength == 0)
{
// move focus
var ue = e.OriginalSource as FrameworkElement;
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
}
And it's working.
I've got some trouble with stoping tunneling with Touch when a window was launched with ShowDialog().
My problem is : When I Touch the button in my Window, the clic(or touch ) continue to the MainWindow and open a new Window if antoher Button is behind.
I try to use
e.Handle = true;
To stop tunneling, it work if i clic with my mouse, but if i touch my screen it don't.
Here is a sample Of Code : ( This sample Window have just one button 'OK'. )
C#
public partial class MessageWindow : Window
{
.... other code ...
public static MessageBoxResult Show(string caption, MessageTypes type, MessageBoxButton buttons)
{
MessageWindow wnd = new MessageWindow();
wnd.Owner = Application.Current.MainWindow;
wnd.Title = "Error Message";
wnd.IsError = true;
wnd.Message = caption;
wnd.IsOk = true;
wnd.ShowDialog();
return wnd.Result;
}
private void OnOK()
{
Result = MessageBoxResult.OK;
this.DialogResult = true;
}
private void _btOK_Click(object sender, RoutedEventArgs e)
{
e.Handled = true;
OnOK();
}
private void _btOKonly_TouchDown(object sender, TouchEventArgs e)
{
e.Handled = true;
OnOK();
}
.... other code again ....
}
XAML
<Grid x:Name="LayoutRoot" Background="White" Width="640" Height="480">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Background="Black" Padding="20,10">
<TextBlock TextWrapping="Wrap" Text="{Binding Title, ElementName=Window}"/>
</Border>
<Button x:Name="_btOKonly" Content="OK" Click="_btOK_Click" TouchDown="_btOK_Click"Grid.Row="2"/>
<StackPanel>
< ... text of error ...>
</StackPanel>
</Grid>
Here is the code to launch my window :
C#
MessageWindow.Show(" This is a sample of error message", MessageWindow.MessageTypes.Error);
Thanks EveryOne Can Help Me :)
Finaly I found my Answer.
In fact i have to just captur "Clic" and not the "Touch" action like this
<Button x:Name="_btOKonly" Content="OK" Click="_btOK_Click" Grid.Row="2"/>
And The "Clic" is Handle like it does.
I'm pretty stuck right now, i'm gonna explain my problem and what i want.
In my solution i have a mainWindow, in that MainWindow i call the first userControl Who is situated in an userControlLibrary. I'ts a menu with button. I want when i click on the first button of the first userControl, i want put the visibility of the second usercontrol to visible (too situated in the userControlLibrary). But i try many things but no one works.
The first userControl is UC_MenuSlider and UC_Start_Study is the second who have to be visibile after click on the button on the first one. At launch UC_Start_Study is hidden.
This is a part of the code of my Mainwindow:
<Grid Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<UserControlLibrary:UC_StartStudy x:Name="UC_Start_Study" Grid.Column="1" Height="Auto" Width="Auto" Margin="70 0 0 0" Visibility="Hidden"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*" MaxWidth="240" MinWidth="240" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<UserControlLibrary:UC_MenuSlider x:Name="UC_MenuSlider" Grid.Column="0"/>
</Grid>
</Grid>
A part of the code of my first UserControl (UC_MenuSlider):
<Grid Name="Grid_Menu" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="Start_Study" Grid.Row="0" Grid.Column="0" Margin="0" Content="Start Study" FontSize="16" Click="Start_Study_Click">
</Button>
</Grid>
At first a basic event,just an event click in my first userControl. with code behind like that:
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
var startStudy = new UserControlLibrary.UC_StartStudy();
startStudy.Visibility = Visibility.Visible;
}
Don't works. Then i use 'RoutedEvent' But I don't really understand who it works.
I hope my question was enough clear, thanks in advance for your anwsers
The problem is because you are creating a new UC_StartStrudy and set its Visibility to Visible. What you really need is to set Visibility of the one in your XAML: UC_Start_Study
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
UC_Start_Study.Visibility = Visibility.Visible;
}
And you could also use XAML databinding the Visibility property of your UC_StartStrudy, and set its value in your code:
XAML:
<Window.Resourses>
<BooleanToVisibilityConverter x:Key="BooltoVisible" />
</Window.Resourse>
.....
<UserControlLibrary:UC_StartStudy x:Name="UC_Start_Study" Grid.Column="1" Height="Auto" Width="Auto" Margin="70 0 0 0" Visibility="{Binding IsUCStartStudyVisible, Converter={StaticResource BooltoVisible}}"/>
Code (remember to implement INotifyPropertyChanged ):
//implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChange(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//property for data binding
private bool _isucstartstudyvisible = false;
public bool IsUCStartStudyVisible
{
get{return _isucstartstudyvisible;}
set{_isucstartstudyvisible=value; RaisePropertyChange("IsUCStartStudyVisible");}
}
//your event to change the visibility
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
IsUCStartStudyVisible=true;
}
I don't understand why you are taking a new instance of UC_StartStudy() as you have already added this in your MainWindow.
Can't you simply turn the visibility of UC_Start_Study as visible within the code.
Let me show you how you can do this.
try
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
this.UC_Start_Study.Visibility = Visibility.Visible;
}