I have two textbox's. I have an event setup for the "onLostFocus" of the textbox's. If i finish typing a word into both boxes one after the other all is well. At the point where i click back on the first textbox i want to click halfway through the word (perfectly resonable thing for a user to do). When the onLostFocus event fires here is my code :
void tbox_LostFocus(object sender, RoutedEventArgs e)
{
IInputElement focusedelement = FocusManager.GetFocusedElement(this);
if (focusedelement is TextBox)
{
TextBox focusedTextBox = focusedelement as TextBox;
int focusIndex = m_commandsStacker.Children.IndexOf(focusedTextBox);
int caretIndex = focusedTextBox.CaretIndex;
The caret index returns as 0 when i call focusedTextBox.CaretIndex. At that point I need to refresh the whole form and set parameters and all other kinds of whizzery, storing the texbox index and caret position to put everything back the same. Why does it return 0 and not the position where the caret should be halfway between the word?
This just doesn't work in c# express edition 2008 (whatever version of WPF that is) so the best thing to do here is to switch to onTextChanged and run the exact same code there, which works a treat. Its obviously annoying that you have to run the code multiple more times than if it worked on lost focus. When I get the time I will check if it works in c# express 2010 as we are upgrading (eventually)
Related
I am trying to page up/down the contents of a simple textbox control in a simple Windows Form on NET 6.0, but something is wrong. Textbox shortcuts are enabled (probably why SendKeys.SendWait("^a"); works) and readonly is false.
I have a method (not on the UI thread) that I call to SendKeys.SendWait("{PgUp}"); to the foreground app (which is both the key sender and textbox (with focus) receiver.
If I type PgUp on the keyboard, the textbox pages up as expected.
If I SendKeys.SendWait("^a");, the textbox selects all text as expected.
If I Sendkeys.SendWait("{PgUp}");, the textbox adds a blank line to the bottom of the text.
From this I conclude that my code is working because it sends "^a" and the textbox receives it and selects all text. But somehow the textbox does not handle the "{PgUp}" key, even though it does when the PgUp key is sent by the keyboard.
I've read easily a dozen articles and posts on the web and SO that talk about paging using scrolling events, positioning the caret and then scrolling to the caret, and so on. But none of them say anything about why SendKeys(^a) and keyboard PgUp would work but SendKeys.SendWait("{PgUp}") would fail.
Can anyone tell me what I'm doing wrong and maybe what I need to do (or read) to fix it? Thank you
UPDATE: Jimi asked for some code, so here is the code that I use to send the ^a and the {PgUp} keys. I know this is not on the UI thread because it is executed from a voice-driven recognizer thread. The app is a voice-driven app that displays content in the textbox by textbox.AppendLines calls. I was trying to PgUp and PgDn the multi-line textbox by voice as well.
When I tried to use Send (I normally use .SendWait for everything in other programs), I received the following error message:
System.InvalidOperationException: 'SendKeys cannot run inside this
application because the application is not handling Windows messages.
Either change the application to handle messages, or use the
SendKeys.SendWait method.'
It is true that my app does not intercept Windows messages. I can't figure out why the app can receive and properly process my keyboard keys, and my "^a' shortcut keys, but not the SendWait("{PgUp}") key.
internal static void
HelperPageUp() {
var keys = "{PgUp}";
keys = "^a";
SendKeys.SendWait(keys);
}
I'm starting to think that {PgUp} is never handled by a textbox or control. Instead, probably {PgUp} must be handled by logic in a case statement that converts PgUp "orders" into sets of actions that implement whatever PgUp means to the app that receives the PgUp key. So maybe I will have to add a keystroke handler to the form. Maybe something like this:
textBox1_KeyUp(object sender, KeyEventArgs e) {
// identify the special key and implement what it means
if (e.KeyCode == Keys.PageDown) {
...
e.Handled = true;
}
Yes, my thought at the end of the question was correct. The ^a was handled by the textbox because I had textbox.EnableShortcuts=true;, so the textbox handled the popular ^a shortcut. But keys like {PgUp} are a different matter; they are not included in shortcuts.
The solution was to write code to handle the {PgUp} key explicitly in the form. Here is my code that worked.
void
textBox1_KeyUp(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.PageUp) {
// page the viewport up; watch for end of content
var charIndex = textBox1.SelectionStart;
var lineIndex = textBox1.GetLineFromCharIndex(charIndex);
// move 20 lines up, but not past zero
var newLine = lineIndex - 20;
var newIndex = Math.Max(0, newLine);
// set the new anchor and scroll to it
var newAnchor = textBox1.GetFirstCharIndexFromLine(newIndex);
textBox1.Select(newAnchor,0);
textBox1.ScrollToCaret();
e.Handled = true;
}
This question already has answers here:
Masked TextBox Input Align Left
(2 answers)
Closed 9 years ago.
I'm writing an app in C# with Visual Studio 2012, and I'm needing to format some input text using MaskedTextBox. The user will type in a folder path to the text box, but since the folder path is relative to another path, I need it to start with ".\", but I do not care how long the path is.
Right now, I have the mask set for the box to \.\\CCCCCCCCCCCCCCCCCC. This works fine except for the fact that when the user clicks into the box, it places the cursor where they click instead of the beginning of the box.
Is there a way to set the mask to still put in the ".\" but not to set any limit on the characters that come after it?
Or is there a way I'm overlooking?
EDIT: More info
So I've tried a couple recommended things, but they don't seem to work. The answer linked here doesn't work well. While I can set it to go to that selection point when I click on the box, it will go there every time you need to click on the box. So you can't select the whole box or edit part of what you typed, which is even worse for usability.
I also tried the method suggested by Adelmo. I made an even handler like so:
public Form1()
{
InitializeComponent();
refreshList();
this.textBoxPrintFolder.GotFocus += new EventHandler(textBoxPrintFolder_GotFocus);
}
private void textBoxPrintFolder_GotFocus(object sender, EventArgs e)
{
this.textBoxPrintFolder.Select(2, 0);
}
This works when tabbing to the box, but apparently clicking on the box doesn't go into the GotFocus event.
I've also tried using the MouseEnter event. While it does work, it takes a few seconds before it will move. Not ideal.
Any help would be greatly appreciated.
Maybe using onFocus event:
You can control cursor position (and selection) by TextBox.SelectionStart and TextBox.SelectionLength properties.
Example if you want move cursor to before 3th character set SelectionStart = 2 and SelectionLength = 0.
http://social.msdn.microsoft.com/Forums/en-US/04362a62-8cbf-4d86-a1bc-2aba8e4978ca/cursor-position-in-textbox
Hope it help you
Long time listener, first time caller here. I'm having a strange issue with the TextBox in WinRT C#/XAML that I hope someone may be able to help me with.
Basically, I'm working on creating a Custom Control that essentially requires a second TextBox to be a copy of the first, including showing the same Text, and showing the same Selected Text. Obviously for the Text requirement I simply respond to the TextChanged event on the first TextBox and set the Text of the second TextBox to the Text from the first, which works great.
For the Selected Text requirement I started with a similar solution, and my code for this is as follows:
void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
this.TextBox2.Select(this.TextBox1.SelectionStart, this.TextBox1.SelectionLength);
}
This seemed to work pretty well when initially used with a mouse:
But I'm having a problem when selecting text with Touch. I double-tap within the TextBox to create the first "anchor" as you do in Touch, then drag to begin the selection; but I only ever manage to select a single character normally before the selection stops. The TextBox doesn't lose focus exactly, but the behaviour is similar to that; the selection anchors disappear and I can't continue selecting anything unless I re-double-tap to start a new selection. If I remove the code to select text in TextBox2 then the Touch selection behaves perfectly in TextBox1.
I've been trying to fix this for a while and cannot, I'm not sure if I can get the desired behaviour with WinRT TextBoxes. Does anyone have any ideas? Or perhaps another way to implement a solution with two TextBoxes with this behaviour?
Thanks a lot.
So this is far from an answer, but discovered a few things that maybe will help you or others come up with a potential workaround. Apologies if these are things you've already seen and noted.
First, it's not the call to TextBox2.Select() that's the problem per se. This for instance, works fine for me
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
TextBox2.Select(3, 5);
}
unfortunately, using start and length versus the hard-coded 3 and 5, that is, the following, DOES NOT WORK:
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
TextBox2.Select(start, length);
}
I also discovered that I could select TWO characters if I started from the end, but only one from the beginning. That got me to thinking about dispatching the call to set the second selection:
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low,
() => TextBox2.Select(start, length));
}
Now I can select 2 from the front and 3 and sometimes 4 from the back. Took it a step further, and was able to select as many as six or seven with a really fast swipe.
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
Dispatcher.RunIdleAsync((v) => Highlight());
}
public void Highlight()
{
TextBox2.Select(TextBox1.SelectionStart, TextBox1.SelectionLength);
}
Seems like the trick to working around this is not setting TextBox2 until whatever vestiges of the TextBox1 SelectionChanged event have completed.
This may be worth registering on Connect.
Mine is only a partial solution as well.
I did some debugging and noticed that the SelectionChanged event is fired throughout the text selection process. In other words, a single finger "swipe" will generate multiple SelectionChanged events.
As you found out, calling TextBox.Select during a text selection gesture affects the gesture itself. Windows seems to stop the gesture after the programmatic text selection.
My workaround is to delay as long as possible calling the TextBox.Select method. This does work well, except for one edge case. Where this method fails is in the following scenario:
The user begins a select gesture, say selecting x characters. The user, without taking their finger off the screen, pauses for a second or two. The user then attempts to select more characters.
My solution does not handle the last bit in the above paragraph. The touch selection after the pause does not actually select anything because my code will have called the TextBox.Select method.
Here is the actual code. As I mentioned above, there are multiple selection changed events fired during a single selection gesture. My code uses a timer along with a counter to only do the programmatic selection when there are no longer any pending touch generated selection changed events.
int _selectCounter = 0;
const int SELECT_TIMER_LENGTH = 500;
async private void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
// _selectCounter is the number of selection changed events that have fired.
// If you are really paranoid, you will want to make sure that if
// _selectCounter reaches MAX_INT, that you reset it to zero.
int mySelectCount = ++_selectCounter;
// start the timer and wait for it to finish
await Task.Delay(SELECT_TIMER_LENGTH);
// If equal (mySelectCount == _selectCounter),
// this means that NO select change events have fired
// during the delay call above. We only do the
// programmatic selection when this is the case.
// Feel free to adjust SELECT_TIMER_LENGTH to suit your needs.
if (mySelectCount == _selectCounter)
{
this.TextBox2.Select(this.TextBox1.SelectionStart, this.TextBox1.SelectionLength);
}
}
Environment
Windows XP x32 Visual Studio 2005 Standard Edition
Honeywell Dolphin 9500 running Windows Mobile 2003 (Pocket PC 2003) With built in Barcode scanner and B&W camera Using their SDK located here.
.NET Compact Framework 1.0 SP3 and .NET Framework 1.1
Using VC#
Goal
I have a ListView control with CheckBoxes = true and View = Details on a form but I don't want the check boxes to be "checkable" by the user. I am using it for a status display of record completion. I do, however, want to use the event handler function to check the box via code (i.e. on record completion: lvMeters_ItemCheck(null, null);).
Problem
I have disabled checking the box itself (I think, the touch screen isn't real precise on this device). However, when selecting a row (I have FullRowSelect = true), the control often checks the checkbox and the event handler doesn't seem to be getting called.
Things I have Tried
I tried to basically undo the action in the event handler:
private void lvMeters_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (sender is ListView)
{
if (e.CurrentValue == CheckState.Checked)
lvMeters.Items[e.Index].Checked = true;
else
lvMeters.Items[e.Index].Checked = false;
}
else if (e.CurrentValue == CheckState.Checked)
lvMeters.Items[e.Index].Checked = false;
else
lvMeters.Items[e.Index].Checked = true;
}
The problem is the above handler doesn't get called on a listview select, nor does the SelectedItemChanged event handler call this event handler but it's still checking the box on select. It does get called when checking the box itself.
Need additional information?
Ask away and I'll do my best!
I'm A Novice
So please feel free to tell me I am doing this completely wrong and should do the entire thing differently.
I'm not familiar with the limits of the ListView on the compact framework, but on the standard framework, you can use the TreeNode.StateImageIndex property. The unchecked/checked states are in fact using small images embedded in the standard winforms code (If I remember correctly, they are index 1 and 2). So, for example, if you do this:
private void lvMeters_ItemCheck(object sender, ItemCheckEventArgs e)
{
e.Item.StateImageIndex = 3;
}
It will change the small icon and set it to nothing. You can also use the ListView ImageList.
Sigh...I somehow managed to remove the event handler from the control when muddling with the designer. I checked at some point and it was still there but at that point I actually did have a logic/code problem.
Thanks for your answers :/
Woot, first Stack Overflow post! I've been asked to work on a desktop application to improve an inventory process for my company. I dabbled with WPF in school and I figured I'd start there. After researching some, I learned about MVVM, put a design together, and forged ahead. Finally, I'm stuck and looking for some help and also a sanity check to see if I'm on the right path.
I have single-column DataGrid bound to an observable collection. Users of the application use a scan gun to enter values in. One potential value that I catch in my "Cell" model object is a "MoveNextColumn" value. This raises a custom event in my model that is handled in the View Model. The handler is supposed to simulate blank entries for all remaining rows in that column, set focus on the last row, and wait for input before moving on. So here is what I have so far:
private void dummyCell_MoveToNextColumn(object sender, RoutedEventArgs e) {
e.Handled = true;
// Cell is the model object containing the parsing rules and raising events
var lSender = sender as Cell;
var gridItems = ViewGridReference.Items;
var lastItem = gridItems[gridItems.Count - 1];
if (lSender == lastItem) {
// We are at the bottom of the column
// Move the program on to the next column
CurrentColumn++;
OnPropertyChanged("ItemPositions");
} else {
// Simulate "empty position" input for this cell and all cells down the column
// Cells are validating themselves as the simulation progresses
foreach (Cell item in ViewGridReference.Items) {
item.ActualItemCode = string.Empty;
}
// ViewGridReference is a reference to my DataGrid set from the view
ViewGridReference.Focus();
ViewGridReference.SelectedIndex = gridItems.Count - 1;
ViewGridReference.CurrentCell = new DataGridCellInfo(lastItem, ViewGridReference.Columns[0]);
((DataGridCell)ViewGridReference.SelectedItem).Focus();
}
}
All of this seems to be working as expected: all rows receive blank input and are validated (I use color properties in the cell to which the view binds to signify the validity of the entry).
Unfortunately, though the focus is on the last row as desired, it is not editable and the user cannot submit another "MoveNextColumn" value which would move the program on. The goal here is to minimize any keyboard interaction. Everything should be done with scan guns and barcodes.
Any ideas on how to make the selected cell editable after this code executes?
Any "hey, your design sucks" feedback would be cool too. This is new to me and I'm open to constructive criticism.
I have made some progress with this. The entire grid was left at an uneditable state in the code above. This now leaves focus on the last cell in my column and allows me to submit input with the scan gun.
This seems to work, but I'd still appreciate some feedback on whether there is a better way.
private void dummyCell_MoveToNextColumn(object sender, RoutedEventArgs e) {
e.Handled = true;
// Cell is the model object containing the parsing rules and raising events
var lSender = sender as Cell;
var gridItems = ViewGridReference.Items;
var lastItem = gridItems[gridItems.Count - 1];
if (lSender == lastItem) {
// We are at the bottom of the column
// Move the program on to the next column
CurrentColumn++;
OnPropertyChanged("ItemPositions");
} else {
// Simulate "empty position" input for this cell and all cells down the column
// Cells are validating themselves as the simulation progresses
foreach (Cell item in ViewGridReference.Items) {
item.ActualItemCode = string.Empty;
}
ViewGridReference.SelectedIndex = gridItems.Count - 1;
ViewGridReference.CurrentCell = new DataGridCellInfo(lastItem, ViewGridReference.Columns[0]);
(ViewGridReference.ItemsSource as ListCollectionView).EditItem(ViewGridReference.SelectedItem);
((DataGridCell)ViewGridReference.SelectedItem).Focus();
}
}
Updated 12/2/2010
Hey, there is an important update to this. The first thing to note is that text entry is being done with a scan gun in my scenario, so 'Enter' keys are sent down with each pull of the trigger. It shoots down each character followed by the Enter key all at once.
WPF sees this enter and wants to set the focus to the DataGridCell directly beneath the cell in which the Enter key input was received. The code above sets the focus to the last cell, but then the Enter key event still fires and is handled by DataGrid after this code is run. The effect is that the focus is reset back to the subsequent cell, not the last cell like I want.
So I need to either figure out how to eat the Enter key for just that scan, or I need to break how WPF handles Enter keys. The last line up there actually throws an exception. We are trying to use a Model class (Class.cs) as a DataGridCell, and there is nothing to handle that cast. Because of that, the Focus() method tries to operate on a null object and we get a NullReferenceException. This was really confusing me because Visual Studio 2010 would sometimes break to alert me about this, but sometimes it wouldn't. However, if I run the executable outside of Visual Studio, it works just fine. That's because unhandled, non-fatal exceptions are ignored and the Enter key behavior fails to operate as normal.
So it works, but in a pretty gross way. I either need to figure out how to do one-time handling of the Enter key and override the default WPF handler, or just leave it like it is and grimace.