How to access focused element programmatically WPF C# - c#

Wondering how should I access elements property which does have the focus. I have found the following code to find the focused element :
var focusedControl = FocusManager.GetFocusedElement(this);
This seems to work well, in debug "focusedcontrol" is the right element however I don't know how to access it programmatically. Something like :
focusedControl.Text = "txt";
The reason why I wanna do this - in the same window as the TextBoxes I have several Buttons which form a keypad. After hitting the Button (Focusable = False) I want to get reference to focused TextBox and insert the corresponding digit in TextBox.Text.
Thanks
Lukas

The GetFocusedElement() method returns IInputElement, not a TextBox.
Since FrameworkElement implements IInputElement, and Control (and TextBox) are derived from FrameworkElement, you can just cast the result to a TextBox yourself:
var focusedControl = FocusManager.GetFocusedElement(this);
var tBox = focusedControl as TextBox;
if (tBox != null)
tBox.Text = "txt";

Related

C# Window From Autoselects Text

I have not dealt with WinForms for a long time.
Now I'm stuck with something trivial but cannot figure it out.
I have a Winform and when a Timer Tick happens I want to show a message in a new form message box:
frmMessage frmM = new frmMessage();
frmM.txtMessage.Text = ConfigurationSettings.AppSettings["Message"];
frmM.Show();
It works but the text in the textbox shows as selected(with a blue background).
I tried
txtMessage.SelectionLength = 0;
Did not help.
Also tried to set focus to a different control, did not help either.
for now, as a workaround, I will use a Label.
This is a consequence of the way TextBox Class is implemented. If a selection is not specifically set, all text will be selected when the control gets focus.
From TextBox.OnGotFocus:
Protected override void OnGotFocus(EventArgs e) {
base.OnGotFocus(e);
If (!selectionSet) {
// We get one shot at selecting when we first get focus. If we don't
// do it, we still want to act Like the selection was set.
selectionSet = true;
// If the user didn't provide a selection, force one in.
If (SelectionLength == 0 && Control.MouseButtons == MouseButtons.None) {
SelectAll();
}
}
Additionally due to the way the SelectionLength Property is implemented, setting that property to zero does not set the selectionSet` flag as it is already zero.
Instead, set the TextBox.SelectionStart Property immediately after setting the text as this will set that flag.
txtMessage.SelectionStart = 0;
However, your work-a-round of using a Label to display a message is much more appropriate than using an input control.
This is not the best answer but it works. You can try this
frmMessage frmM = new frmMessage();
frmM.txtMessage.Text = "";
frmM.txtMessage.AppendText(ConfigurationSettings.AppSettings["Message"]);
frmM.Show();

C# - Determine the focused RichTextBox in a Split Container of the Active MDI Child

I have a Form (Form2) that contains a Split Container, the RichTextBox is on the Left Panel and the WebBroswer is on the Right Panel.
I am showing the Form as a child of a MDIParent Form 1. What I wanted to do is copy the selected text of the active MDI Child. However due to the RichTextBox being inside a Split Container, I cannot target the RichTextBox and it returns nothing.
Form activeChild = this.ActiveMdiChild;
if (activeChild != null)
{
try
{
RichTextBox theBox = (RichTextBox)activeChild.ActiveControl;
if (theBox != null)
{
// Put the selected text on the Clipboard.
Clipboard.SetDataObject(theBox.SelectedText);
}
}
catch
{
MessageBox.Show("Unable to Copy to Clipboard");
}
}
The result is, the Message Box shows so that means I wasn't able to target the RTB properly. How can I get the current active RTB?
Since the ActiveControl being returned from the child form is the SplitContainer control, then we will need to go one level deeper and get the ActiveControl from that container in order to finally get the RichTextBox control. Note that we have to check for the object types and null along the way, in case a different control may be selected.
Here's one way to get the rich text box text (or an empty string if it's not selected):
var childSplitContainer = this.ActiveMdiChild?.ActiveControl is SplitContainer
? (SplitContainer)activeChildForm.ActiveControl
: null;
var splitContainerRTB = childSplitContainer?.ActiveControl is RichTextBox
? (RichTextBox)childSplitContainer.ActiveControl
: null;
Clipboard.SetDataObject(splitContainerRTB?.Text ?? string.Empty);

How do you get the actual height of the DropDownList attached to a ComboBox in WPF?

I want to get the actual height of the ComboBox plus the height of its DropDown when it is opened. However there does not appear to be an accessible property on the ComboBox to give this.
The ComboBox.ActualHeight property only gives the height of the base ComboBox, not its dropdown.
This one is kind of infuriating as I think I can see the value set on a property in the debugger, but the property is not accessible in code for some reason - ItemsHost.ActualHeight.
See below:
However, ItemsHost which appears to have the height of the dropdown is not accessible from code!
The property is not accessible because it is not defined as public. You could get its value using reflection:
Get property value from string using reflection in C#
You shouldn't really do this though as the property is non-public for a reason.
Instead, you could get a reference to the Popup element of the ComboBox and check the ActualHeight property of its Child, e.g.:
ComboBox cmb = sender as ComboBox;
double heightOfComboBox = cmb.ActualHeight;
double heightOfPopup = 0.0;
Popup popup = cmb.Template.FindName("PART_Popup", cmb) as Popup;
if (popup != null)
{
FrameworkElement fe = popup.Child as FrameworkElement;
if (fe != null)
heightOfPopup = fe.ActualHeight;
}
double totalHeight = heightOfComboBox + heightOfPopup;

Accessing variables dynamically in C#

I have tons of Buttons named like this x0y1
How do I access the variable name dynamically so I could loop all names by xiy1 or so.
in PHP it would be like ${"myString" . $randomvar}
I can't use a list or array because the the button already exist defined through the xaml
You can use:
var textbox =
this.Controls.OfType<TextBox>().Where(txb => txb.Name == "myString").FirstOrDefault();
This assumes you are in the context of your form (this.Controls).
And of course, don't forget to add using System.Linq;...
You can get all the textbox using this method
void AllTextBox(System.Windows.Forms.Control.ControlCollection ctrls)
{
foreach (Control ctrl in ctrls)
{
if (ctrl is TextBox)
{
if (ctrl.Name == "textBox1")
{
// do your stuf with textbox
}
}
}
}
You can create function that return control by name :
Control GetControlByName(string Name)
{
foreach(Control control in this.Controls)
if(c.Name == Name) return control ;
return null;
}
or Function with a specific control like that :
Button GetButtonByName(string Name)
{
foreach (Control c in this.Controls.OfType<Button>())
if (c.Name == Name) return c;
return null;
}
For wpf project...
Let's say you have a grid named MyGrid and there's lot of buttons on it.
You want to refer to the button named x0y1:
var btn = MyGrid.Children.OfType<Button>().Where(x=>x.Name=="x0y1");
Note: above code should work for flat structure (one level deep only).
You can achieve the same by using code provided in this thread: How can I find WPF controls by name or type?
Just call FindName("elementName"). FindName searches through all child elements of a FrameworkElement. To access any button by its name as string in a window, call the FindName() method of the window !
If your code is in a class inheriting from Window, just use:
Button button = (Button)FindName("xiy1");
If you write the code in a class not inheriting from Window but FrameworkElement, which is unlikely, use:
Window window = Window.GetWindow(this);
Button button = (Button)window.FindName("xiy1");
Check the MSDN documentation about Namescopes for more information about limitations.

casting new System.Windows.Forms.Control object to System.Windows.Forms.Textbox

i get an InvalidArgumentException while casting Control to System.Windows.Forms.Textbox:
Unable to cast object of type 'System.Windows.Forms.Control' to type 'System.Windows.Forms.TextBox'.
System.Windows.Forms.Control control = new System.Windows.Forms.Control();
control.Width = currentField.Width;
//here comes the error
((System.Windows.Forms.TextBox)control).Text = currentField.Name;
I am doing this, because I have different Controls (Textbox, MaskedTextbox, Datetimepicker...), which will dynamically be added to a panel and have the same basic properties (Size, Location... -> Control)
Why isn't the cast possible?
The cast fails because control is not a TextBox. You can treat a TextBox as a control (higher up the type hierarchy) but not any Control as a TextBox. For setting common properties you can just treat everything as Control and set them whereas you have to create the actual controls you want to use beforehand:
TextBox tb = new TextBox();
tb.Text = currentField.Name;
Control c = (Control)tb; // this works because every TextBox is also a Control
// but not every Control is a TextBox, especially not
// if you *explicitly* make it *not* a TextBox
c.Width = currentField.Width;
You control is an object of Control class which is parent class. May be more controls are inheriting from parent.
Hence a child can be cast as parent but not vice versa.
Instead use this
if (control is System.Windows.Forms.TextBox)
(control as System.Windows.Forms.TextBox).Text = currentField.Name;
or
Make a TextBox object. That one will always be a TextBox and you do not need checking/casting for it.
Joey is right:
your control isn't a textbox! You can test types using:
System.Windows.Forms.Control control = new System.Windows.Forms.Control();
control.Width = currentField.Width;
if (control is TextBox)
{
//here comes the error
((System.Windows.Forms.TextBox)control).Text = currentField.Name;
}
All your controls inherit from System.Windows.Forms.Control. However, a TextBox is not the same as DateTimePicker, for example, so you cannot cast them to each other, only to the parent types. This makes sense as each control is specialized for doing certain tasks.
Given that you have controls of different types, you may wish to test the type first:
if(control is System.Windows.Forms.TextBox)
{
((System.Windows.Forms.TextBox)control).Text = currentField.Name;
}
You can also speculatively cast to the type using the 'as' keyword:
TextBox isThisReallyATextBox = control as TextBox;
if(isThisReallATextBox != null)
{
//it is really a textbox!
}

Categories