Simplest application possible:
<Page
x:Class="TestApp.MainPage"
...>
<Grid>
<TextBox />
</Grid>
</Page>
Question: is there any elegant way to prevent the cursor (focus) from being set in the TextBox on application start up?
To expand: My real issue is that I have a PopUp that is opened when the TextBox receives focus. If I click on an element in my PopUp it should close, but since the TextBox is the first focusable element in my page it automatically receives focus and thus the PopUp immediately opens again. The core of the problem I think is represented by the example above.
Focus is managed by various properties like IsTabStop, TabIndex, IsHitTestVisible, and the FocusManager class. There is built-in functionality to focus the first focusable element once the window is activated, and this behavior is generally not customizable.
We could designate a different element to be focused instead of the textbox like, say, the page itself:
<Page IsTabStop="True">
<TextBox/>
</Page>
This works in that the page gets initial focus instead of the textbox, but now the page participates in tabbing behavior, which is slightly undesirable.
Typically the framework will set focus to the RootScrollViewer when you click out of a focused control, even though the RootScrollViewer isn't a tab stop (so it can't receive focus by tabbing). If we can focus the RootScrollViewer upon page load, the framework will detect that something has focus and won't attempt to focus the first element.
<Page Loaded="onPageLoaded">
<TextBox/>
</Page>
private ScrollViewer getRootScrollViewer()
{
DependencyObject el = this;
while (el != null && !(el is ScrollViewer))
{
el = VisualTreeHelper.GetParent(el);
}
return (ScrollViewer)el;
}
private void onPageLoaded(object sender, RoutedEventArgs e)
{
getRootScrollViewer().Focus(FocusState.Programmatic);
}
This is the most "elegant" way that I know to prevent the textbox from getting focused automatically.
Related
I'm relatively new to WPF and I am struggling to manage the focus of an element at runtime.
I have a simple user control with a TextBox inside
<UserControl [...]
IsVisibleChanged="UserControl_IsVisibleChanged">
[...]
<TextBox x:Name="myTextBox" [...] />
</UserControl>
That I added on my WPF window
<ctrl:MyPanel
x:Name="myPanel"
Visibility="{Binding MyBooleanProperty}"
Panel.ZIndex="999" />
MyBooleanProperty is changing at runtime under some logic and the panel is showing up accordingly.
I need to have keyboard focus on myTextBox everytime myPanel becomes visible so user can enter data without using mouse, tab key or anything else.
Here's the logic on the event handler of IsVisibleChanged
private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.Visibility == Visibility.Visible)
{
myTextBox.Focus();
myTextBox.SelectAll();
}
}
This works, but if I click any button on the window before myPanel becomes visible then I cannot set focus in myTextBox.
I've tried many things, for example setting
Focusable="False"
on the buttons with no luck.
Thanks in advance for your help!
After a little more searching I found a workaround based on this answer by Rachel:
Dispatcher.BeginInvoke(DispatcherPriority.Input,
new Action(delegate () {
myTextBox.Focus();
Keyboard.Focus(myTextBox);
myTextBox.SelectAll();
}));
Delegating the focus action actually works.
I currently have a program where you can load a text in it.
Now I created a button that Pops up a flyout/ContentDialog but Im not happy with it because Limits me of what Im trying to achieve.
When I click the button it opens a flyout, the flyout gets the full Focus. That means I cannot scroll to the text WHILE the flyout-box is open. And if I click outside the flyout-box the flyout-box disappears.
I have a similar Problem to the ContentDialog.
When I click the button and the ContentDialog Pops up, everything behind the ContentDialog goes a bit into White/Grey Color. Also the ContentDialog does not allow any Focus outside the ContentDialog itself.
So what do I want to have?
I want that when I click on the button that a Window appears. I should be able to customize the window (writing text in it and it should have a button).
While this Window is open I want to be able to do Actions outside that window without the window Closing. For example Scrolling through the text I loaded.
Is there something I can achieve this with?
Take a look at the Popup class. This will let you display content on top of other content within your app's window. It's similar to the Flyout but without all of the built-in Flyout behavior that you don't want. The Popup class documentation has more details and commentary on when and how to use it.
Here's a really bland example with no styling.
<Grid>
<Popup x:Name="popup">
<StackPanel>
<TextBlock Text="Poppity pop pop" />
<Button Click="ClosePopup_Click">Close</Button>
</StackPanel>
</Popup>
<Button Click="OpenPopup_Click">Open Popup</Button>
</Grid>
private void OpenPopup_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = true;
}
private void ClosePopup_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = false;
}
There is a slightly more complicated example in the Popup documentation
I just hide and show grids with whatever I want inside.
This is a MVVM WPF Question., c#.
Within a Window I have a Tab control that looks like this
<TabControl TabStripPlacement="Top" >
<TabItem Style="{StaticResource Tabitemstyle}">
<TabItem.Header>
<Label Content="Home" Style="{StaticResource Tablablestyle}"/>
</TabItem.Header>
<v:HomePageView/>
</TabItem>
<TabItem ....
<v:OtherPageView/>
The trick is that there exists a textbox within the 2nd tab item that I wish to have input focus when the user selects the 2nd tab.
I've tried a few solutions, but the closest one so far (using data trigger style, or focused element) almost works:
I can see that the cursor is intended to be within the text box, but it doesn't blink. It seems the focus is still on the tab control in the outside window, not the text box element in the view that is defined by OtherPageView.xaml. When I hit tab once, it is all ok, but this is what I am trying to relieve the users of having to do.
I would use the code behind:
Listen to visibility changed event on the TabItem content (i.e., v:HomePageView)
Find the textbox UI element (you can simply give the textbox a name
in the xaml and refer to it from code behind)
Next, set focus on the text box using the UIElement.Focus() method
Finally if the keyboard did not focus , then use the
Keyboard.Focus(...) method to focus the keyboard on the textbox.
I have two TabItem's contained inside a TabControl.
Each TabItem contains serveral TextBox's.
When TabControl's OnSelectionChanged event is fired, as well as selecting the new TabItem, it is also setting focus on the first TextBox contained inside the newly selected item.
Is there any way to prevent this from happening?
Setting IsTabStop="False" on the TextBox will achieve this, but unfortunately also prevents the TextBox from being 'tabbed' into.
In your tab control, handle the focus event for each of the tabs like this:
<TabItem GotFocus="TabItem_OnGotFocus">
Then just remove focus using:
private void TabItem_OnGotFocus(object sender, RoutedEventArgs e)
{
Keyboard.ClearFocus();
}
Just add a container to your content as Grid, Stackpanel, Border, etc. and set it Focusable. When Tab selection change, the focus is set to the container and you can also use the tab key.
<TabItem Header="myHeader">
<StackPanel Focusable="True">
...
</StackPanel>
</TabItem>
#shannon it answers to your question about MVVM
I am new to WPF and am going through the examples of Professional WPF in .net 4.5. In the commands chapter, there is an example where multiple controls can send the same command. I am using a Button, CheckBox and MenuItem to trigger the New command.
The issue I am facing is that if MenuItem is pressed for the first time, the source shows correctly. However, after clicking the Button or CheckBox, then clicking MenuItem shows me the source of the last control Button or CheckBox, whichever was pressed. I couldn't find what was wrong with my code or why is this behavior shown by MenuItem in WPF.
Below is the code.
<Window x:Class="WpfApplication1.CommandSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CommandSample" Height="300" Width="300">
<Window.CommandBindings>
<CommandBinding Command="New" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<StackPanel>
<Button Command="New" MaxWidth="80" MaxHeight="30" Content="{x:Static ApplicationCommands.New}" />
<Menu MaxHeight="30" VerticalAlignment="Top">
<MenuItem Header="File">
<MenuItem Command="New"></MenuItem>
</MenuItem>
</Menu>
<CheckBox Command="New"></CheckBox>
</StackPanel>
</Window>
namespace WpfApplication1 {
public partial class CommandSample: Window {
public CommandSample() {
InitializeComponent();
}
private void CommandBinding_Executed(object sender,ExecutedRoutedEventArgs e)
{
MessageBox.Show("New Command launched by " + e.Source);
}
}
}
Yes this is correct (or at least that's how it's designed). Routed commands start routing based on the CommandTarget you specify. If one isn't specified typically the object raising the event uses itself as the starting point (so the MenuItem in this case). So the routing starts with the MenuItem in this case as you might expect. Nothing handles it there so the CommandManager goes up the parent chain. When it hits an element that is a FocusScope (like the Menu), it checks the FocusedElement of the "parent" FocusScope (e.g. the FocusScope of the parent of the Menu which in this case is the Window). If there is a FocusedElement (which there will be one once you have focused an element in the window's focus scope such as your button, checkbox, a textbox that you might put in that stackpanel, etc.) then the CommandManager starts routing the event from that element. When it does that it creates a new ExecutedRoutedEventArgs where the OriginalSource is that starting element (so the button, checkbox, textbox) and then continues routing up the tree.
So when you first ran the app, the FocusedElement of the Window (that's the root focus scope in your example) is null so there is no re-routing needed so the CommandManager just kept going up the parent chain past the Menu and that is why MenuItem appeared as the Source & OriginalSource. When you clicked on the Button you gave that keyboard focus and as part of it also became the logically focused element of its focus scope (i.e. the FocusedElement of its containing FocusScope). So when the MenuItem was subsequently clicked and the CommandManager ultimately reached the Menu, it then re-routed over to the Button (or whatever you focused in the window's focusscope) and started routing up from there. I say this is expected because with routed command you want the routing to go through the logically focused element so that for example, the Cut command of a menu item would trigger a cut of the TextBox in the Window that had focus.