I am using a ThirdParty keyboard control (DotNetBar from DevComponents, link here) within a WPF desktop application to enter text within a TextBox control. The application is developped on Windows 8 and .NET 4.5.
NOTE: The Windows Tablet Tip was tried, but it has many limitations which makes it difficult to use.
The keyboard being a WindowsForms control, it is put within a WindowsFormsHost.
Since the WindowsForms SendKeys method used by this keyboard will not work well in WPF (as mentionned in many articles on SO), I am programmatically sending the keys to the textbox using the InputManager, like so:
private void _keyboardControl_SendingKey(object sender, KeyboardKeyCancelEventArgs e)
{
// to prevent SendKeys to happen.
e.Cancel = true;
if (string.IsNullOrEmpty(e.Key))
{
return;
}
// A special key is a key like "Enter", "Backspace", "Left arrow", ...
if (IsSpecialKey(e.Key))
{
var keyEventArgs = new KeyEventArgs(
System.Windows.Input.Keyboard.PrimaryDevice,
System.Windows.Input.Keyboard.PrimaryDevice.ActiveSource,
0,
GetKeyValueFromStringCode(e.Key)) { RoutedEvent = Keyboard.KeyDownEvent };
InputManager.Current.ProcessInput(keyEventArgs);
}
// "Normal" keys, like a, b, C, (, 1, ....
else
{
var textCompositionEventArgs = new TextCompositionEventArgs(
System.Windows.Input.Keyboard.PrimaryDevice,
new TextComposition(InputManager.Current,
System.Windows.Input.Keyboard.FocusedElement,
e.Key)) { RoutedEvent = Keyboard.TextInputEvent };
InputManager.Current.ProcessInput(textCompositionEventArgs);
}
}
This effectively puts the right keys into the target WPF textbox which has the focus prior to showing the ThirdParty keyboard.
The textbox Text property has binding to a ViewModel property. The issue is that the updates made to the textbox are not being propagated through the binding when keys are entered programmatically.
If I use my own physical keyboard to type within the same textbox instead, the binding is correctly updated.
Any guidance on this would be greatly appreciated. It took a while to get here, it would be too bad if what I'm trying is not possible. Thanks!
Binding.UpdateSourceTrigger value for Text DP of TextBox by default is LostFocus. So source of binding won't be updated until lost focus fired on textBox.
You need to set it to PropertyChanged, so that whenever Text property changes, it gets updated to source binding.
<TextBox Text="{Binding PropertyName, UpdateSourceTrigger=PropertyChanged}"/>
Related
In windows forms I have a simple TextBox:
TextBox textBox = new TextBox() { Text = "text" };
textBox.Enabled = false;
textBox.MouseEnter += (object sender, EventArgs e) =>
{
MessageBox.Show("MOUSE ENTERED"); // this never fires if the control is disabled.
};
I want to disable the users ability to interact with the control and I want the control to be styled as a disabled control. But I also want to receive MouseEnter,MouseLeave, and Click events from the control so that I can change the background cover of the control on hover and respond to clicks on the control.
But as I have just discovered if you disable a windows forms control it disabled the events as well. I know with some effort I can accomplish the same thing by checking mouse coordinates globally but it would be a lot nicer if I could just have it disabled but still receive events for it. Is that possible?
Enabled doesn't really do anything in Windows Forms itself. It is a property of windows controls in general that a disabled window doesn't receive input messages (such as mouse events and keyboard events). So no, there is no way for you to disable a control and still receive those messages. Windows just don't work that way on Windows. It's not the TextBox control filtering those messages away - they don't come in the first place.
TextBox is a great wrapper around a windows common control. When you do something like tbx.Text = "Hello";, the TextBox just sends a message to that common control, saying "change the text to Hello". If you want to change that, you need to make the control essentially from scratch. You can make some hack that reverts whatever the common control does as response to a mouse event, but these usually don't work very well and tend to break down in unexpected ways.
In practice, what you really want is probably to tweak either the way ReadOnly behaves (e.g. disabling focus as well as making the control read only, but that's again just a dirty hack), or replace the TextBox with a control that can either be a control or a label - allowing you to switch between the two. If you want the text box to stop behaving as a text box, stop it from being a text box. Problem solved :)
I'd still reconsider using ReadOnly, though. Are you sure the user would not want to select text in the text box and copy it somewhere else? Or change the reading order?
I am creating a View Controller that records the Phone Number or Email adress of the user, and I want the placeholder of the textfield to change when they select either the "Phone" button, or the "Email" button.
This is just the button that is supposed to change the placeholder
void PhoneSelectBtn(object sender, EventArgs e)
{
EmailPhoneBox.AttributedPlaceholder = new NSAttributedString("Phone");
}
and every time I run the application, it crashes and this is the error that I get:
Objective-C exception thrown. Name: NSUnknownKeyException Reason: [<UIViewController 0x7f813ec3b870> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key EmailPhoneBox.
Native stack trace:
I have tried other options, such as using a segmented control (obviously it is a little different then setting up a button), and I get the same result. I have changed button methods, classes, and the same result occurs every single time. There are no unnecessary events lingering that aren't attached to anything either. Out of ideas. If one could explain step by step what to do, that would be great. I am sure that it isn't a hard thing to do, but I am just learning, and am finding it hard to find applicable documentation on small things like this. Thanks, Josh
It seems that just like with many other Xamarin features which seem like they should be added but aren't, this one needs a custom renderer.
See this link for more.
Another option is
Set the placeholder string to your Editor's Text in Xaml Then in Code behind file:
InitializeComponent();
var placeholder = myEditor.Text;
myEditor.Focused += (sender, e) =>
{
// Set the editor's text empty on focus, only if the place
// holder is present
if (myEditor.Text.Equals(placeholder))
{
myEditor.Text = string.Empty;
// Here You can change the text color of editor as well
// to active text color
}
};
myEditor.Unfocused += (sender, e) =>
{
// Set the editor's text to place holder on unfocus, only if
// there is no data entered in editor
if (string.IsNullOrEmpty(myEditor.Text.Trim()))
{
myEditor.Text = placeholder;
// Here You can change the text color of editor as well
// to dim text color (Text Hint Color)
}
};
UserControl with buttons (some of them are disabled) is nested inside other UserControl. There are several of such displayed in the window at once.
Now I need to set focus to first enabled button of nested UserControl, while the logic to choose focus will run on the level of window (e.g. when window will enable certain UserControl).
I need to be able to pass that focus request (via properties?) through several ViewModels and finally trigger it in the View of nested UserControl.
Ho can I abstract focus request? E.g. I want to be able to tell "set focus to this high level UserControl" and that should somehow automatically go through nested UserControl and its buttons, because only button is the element what can receive focus.
Pseudo-code:
// in window
UserControlA.Focus();
// should in fact set focus to 4th button of nested user control
UserControlA.UserControlB.ButtonD.Focus();
// because of data templates it is actually more like this
var nested = UserControlA.ContentControl.Content as UserControlB;
var firstEnabledButton = nested.ItemsControl[3] as Button;
firstEnabledButton.SetFocus();
// and because of MVVM it may be as simple as
ViewModelA.IsFocused = true;
// but then A should run
ViewModelB.IsFocused = true;
// and then B should set property of button ViewModel
Buttons.First(o => o.IsEnabled).IsFocused = true.
// and then this has to be somehow used by the view (UserControlB) to set focus...
Problem is not with how to set focus in MVVM, this can be done somehow (with triggers it needs ugly workaround where property is first set to false). My problem is how to pass that request ("and then ..., and then ..., and then..." in example above).
Any ideas?
I am looking for a simple and intuitive xaml solution with the most reusability. I don't want to spam every ViewModel and views with ...IsFocused properties and bindings.
I can use some side effect to my advantage, e.g. consider this behavior
public static bool GetFocusWhenEnabled(DependencyObject obj) => (bool)obj.GetValue(FocusWhenEnabledProperty);
public static void SetFocusWhenEnabled(DependencyObject obj, bool value) => obj.SetValue(FocusWhenEnabledProperty, value);
public static readonly DependencyProperty FocusWhenEnabledProperty =
DependencyProperty.RegisterAttached("FocusWhenEnabled", typeof(bool), typeof(FocusBehavior), new PropertyMetadata(false, (d, e) =>
{
var element = d as UIElement;
if (element == null)
throw new ArgumentException("Only used with UIElement");
if ((bool)e.NewValue)
element.IsEnabledChanged += FocusWhenEnabled_IsEnabledChanged;
else
element.IsEnabledChanged -= FocusWhenEnabled_IsEnabledChanged;
}));
static void FocusWhenEnabled_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var element = (UIElement)sender;
if (element.IsEnabled)
element.Dispatcher.InvokeAsync(() => element.Focus()); // invoke is a must
}
which can be used to automatically focus enabled element. This require some IsEnabled logic in addition and will easily stop working in some complicated scenarios (where enabling should not cause the focusing).
I am thinking if I can add some attached property to pass focus requests all the way through xaml (using only xaml) when attempting to set focus to container, which is not focusable.
I think you should consider using the FrameworkElement.MoveFocus method together with FocusNavigationDirection.Next - this should in general give you the expected result, i.e. give focus to the first encountered control which can receive keyboard focus. In particular that means that non-focusable controls, disabled controls, and controls that cannot receive keyboard focus (such as ItemsControl, UserControl etc.) will be omitted. The only catch here is that the controls will be traversed in tab order, but unless you're messing around with that it should traverse the visual tree in depth-first pre-order manner. So this code:
UserControlA.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
should give focus to UserControlA.UserControlB.ButtonD if it is the first keyboard-focusable and enabled descendant of UserControlA.
In terms of dismissing the necessity to use code-behind what I'd do is the following. First of all I'd drop using view-model properties to control focus. Moving focus seems to me a lot more like request-based concept rather than state-based, so I'd use events (e.g. FocusRequested) instead. To make it reusable I'd create a one-event interface (e.g. IRequestFocus). The final touch would be to create a behavior that would automatically inspect if DataContext of the attached object implements IRequestFocus and call MoveFocus each time the FocusRequested event is raised.
With such setup all you'd need to do is to implement IRequestFocus in ViewModelA, and attach the behavior to UserControlA. Then simply raising the FocusRequested in ViewModelA would result in moving focus to UserControlA.UserControlB.ButtonD.
I have created a custom form control for use in my Kentico bizform using asp.net and I want to change the field caption style of another field in the form depending upon the value in my custom form control field. So, this is what I have done:
protected void ddl_SelectedIndexChanged(object sender, EventArgs e)
{
if(this.Value == "1")
{
FormEngineUserControl formItem = (FormEngineUserControl)this.Form.FieldControls["Other"];
formItem.FieldInfo.CaptionStyle = "font-weight:bold";
}
}
However, the field caption in the form doesn't seem to get bolded. I tried testing if the event even fires and it does. Infact, if I try something like formItem.Text = "Something" then the texbox gets filled with "Something". While debugging I also noticed that the field caption style does get changed to "font-weight: bold" but that doesn't show on the form. So, there is something wrong with the captionstyle property or the way I am using it. How do I get it to work?
(Please note that the field control "Other" is a text box input)
It's probably too late in Page's lifecycle and the control has already been rendered. Try to set the CaptionStyle earlier (e.g. in control's OnLoad or OnInit) then you'll know with certainty.
My scenerio is like this:
At runtime, I bind ToolStripComboBox to array of struct:
cbxTimes.ComboBox.DataSource = PlayTimeLengths;
cbxTimes.ComboBox.DisplayMember = "Description";
cbxTimes.ComboBox.ValueMember = "Minutes";
The DropDownStyle of ToolStripCombobox is set to DropDown.
Everything is working fine, I can select values from the dropdown list and I can write text in the control.
However I wanted to prevent user from pressing some controls and alternate the Text property when some other controls are pressed.
I am trying to accomplish this in KeyPress event:
private void cbxTimes_KeyPress(object sender, KeyPressEventArgs e)
{
var cbxSender = ((ToolStripComboBox)sender).ComboBox;
string S = cbxSender.Text;
//some operations on the S variable
cbxSender.Text = S;
e.Handled = true;
} // breakpoint here shows that cbxSender.Text is not changed to S!
So the Text property has not been changed but I didn't get any exception.
However, if I run the program further (I quit from the debugging) I see that the Text property is changed - to be more specific. I see the text from S inside the control.
Now, imagine that I press any key for the second time, and again I am in the debugger in the same event:
private void cbxTimes_KeyPress(object sender, KeyPressEventArgs e)
{
var cbxSender = ((ToolStripComboBox)sender).ComboBox;
string S = cbxSender.Text; // this time breakpoint is here
//some operations on the S variable
cbxSender.Text = S;
e.Handled = true;
} // breakpoint here shows that cbxSender.Text is not changed to S!
But this time I put breakpoint on the second line and after examining the Text property I see that it still has not changed. Despite the fact that I've altered it on the first time when the event was fired up and the altereted text is visible in the control. But under debugger I see different value, I see value that has been set up at the begining. Value which belongs to the array of structs.
SO what can I do to overcome this problem?
Honestly this is one of the things I hate about Windows Forms databinding. In WPF you would not bind to the objects directly, you'd bind to a "ViewModel" object which encapsulated this view logic you have and bind to it instead.
My workaround to all of this would be to just not use databinding for this case at all and manually populate the items as needed. I can understand why you might be having this problem. If you had updated your underlying bound object's .Text (or whatever causes ToString() to display the value), you would probably see the new value you'd set, but that upsets the semantics of your underlying objects, which is Not A Good Thing.