I have a usercontrol loaded inside a canvas; this usercontrol on default have visibility collapsed. When a specific textbox of my window is focused the usercontrol become visible.
When usercontrol become visible I want set focus to another textbox inside usercontrol.
I try to do that:
private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.Visibility == Visibility.Visible)
{
FocusManager.SetFocusedElement(this, TextBlockInput);
}
}
It seems work but there is a problem: the textbox seems focused but the cursor into textbox don't blink and I can't type chars for input.
I would that after focus the textbox is ready for input. How can I do?
Well, I solve in this way:
private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.Visibility == Visibility.Visible)
{
this.Dispatcher.BeginInvoke((Action)delegate
{
Keyboard.Focus(TextBlockInput);
}, DispatcherPriority.Render);
}
}
I think that the problem was tha focus call into IsVisibleChanged event "scope"...right?
try
Keyboard.Focus(TextBlockInput);
see here for more details
Another possible workaround is instead of Visibility property use Opacity. In this case calling Focus() actually sets focus.
Related
Does anyone know how to dynamically set the ElementName for textblock.text binding?
I have two Datagrids that have the same information but the second DataGrid is just a filter of the same datasource, but what I want is to bind text of a textblock to the selected item depending if the item was clicked in the main datagrid or the secondary datagrid.
I have the below code to bind the textblock to one datagrid but I would also like the same to happen if the user clicked an item in the secondDataGrid.
Is this possible?
<TextBlock Margin="29,0" Text="{Binding SelectedItem.Name, ElementName=MainDataGrid}"
It is possible, though I don't think this is the proper solution.
You can handle one of the DataGrids' events in the code-behind, where in the handler you can write the following code:
BindingOperations.SetBinding(textBlock, TextBlock.TextProperty,
new Binding("SelectedItem.Name")
{
ElementName = "DataGrid1"
});
Basically you reset the Binding on the TextBlock's Text property with this code, where:
textBlock is the name of your TextBlock;
with TextBlock.TextProperty you define that you want to work with the Text property on the TextBlock;
The third paramter is the new Binding itself. The constructor takes the Path of the Binding and then in the "body" I set the ElementName.
If DataGrid1 fires the event you set the ElementName to that DataGrid's name, if DataGrid2 fires the event then you set the ElementName to the second DataGrid's name.
SelectionChanged can be a good event to handle on both DataGrid, but if you want the TextBlock to update when you selected and element in the first then select another one in the second and then click back to the first element to update then you need to handle the GotFocus event as well.
Play a little bit with it and you will see what I mean.
My working example:
private void SetBindingOnTextBlock(string elementName)
{
BindingOperations.SetBinding(textBlock, TextBlock.TextProperty, new Binding("SelectedItem.Name")
{
ElementName = elementName
});
}
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SetBindingOnTextBlock("DataGrid1");
}
private void DataGrid_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
SetBindingOnTextBlock("DataGrid2");
}
private void DataGrid1_GotFocus(object sender, RoutedEventArgs e)
{
SetBindingOnTextBlock("DataGrid1");
}
private void DataGrid2_GotFocus(object sender, RoutedEventArgs e)
{
SetBindingOnTextBlock("DataGrid2");
}
UPDATE 1:
Set
IsSynchronizedWithCurrentItem="True"
on the DataGrids and it may solve your problem if ItemsSources are the same. (Not sure if this is what #dkozl meant) Originally I assumed that they are different.
I have a WPF user control with multiple child controls and I am focusing DataGrid and TextBox programmatically with the following code:
searchTextBox.Focus();
and
productGrid.Focus();
productGrid.Focus(dataGrid); //tried this but it does not help
searchTextBox focuses normally but dataGrid does not (keyboard focus stays on some other control). Below I provided full source code that hides searchTextBox and moves focus to productGrid (searchPanel is a parent Grid of searchTextBox):
private void Execute_CancelCommand(object sender, ExecutedRoutedEventArgs e)
{
if (searchPanel.Visibility == Visibility.Visible)
{
searchPanel.Visibility = Visibility.Collapsed;
searchTextBox.Clear();
searchTextBox.Background = Brushes.White;
//the focus stays on the splitter for some reason
productGrid.Focus();
Keyboard.Focus(productGrid);
}
}
what can cause this situation?
Thnx.
It seems that productGrid.Focusable property is set to "false". You should just set it to "True" and your code should work correctly and there will be no need in calling Keyboard.Focus() method.
I created a WPF UserControl, that handles all GotFocus/LostFocus events of its child controls. I call the OnGotFocus/OnLostFocus of the UserControl, but the IsFocused property of the UserControl will not set:
void MyUserControl_Initialized(object sender, EventArgs e)
{
foreach (UIElement control in (Content as Panel).Children)
{
control.LostFocus += control_LostFocus;
control.GotFocus += control_GotFocus;
}
}
void control_GotFocus(object sender, RoutedEventArgs e)
{
if (!IsFocused)
{
e.Handled = false;
OnGotFocus(e);
}
}
void control_LostFocus(object sender, RoutedEventArgs e)
{
bool hasAnythingTheFocus = false;
foreach (UIElement control in (Content as Panel).Children)
{
if (control.IsFocused)
{
hasAnythingTheFocus = true;
}
}
if (!hasAnythingTheFocus)
{
OnLostFocus(e);
}
}
How can I set it?
Instead of the IsFocused you can use IsKeyboardFocusWithin
use the event UIElement.IsKeyboardFocusWithinChanged and it should worked perfectly.
The GotFocus method will be called when the relevant control receives logical focus... from the UIElement.GotFocus Event page on MSDN:
Logical focus differs from keyboard focus if focus is deliberately forced by using a method call but the previous keyboard focus exists in a different scope. In this scenario, keyboard focus remains where it is and the element where a Focus method is called still gets logical focus.
A more precise interpretation of this event is that it is raised when the value of the IsFocused property of an element in the route is changed from false to true.
Because this event uses bubbling routing, the element that receives focus might be a child element instead of the element where the event handler is actually attached. Check the Source in the event data to determine the actual element that gained focus.
it will get focus when the user clicks on the relevant control in the UI and/or when you call control.Focus() in your code. The IsFocused is readonly and cannot be set.
I have 2 controls on a form. One numericUpDown (from the Silverlight Toolkit) and a simple Rectangle.
On the MouseLeftButtonDown of the Rectangle I popup a MessageBox with the numericUpDown value.
If I use the arrows to change the value of the numericUpDown, everyting is fine. But if I edit the value manually (with the keyboard) and immediately click on the Rectangle it shows the previous value of the numericUpDown. If I click a sencond time on the rectangle it will show the new value.
The numericUpDown.ValueChanged event is raised after the Rectangle.MouseLeftButtonDown event.
Is that a Silverlight bug? Anybody knows a workaround for that?
(btw I cannot change my Rectangle controls or events)
As workaround I propose you to create your own control like:
public class MyNumericUpDown : NumericUpDown
{
private TextBox _textBox;
public void Sync()
{
ApplyValue(_textBox.Text);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_textBox = (TextBox)GetTemplateChild("Text");
}
}
Now you can use method Sync to syncronize display text with control Value property. You can call method from XAML declaratively or in code behind. In your case:
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
myNumericUpDown.Sync();
MessageBox.Show(myNumericUpDown.Value.ToString());
}
I have combobox in WPF application that when the user clicks on it, it selects all the text. How can I change the behavior of this to when the user clicks it just set the typing cursor like a normal textbox?
Try
<ComboBox IsEditable="True" />
According to Reflector, the ComboBox code contains this:
private static void OnGotFocus(object sender, RoutedEventArgs e)
{
ComboBox box = (ComboBox) sender;
if ((!e.Handled && box.IsEditable) && (box.EditableTextBoxSite != null))
{
if (e.OriginalSource == box)
{
box.EditableTextBoxSite.Focus();
e.Handled = true;
}
else if (e.OriginalSource == box.EditableTextBoxSite)
{
box.EditableTextBoxSite.SelectAll(); // <==
}
}
}
This method is registered for the GotFocus event in the static constructor using the EventManager:
EventManager.RegisterClassHandler(typeof(ComboBox), UIElement.GotFocusEvent, new RoutedEventHandler(ComboBox.OnGotFocus));
So, I think you can only change that behavior by deriving a custom control from ComboBox and override this event registration by your own method which replaces the call to SelectAll() with another method which sets the caret to the correct position. However, I do not know how to set the caret to the click position. You might have to use Reflector on the TextBox to find that...
Seems that I had to solve similar issue.
It's quite tricky, but the way I solved is to set IsEditable to false/true from code, at the same time I set the focus on TextBox.
Not the pretties way but does the job.