question edited to provide a better explanation
I am using a treeview consisting of a stackpanel with a textblock and a textbox inside. What I would like to achieve is the total selection of the text when the textbox appears.
The textblock disappears by double-clicking or selecting an option from a context menu, giving visibility to the textbox to rename the item.
I'd like to have the selectall on the MouseLeftButtonDown on the textblock and also on click on a context menu option.
My treeview is contained in the MainWindow and, the stackpanel (with the text block and the textbox) is in a different file and I dynamically add it to the tree view depending on the user's action.
When I click on the StackPanel the first click highlights it, on double-click it opens a page and, on the MouseLeftButtonDown (and on click in a contextmenu option) I change the visibility of the textblock with the textbox and here I want the selectall() event to get fired.
I tried the following code and it only works halfway:
private void mniRename_Click(object sender, RoutedEventArgs e)
{
prevSelected.MyTextBlock.Visibility = Visibility.Collapsed;
prevSelected.MyTextBox.Visibility = Visibility.Visible;
prevSelected.MyTextBox.Focus();
if (prevSelected.MyTextBox.IsFocused)
{
prevSelected.MyTextBox.SelectAll();
}
prevSelected.MyTextBox.Text = prevSelected.MyTextBlock.Text;
}
The issue is that the SelectAll() event doesn't work on the first click while the Focus() works, then on the following clicks everything works fine.
The code is always executed in the same way.
Does anyone have any idea why this happens?
No really sure what you want to achieve. but what you describe can be achieved by the following code:
XAML
<StackPanel Orientation="Horizontal">
<TextBox x:Name="MyTextBox" LostFocus="MyTextBox_OnLostFocus" Width="100"/>
<TextBlock x:Name="MyTextBlock" Text="{Binding ElementName=MyTextBox, Path=Text}" MouseLeftButtonDown="MyTextBlock_OnMouseLeftButtonDown"/>
</StackPanel>
C#
private void MyTextBox_OnLostFocus(object sender, RoutedEventArgs e)
{
MyTextBox.Visibility = Visibility.Hidden;
MyTextBlock.Visibility = Visibility.Visible;
}
private void MyTextBlock_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MyTextBlock.Visibility = Visibility.Collapsed;
MyTextBox.Visibility = Visibility.Visible;
MyTextBox.Focus();
MyTextBox.SelectAll();
}
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.
Not sure if anyone has had this problem but there is a random home button that shows up on my UWP app whenever I click a button within the app. The button does not exist in my application so I'm not sure where it is coming from. it appears in the same place every time and if I drag the window it doesn't move with it. It appears every time i click on a button control, then fades away after 4-5 seconds.
UPDATE
After further investigation I found what was happening. I have a webview control in the background and button controls in the front view. The website I navigate to (vans.co.uk) has it's store logo in the top left corner and when the mouse hovers over it, the "Home" tooltip appears. However, if I click on a button control anywhere on the screen, and change the visibility property of that button to collapsed in the click method, this "Home" tooltip appears. There must be some sort of event passed to the webview when a button is collapsed on click. This happens on any website, not just vans.co.uk, but the logo on this site is positioned in a way that the tooltip pops up. I wrote a simple app to recreate this:
XAML:
<Page
x:Class="HomeTootipBug.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HomeTootipBug"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<WebView x:Name="webView" Visibility="Visible" DefaultBackgroundColor="White" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
<Button x:Name="btn" Background="Gray" HorizontalAlignment="Center" VerticalAlignment="Center" Width="500" Height="100" Click="btn_Click"></Button>
</Grid>
</Page>
xaml.cs:
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace HomeTootipBug
{
public sealed partial class MainPage : Page
{
public bool compOut = false;
public MainPage()
{
this.InitializeComponent();
webView.Navigate(new Uri("https://www.vans.co.uk"));
}
private void btn_Click(object sender, RoutedEventArgs e)
{
btn.Visibility = Visibility.Collapsed;
btn.Visibility = Visibility.Visible;
}
}
}
This seems to be a compination of how the vans.co.uk works & how the UWP event handling works. In short, collapsing the button in click allows the WebView to receive focus, quite likely prompting vans web site to run JS which shows the Home-button.
You can monitor what happens by adding GotFocus event handler to the WebView. If you start from scenario where your button isn't collapsed:
private void btn_Click(object sender, RoutedEventArgs e)
{
//btn.Visibility = Visibility.Collapsed;
//btn.Visibility = Visibility.Visible;
Debug.WriteLine("Button Clicked "+ e.OriginalSource.ToString());
}
private void WebView_GotFocus(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Webview got focus");
}
You can see the following debug output when you click the button few times:
Button Clicked Windows.UI.Xaml.Controls.Button
Button Clicked Windows.UI.Xaml.Controls.Button
Button Clicked Windows.UI.Xaml.Controls.Button
Button Clicked Windows.UI.Xaml.Controls.Button
Button Clicked Windows.UI.Xaml.Controls.Button
Now if you remove the comments from code, enabling the collapsing:
private void btn_Click(object sender, RoutedEventArgs e)
{
btn.Visibility = Visibility.Collapsed;
btn.Visibility = Visibility.Visible;
Debug.WriteLine("Button Clicked "+ e.OriginalSource.ToString());
}
private void WebView_GotFocus(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Webview got focus");
}
You can see the following output in debug console after few clicks:
Button Clicked Windows.UI.Xaml.Controls.Button
Webview got focus
Webview got focus
Button Clicked Windows.UI.Xaml.Controls.Button
Webview got focus
Webview got focus
Button Clicked Windows.UI.Xaml.Controls.Button
Webview got focus
It's quite likely that this is related how UWP deals with event bubbling & routed events.
I've got a simple WPF dialog with these two controls:
<TextBox Text="{Binding MyText}"/>
<Button Command="{Binding MyCommand}" IsDefault="True"/>
Now, when I enter some text in the TextBox and click the button using the mouse, everything works like expected: the TextBox will set MyText and MyCommand is called.
But when I enter some text and hit enter to "click" the default button, it does not work. Since on hitting enter the focus does not leave the TextBox, the binding will not be refresh MyText. So when MyCommand is called (which works), MyText will contain old data.
How do I fix this in MVVM? In classic code-behind I probably just would call "MyButton.Focus()" in the MyCommand handler, but in MVVM the MyCommand handler does know nothing about the button.
So what now`?
Add the UpdateSourceTrigger to your TextBox with the value PropertyChanged. The default behavior of the Textbox is to update the source, when it´s lost focus.
<TextBox Text="{Binding MyText, UpdateSourceTrigger=PropertyChanged}"/>
Try this. This code moves focus on the button clicked. Thus binding completes before command processed.
public App()
{
EventManager.RegisterClassHandler(typeof(Button), Button.ClickEvent, new RoutedEventHandler(GenericButtonClickHandler));
}
void GenericButtonClickHandler(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button == null)
return;
if (button.IsDefault)
button.Focus();
}
One Solution ist, to create your own Class OKButton that calls Me.Focus in the OnClick-Method. This will be called before the Click_Event and before any Command that is bound to the button. You just have to remember to use an OKButton instead of setting IsDefault=True
Public Class OKButton
Inherits System.Windows.Controls.Button
Public Sub New()
MyBase.New()
Me.Content = "OK"
Me.IsDefault = True
End Sub
Protected Overrides Sub OnClick()
Me.Focus()
MyBase.OnClick()
End Sub
End Class
I Have a Control Template similar to this in the App.xaml:
<ControlTemplate x:Key="Register" >
<Grid>
<TextBox Name="REGUSEBOX"/>
<ButtonName="REGBUTTON" Click="Button_Click" />
</Grid
</ControlTemplate>
The Button_Click method was generated in the App.xaml.cs and it works fine, But I can't access the the Textbox.
How can i access the Textbox in the Click method?
Thanks
sender of Click event here is a Button. you can cast it to Button type, take parent (which is Grid), find parent's child element by name and cast it to TextBox
private void Button_Click(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
Grid grd = button.Parent as Grid;
TextBox txt = grd.FindName("REGUSEBOX") as TextBox;
}
note: wpf approach usually doesn't require such manipulations. Binding for TextBox + Command for Button should allow to do all the job in model, not in code behind. if controls have to change their apperance depending on some conditions, Style and Triggers can help
This should do the trick:
private void Button_Click(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
}
The first parameter is the Button Object.
Button button = sender as Button;
the button is what you want. But, I suggest use MVVM Pattern in developing of WPF.
If you want know more. Here go
This is my XAML code:
<ListBox ItemsSource="{Binding}" Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel Width="370">
<TextBlock Text="{Binding AuthorName}" x:Name="author" MouseEventLeftDown="click"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And the Click Handler
private void click(object sender, RoutedEventArgs e)
{
if(author.Text.Equals("Hi"))
{
// Do Something Special
}
}
The error is:
Error: The name 'author' does not exist in the current context
But I don't understand what is causing this error or why it is occurring.
Your TextBlock with the Name author doesn't exist in the scope of your click handler because it's in a DataTemplate. What's happening is that the author TextBlock is created once for every one of your data items (Presumably an Author class or a Book class of some kind), so you literally can have dozens of controls named author.
You are better off casting your sender in your click handler to a text box and then checking its text property. Something like this:
private void click(object sender, RoutedEventArgs args)
{
var textBox = sender as TextBox;
if(textBox == null)
return;
if(textBox.Text.Equals("hi"))
{
// Do Something Crazy!
}
}
It's probably better to use a UI element designed for touch, such as a HyperlinkButton or a Button. You can style these any way you would like to - especially if you use Expression Blend - but it is good design to include some visual feedback about the Touch.
Also - I'm not sure about your == code - you're comparing the sender (a UI element) against some string expression?
First off, your TextBlock is defined in a DataTemplate; try x:Name instead of Name on your TextBlock.
Secondly it might be quite tricky to click your TextBlock since you will have to press an exact pixel in your TextBlock. To make it easier to click your TextBlock you might want to put a Background on your TextBlock, so it will be a lot easier to click. You can even make the background transparent:
Background="Transparent"
use the gesture listener for create an event handler like "tap" or double" or whatever.
Use this...
private void click(object sender, RoutedEventArgs e)
{
var author = (TextBlock)sender;
if (author.Text.Equals("Hi"))
{
// Do Something Special
}
}