Add character counter to MemoExEdit control - c#

I am trying to make a character counter, 40/200...41/200 and so on. Now for a textbox control I am hooking into the KeyUp Event with something like this...
public static void GetRemainingChars(MyTextBox txt, LabelControl lbl)
{
var maxChars = txt.Properties.MaxLength;
lbl.Text = txt.Text.Length + "/" + maxChars;
}
Unfortunately the MemoExEdit control has a popup window you type the text into and that seems to be hidden. I tried the KeyUp, EditValueChanging, TextChanged, and they all do the same thing. They don't fire till the user closes the popup. I am guessing that it is a composite control that transfers the editvalue when it closes.
Any ideas on how I can get at the popups events? Is there a different way to do this?

Just because I couldn't find this anywhere else I will post my solution for other's benefit.
Subscribe to the Popup Event of the MemoExEdit control, then inside that subscribe to the EditValueChanging Event. That is where you can hook in. See below for MY working version. Tweaks may be needed for yourself. Also, the Popup Event is created in my Designer.cs file.
private void memContactWith_Properties_Popup(object sender, EventArgs e)
{
MemoExPopupForm popupForm = (sender as DevExpress.Utils.Win.IPopupControl).PopupWindow as MemoExPopupForm;
MemoEdit me = popupForm.Controls[2] as MemoEdit;
me.EditValueChanging += new DevExpress.XtraEditors.Controls.ChangingEventHandler(me_EditValueChanging);
}
void me_EditValueChanging(object sender, DevExpress.XtraEditors.Controls.ChangingEventArgs e)
{
var memo = (sender as MemoEdit);
var maxChars = memo.Properties.MaxLength;
lblContactWithCharCount.Text = memo.Text.Length + "/" + maxChars;
}

Related

Grabbing the textbox label

Hello im making my first project with about 10 different textboxes where the user puts data in. when he/she clicks the the textbox the textbox text clears and a virtual numpad form pops up and when he leaves the textbox the numpad "hides".
right now (or i would) i have 2 events for every textbox, a click event and a leave event,
private void sheetWidthBox_Enter(object sender, EventArgs e)
{
vnumPadForm.Location = PointToScreen(new Point(sheetWidthBox.Right, sheetWidthBox.Top));
vnumPadForm.Show();
}
Im sure there is a way of dynamically coding that in one event and just grabbing the label name. i have played around with it a bit on my numpad like this and it works good;
private void button_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
string num = b.Text;
SendKeys.SendWait(num);
}
Like that but instead i want to get the label name
right now (or i would) i have 2 events for every textbox, a click event and a leave event,
it works but very inefficient.
Change the name of the handler to something generic like "anyBox_Enter()", and update to the code below:
TextBox curTextBox = null;
private void anyBox_Enter(object sender, EventArgs e)
{
curTextBox = sender as TextBox;
vnumPadForm.Location = PointToScreen(new Point(curTextBox.Right, curTextBox.Top));
vnumPadForm.Show();
}
Note that I added a class level variable called "curTextBox" that gets set from the generic handler! This will track whatever TextBox was entered last.
Now, one by one, select each TextBox on your Form that you want to wire up to this common handler. After selecting each one, in the Properties Pane, click on the "Lightning Bolt" Icon to switch to the events for that control if they are not already showing. Find the "Enter" entry and change the dropdown to the right so that it says "anyBox_Enter".
Then in your button click handlers you can use the "curTextBox" variable to know where to send the key:
private void button_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
string num = b.Text;
if (curTextBox != null) {
curTextBox.Text = num; // or possibly APPEND this to the TB?
}
}

DevExpress select all when clicked on GridView cell (TextEdit)

I need to make it so when the user clicks on a cell with TextEdit in a grid view, it will select all in the textedit. I tried many many ways i could find in the internet, but none of them work well.
"EditorShowMode = MouseUp" way breaks everything, for example when you click on a cell that has checkedit; it selects the cell, then you need o click again to actually click on the CheckEdit.
"Use EditorShowMode = MouseUp and manually handle other things on MouseDown" is just ew. Won't work fine for all types of controls.
"Change selection length etc. on ShownEditor event" way doesn't work too, actually it selects the text when clicked, but it doesn't override the default function so the selection instantly changes. Also tried the SelectAll method but it had some problems that i dont remember (probably didnt work at all).
I have really tried many things, but couldn't find a totally fine way. Please tell me if you can get a working way without breaking other types of controls in the grid.
Answered by Pavel on DevExpress Support (works great):
The easiest way to achieve this is to use the GridView.ShownEditor event to subscribe to the active editor's MouseUp event. Then, select all text in the MouseUp event handler and detach this handler to avoid subsequent text selection.
private void GridView_ShownEditor(object sender, EventArgs e)
{
GridView view = sender as GridView;
if (view.ActiveEditor is TextEdit)
view.ActiveEditor.MouseUp += ActiveEditor_MouseUp;
}
private void ActiveEditor_MouseUp(object sender, MouseEventArgs e)
{
BaseEdit edit = sender as BaseEdit;
edit.MouseUp -= ActiveEditor_MouseUp;
edit.SelectAll();
}
You could use GridView CustomRowCellEdit event and set an event of text editor such as Mouse Up. Setting the RepositoryItemTextEdit MouseUp event can be set as in the example.
Example:
private void gridView1_CustomRowCellEdit(object sender, CustomRowCellEditEventArgs e)
{
if (e.RepositoryItem is DevExpress.XtraEditors.Repository.RepositoryItemTextEdit)
{
DevExpress.XtraEditors.Repository.RepositoryItemTextEdit rep = new DevExpress.XtraEditors.Repository.RepositoryItemTextEdit();
rep.ReadOnly = false;
rep.MouseUp += rep_MouseUp;
e.RepositoryItem = rep;
}
}
void rep_MouseUp(object sender, MouseEventArgs e)
{
DevExpress.XtraEditors.TextEdit te = sender as DevExpress.XtraEditors.TextEdit;
te.SelectAll();
}
You should handle Enter event for TextEdit
private void myRepositoryItemTextEdit_Enter(object sender, EventArgs e)
{
var editor = (DevExpress.XtraEditors.TextEdit)sender;
BeginInvoke(new MethodInvoker(() =>
{
editor.SelectionStart = 0;
editor.SelectionLength = editor.Text.Length;
}
}

Event that triggers BEFORE my form loses focus

I need to be alerted before my entire form loses focus. The Deactivate event only triggers after it loses focus. LostFocus and Leave are only for controls.
I have also tried overriding WndProc but this only triggers after the message has been processed.
overriding PreProcessMessage only can be used for keyboard stuff, not form deactivation.
Dodgy Method
Even though this is a quick and hacky way of doing it, changing Input Language is unnatural to start with..
private void Form1_Deactivate(object sender, EventArgs e)
{
((Form)sender).Activate();
System.Diagnostics.Debug.WriteLine(this.ActiveControl.Name);
//Change Input Language here..
//Alt TAB to set focus to the application selected 5 milliseconds ago
SendKeys.SendWait("%{TAB");
}
Correct and orthadox method
How to monitor focus changes? and C#: Detecting which application has focus
Its using the Automation framework, Add references to UIAutomationClient and UIAutomationTypes and use Automation.AddAutomationFocusChangedEventHandler, e.g.:
public class FocusMonitor
{
public FocusMonitor()
{
AutomationFocusChangedEventHandler focusHandler = OnFocusChanged;
Automation.AddAutomationFocusChangedEventHandler(focusHandler);
}
private void OnFocusChanged(object sender, AutomationFocusChangedEventArgs e)
{
AutomationElement focusedElement = sender as AutomationElement;
if (focusedElement != null)
{
int processId = focusedElement.Current.ProcessId;
using (Process process = Process.GetProcessById(processId))
{
Debug.WriteLine(process.ProcessName);
}
}
}
}
Got it, this hack works perfectly.
private void MyForm_Deactivate(object sender, EventArgs e)
{
Thread.Sleep(200); //delay to allow external tab time to open
Form f1 = new Form(); //create a new form that will take focus, switch input, then terminate itself
f1.Shown += new EventHandler((s, e1) => { f1.Activate(); InputLanguage.CurrentInputLanguage = InputLanguage.DefaultInputLanguage; f1.Close(); });
f1.Show();
}
EDIT: upon further testing I have found this to be equally unreliable. It doesn't seem like there is a good way to do this at all.
For now I am tracking the mouse and keyboard to detect when the user is about to deactivate it. Obviously a mouse and keyboard hook is a horrible solution but its the only reliable solution so far.

lost focus and got focus events of a text box

1.How to give both lostfocus event and gotfocus event for a textbox at the same time?
2.That is, i have to append % to a text box, so i will use lost focus event.
3.But whenever the user again goes to d text box i need to call got focus event.
4.So is this possible to call both the events of a text box at the same time??
this is for lostfocus event:
protected void lostfocus(object sender, EventArgs e)
{
if (txtMarks.Text != "")
{
txtMarks.Text += "%";
ddlGrade.Focus();
}
else
{
txtMarks.Text = "";
ddlGrade.Focus();
}
}
this is for gotfocus event:
protected void lostfocus(object sender, EventArgs e)
{
if (txtMarks.Text.contains("%"))
{
txtMarks.Text = "";
ddlGrade.Focus();
}
}
If you want to append "%" on lost focus and clear the value when you got focus, maybe you should consider adding a separate label on the right of the textbox with the content "%". In this way the user will know that this is a percentage textbox. What you want to do does not look very nice.
Instead of
if (txtMarks.Text != "")
use this
if(!string.IsNullOrEmpty(txtMarks.Text))

Hooking up generic event handlers to multiple controls of the same type

I have a WinForms app that contains many NumericUpDown controls. In a nutshell, if my users enter a value into the control and then delete the text, I want to restore it (the text) when the control loses focus. So I decided that I'd check .Text when the control loses focus and if it's empty, I set .Text = .Value.ToString().
I'm doing this in the Leave event handler and it works just fine. But as I said, I have many of these controls (18, to be exact). I don't like creating 18 Leave event handlers that all do the same thing so I created a generic one like this:
private void numericUpDown_GenericLeave(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(((NumericUpDown)sender).Text))
((NumericUpDown)sender).Text = ((NumericUpDown)sender).Value.ToString();
}
I started to hook up all of the controls to this generic event handler but I quickly got tired of doing this:
numericUpDown1.Leave += numericUpDown_GenericLeave;
numericUpDown2.Leave += numericUpDown_GenericLeave;
numericUpDown3.Leave += numericUpDown_GenericLeave;
...
numericUpDown18.Leave += numericUpDown_GenericLeave;
So I thought I'd create a function that would return a list of all the controls of a specified type and then loop through that list and hookup the event handlers. That function looks like this:
public static List<Control> GetControlsOfSpecificType(Control container, Type type)
{
var controls = new List<Control>();
foreach (Control ctrl in container.Controls)
{
if (ctrl.GetType() == type)
controls.Add(ctrl);
controls.AddRange(GetControlsOfSpecificType(ctrl, type));
}
return controls;
}
I call the function like this:
var listOfControls = GetControlsOfSpecificType(this, typeof(NumericUpDown));
foreach (var numericUpDownControl in listOfControls)
{
numericUpDownControl.Leave += numericUpDown_GenericLeave;
}
When I run my app, however, I don't see the expected behavior that occurs when I manually hookup each control to the generic event handler. This code is currently in the constructor of my form and I've tried calling it before as well as after the call to InitializeComponent() but neither one seems to be working. I get no error of any kind, I just don't see the behavior that I was expecting. I have a breakpoint set inside the generic event handler but the debugger never breaks so it seems like the event handler isn't being hooked up correctly. Does anyone know why this might be or how I can troubleshoot it further? Thanks!
EDIT
I just realized that the call to:
var listOfControls = GetControlsOfSpecificType(this, typeof(NumericUpDown));
was happening before the call to InitializeComponent() so of course the list of controls being returned was empty. DOH! Thanks for all the replys. I apologize for wasting everyones time. :-(
You're passing this to your method, which is presumably a reference to your form. Your method will only catch the controls that are placed directly on your form. Any NumericUpDown controls that are not directly on the form (i.e. they're sitting on a panel or something) will be missed.
Why not create a user control that has a NumericUpDown control in it.
Then handle this is in the user control events.
This worked for me:
private decimal _previous = 0;
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
if (((NumericUpDown)sender).Text.Length > 0)
{
_previous = this.numericUpDown1.Value;
}
}
private void UserControl1_Leave(object sender, EventArgs e)
{
if (this.numericUpDown1.Text == "")
{
this.numericUpDown1.Value = _previous;
this.numericUpDown1.Text = System.Convert.ToString(_previous);
}
}
Just note that the Leave event is on the user control not on the updown control itself.
Question answered. See Edit above. Thanks to bsegraves for pointing me in the right direction.

Categories