WPF TextBox AcceptsReturn = True - wpf

In WPF Application I have a textbox.
I set its AcceptsReturn Property to true.
So, I can enter data in multiple lines.
When user press enter in the textbox I want to check :
1) Is the cursor on the last line?
2) If cursor is on the last line then check if thatLine.Text = Nothing?

Something like this?
private void TextBoxOnTextChanged(object sender, TextChangedEventArgs e)
{
TextBox tb = sender as TextBox;
if (tb == null)
{
return;
}
string[] lines = tb.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
if (tb.CaretIndex >= tb.Text.Length - lines.Last().Length)
{
// cursor is on last line
if (string.IsNullOrEmpty(lines.Last()))
{
// cursor is on last line and line is empty
}
}
}
ok is in c# but i don't know the vb syntax..
if you need a translation to vb: http://www.developerfusion.com/tools/convert/csharp-to-vb/ ;-)

Related

WPF - set text to Window as TextBox

i would like catch text in WPF Window. For example, application window will focus and I am going to write without focus in some textbox. My application has input from barcode reader. I want users to be able read a barcode without click to some textbox - for faster work. It is possible? I tried event PreviewKeyDown but application catch only first char. My barcodes are in format #12000012546 and barcode reader emulate numeric keyboard (Shift + num) - for example instead of char # KeyEventArgs return only "System". This is my code:
static string text = string.Empty;
private void MainWindow_OnPreviewKeyDown(object sender, KeyEventArgs e)
{
text += e.Key.ToString();
if (text.Length == 12)
{
MessageBox.Show(text)
text = null;
}
}
Thanks for advice
If your Barcode reader is really doing key presses (Shift + number) to do your # character, then check this out. This was tested on an Spanish Keyboard, so the # character is on my 3 key (Key.D3)
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
var regex = new Regex("(#)|([0-9])");
var keystr = e.Key.ToString();
if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
{
if (regex.Match(keystr).Success)
if (e.Key == Key.D3) textBox1.Text += "#";
}
else if (regex.Match(keystr).Success)
textBox1.Text += keystr.Replace("D","");
}

Why the GetCharIndexFromPosition() doesn't return properly for last character of textbox?

public partial class Form1 : Form
{
TextBox textBox;
public Form1()
{
InitializeComponent();
textBox = new TextBox() { Height = 30, Width = 200, Text = "Syncfusion Software", Font = new Font("Arial", 11) };
textBox.MouseMove += textBox_MouseMove;
this.Controls.Add(textBox);
}
void textBox_MouseMove(object sender, MouseEventArgs e)
{
var selectionStart = textBox.GetCharIndexFromPosition(e.Location);
textBox.SelectionStart = selectionStart;
textBox.SelectionLength = 0;
}
}
Here is my code, this is simple sample that i tried to get clear information about GetCharIndexFromPosition() method of TextBox.
In Mouse move, i get the char index position using the current mouse position of the textbox and set selection start of the textbox based on it. So that if i mouse move, then the selection start or caret position will be set based on the mouse move. But there was an issue with when mouse moved at the end of text, selection start is not set to last. it sets last but before.
For example, if a text box contains text "stack", then if mouse position is after the "k" then caret position should be at the end, but it displayed inbetween "c" and "k". GetCharIndexPosition() doesn't returns value properly for last character. Let me know solution for this
Thanks in Advance.
Regards,
Venkatesan R
This is a known documented behavior. The Remarks section of the GetCharIndexFromPosition method documentation contains the following Important note:
If the specified location is not within the client rectangle of the control, or is beyond the last character in the control, the return value is the index of the last character.
The workaround is to use the reverse method GetPositionFromCharIndex to adjust the returned index.
Something like this
void textBox_MouseMove(object sender, MouseEventArgs e)
{
var charIndex = textBox.GetCharIndexFromPosition(e.Location);
var charPosition = textBox.GetPositionFromCharIndex(charIndex);
if (e.Location.X > charPosition.X) charIndex++;
textBox.Select(charIndex, 0);
}
P.S. As a side note, I have no idea what this method is trying to achieve, but for sure it prevents the standard text selection by mouse behavior.
This ended up really bothering me, so I expanded Ivan Stoev's idea to a rather overengineered method that calculates the pixel width of the last character and divides it by two to accurately emulate the same behaviour as on the other characters.
The method was written for a drag/drop scenario, where the selection is adjusted to the drop position while hovering the mouse over.
// Cached, so it doesn't get recalculated on each moved pixel.
private Char _textBoxLastChar = '\0';
private Int32 _textBoxLastCharHalfWidth = 0;
private void TextBox_DragOver(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent(DataFormats.UnicodeText))
return;
TextBox tb = sender as TextBox;
if (tb == null)
return;
Int32 textLen = tb.Text.Length;
if (textLen > 0 && _textBoxLastChar != tb.Text[textLen - 1])
{
_textBoxLastChar = tb.Text[textLen - 1];
_textBoxLastCharHalfWidth = (Int32)Math.Round(GetStringWidth(_textBoxLastChar.ToString(), tb.Font) / 2);
}
Point localPoint = tb.PointToClient(new Point(e.X, e.Y));
Int32 index = tb.GetCharIndexFromPosition(localPoint);
// fix for fact it returns the last char position when you go outside text bounds.
Int32 charPosition = tb.GetPositionFromCharIndex(index).X;
if (textLen != 0 && index == textLen - 1 && localPoint.X > charPosition + _textBoxLastCharHalfWidth)
index++;
if (!tb.Focused)
tb.Focus();
tb.SelectionStart = index;
tb.SelectionLength = 0;
}
public static Double GetStringWidth(String text, Font f)
{
//create a bmp / graphic to use MeasureString on
Single areaSize = f.Size * 20;
using (Bitmap b = new Bitmap(1, 1))
using (Graphics g = Graphics.FromImage(b))
{
SizeF sizeOfString = g.MeasureString(text, f, new SizeF(areaSize, areaSize), StringFormat.GenericTypographic);
return sizeOfString.Width;
}
}
Of course, if you ever change the font or font size of the text box, you'll have to reset _textBoxLastChar back to '\0'.

Detect when caret position changes in RichTextBox

I am trying to implement very simple text formatting functionality for a RichTextBox in WPF. This just consists of a few bold, italic, etc ToggleButtons just above the RichTextBox. See image below, but ignore the top TextBox - the RichTextBox is the bigger one at the bottom.
Toggling formatting for either a selection or at the caret position (for text that will be typed in) is not a problem, as I'm doing this:
private void BoldButton_Checked(object sender, RoutedEventArgs e)
{
this.SetSelectionBold(true);
}
private void BoldButton_Unchecked(object sender, RoutedEventArgs e)
{
this.SetSelectionBold(false);
}
private void SetSelectionBold(bool isBold)
{
var selection = this.RichText.Selection;
if (selection != null)
{
selection.ApplyPropertyValue(TextElement.FontWeightProperty, isBold ? FontWeights.Bold : FontWeights.Normal);
}
}
However, if the user moves the caret somewhere else (e.g. from bold text to normal text) then I'd like the ToggleButtons to reflect that state, in much the same way as it works in Word. Is it possible to detect when the caret position changes, and take action accordingly?
Hook yourself into SelectionChanged event and get current caret position, and test if the property exists on that selection?
In the event, probably you want something like:
var selection = richTextBox.Selection;
if(selection != null)
{
if(selection.GetPropertyValue(TextElement.FontWeightProperty) == FontWeights.Bold)
// todo; enable your button
}
If that event is not triggered by caret positioning(the document doesn't say anything about that),
you probably need to inherit from RichTextBox and override OnSelectionChanged, after that you need to actually generate your own Caret, eg:
var currentCaretPlusOne = new TextRange(richTextBox.CaretPosition,
richTextBox.CaretPosition+1);
if(currentCaretPlusOne != null)
{
if(currentCaretPlusOne.GetPropertyValue(TextElement.FontWeightProperty)
== FontWeights.Bold)
// todo; enable your button
}

Windows Phone 7 - Deselecting ListBoxItem in nested ListBoxes

I have a ListBox with dates.
Each ListBoxItem (date) have another ListBox with that date's events.
When I select an event it gets highlighted (SelectedIndex/SelectedItem) and I navigate to another Pivot. This works fine.
My problem is that every ListBox has it's own SelectedItem. I want to clear the SelectedItem from each ListBox, but I cannot get it to work!
Here's my try:
//Store a reference to the latest selected ListBox
public ListBox SelectedListBox { get; set; }
private void SelectionChangedHandler(object sender, SelectionChangedEventArgs e)
{
ListBox lstBox = ((ListBox)sender);
//This row breaks the SECOND time!!
var episode = (Episode)lstBox.SelectedItem;
episodeShowName.Text = episode.Show; //Do some code
episodeTitle.Text = episode.Name; //Do some code
episodeNumber.Text = episode.Number; //Do some code
episodeSummary.Text = episode.Summary; //Do some code
resetListBox(lstBox); //Do the reset !
pivot1.SelectedIndex = 1;
}
private void resetListBox(ListBox lstBox)
{
if (SelectedListBox != null)
SelectedListBox.SelectedIndex = -1;
//If I remove this line, the code doesn't break anymore
SelectedListBox = lstBox; //Set the current ListBox as reference
}
var episode is null the second time. How come?
I found the problem!
private void resetListBox(ListBox lstBox)
{
if (SelectedListBox != null)
SelectedListBox.SelectedIndex = -1;
//If I remove this line, the code doesn't break anymore
SelectedListBox = lstBox; //Set the current ListBox as reference
}
When I set the previous selected ListBox's SelectedIndex to -1, the SelectionChangedHandler event gets triggered again (of course) and screws up ! :D
Easy fix:
private void SelectionChangedHandler(object sender, SelectionChangedEventArgs e)
{
ListBox lstBox = ((ListBox)sender);
if (lstBox.SelectedIndex < 0)
return;

RichTextBox and Inserting at Caret Positions

Here is the deal: I have a RichTextBox control and it works fine. The problem is that there is a button "Insert Current DateTime" which adds/injects the current datetime into the RichTextBox. The user can enter the datetime anywhere where the caret is pointing. This involves complicated string manipulation and stuff.
Any ideas how to get the current caret position. Whenever I get RichTextBox.CaretPositon it seems it is pointing to the start of the RichTextBox and not where the actual caret is.
UPDATE 1:
The date time button click code:
private void DateTimeStampButton_Click(object sender, RoutedEventArgs e)
{
//TextRange tr = new TextRange(textBox.Selection.Start, textBox.Selection.End);
var tr = new TextRange(textBox.Document.ContentStart, textBox.Document.ContentEnd);
if(tr.Text.Length == 2)
{
if(tr.Text == "\r\n")
{
tr.Text = tr.Text.TrimStart(new[] { '\r', '\n' });
}
}
textBox.CaretPosition.InsertTextInRun(DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + ": ");
DateTimeStampButton.Focusable = false;
}
private void SharpRichTextBox_LostFocus(object sender, RoutedEventArgs e)
{
SetValue(TextProperty, Text);
var binding = BindingOperations.GetBinding(this, TextProperty);
if (binding == null) return;
if (binding.UpdateSourceTrigger == UpdateSourceTrigger.Default || binding.UpdateSourceTrigger == UpdateSourceTrigger.LostFocus)
{
// if (TextProperty != null) BindingOperations.GetBindingExpression(this, TextProperty).UpdateSource();
}
}
public string Text
{
get
{
var newValue = new TextRange(Document.ContentStart, Document.ContentEnd).Text.RemoveNewLineAndReturn();
return newValue;
}
set
{
if (!String.IsNullOrEmpty(value))
{
SetValue(TextProperty, value.RemoveNewLineAndReturn());
Document.Blocks.Clear();
Document.Blocks.Add(new Paragraph(new Run(value)));
OnPropertyChanged("Text");
}
}
}
UPDATE 2:
Turned out the problem was with the DateTime button being Focusable. I turned it to be not focusable and it worked as expected. When focus was lost on the RichTextBox it was resetting the caret position. It happened only once since in the code the btn_DateTime was dynamically being set as Focusable = false. I placed Focusable = false in XAML and everything worked fine from the start.
I'm using this code to successfully do what you are attempting:
private void insertNowButton_Click(object sender, RoutedEventArgs e)
{
//NOTE: The caret position does not change.
richTextBox1.CaretPosition.InsertTextInRun(DateTime.Now.ToString());
}
EDIT: Addressing Update 1
private void DateTimeStampButton_Click(object sender, RoutedEventArgs e)
{
var tr = new TextRange(textBox.Document.ContentStart, textBox.Document.ContentEnd);
if (tr.Text.Length == 2)
{
if (tr.Text == "\r\n")
{
tr.Text = tr.Text.TrimStart(new[] { '\r', '\n' });
}
}
/* Changing the text is the only way I can get the date to insert at the beginning */
tr.Text = "I need a beer at ";
textBox.CaretPosition.InsertTextInRun(DateTime.Now.ToString());
}
It looks like SetValue is changing the text so based on my test that actually changing the text resets the caret, I would agree with you that SetValue is causing the problem...
I tried this solution with WPFToolkit.Extended RichTextBox and it didn't work for me.
However I found another one and thought it would be good to post it in here in case someone else could use it.
My problem was also that the after I clicked a button that is supposed to append text at the caret location, it instead adds it at the beginning of the RichTextBox.
So The solution I found is similar to the one in here -
RichTextBox CaretPosition physical location
Instead of using CaretPosition I used RichTextBox.Selection.Start.InsertTextInRun("SomeText").
It considered the selection's start as the caret position even though no selection was made and therefore was good enough for me.
I hope someone will find this useful :)
This worked for me:
private void InsertText(String text, RichTextBox rtb)
{
rtb.CaretPosition = rtb.CaretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);
rtb.CaretPosition.InsertTextInRun(text);
}
I found the code here:
How do I move the caret a certain number of positions in a WPF RichTextBox?

Resources