LostFocus event of an Image isn't firing - c#

I have an image which displays a delete button when tapped. What I need is for the delete button to disappear when the image has LostFocus.
Typically, for say a textbox I'd just use something like the following.
tb.LostFocus += tbOnLostFocus;
private void tbOnLostFocus(object sender, RoutedEventArgs e)
{
delBtn.Visibility = Visibility.Collapsed;
}
My issue is that the same code just isn't firing on an image. I vaguely remember reading somewhere a while ago that LostFocus events wont fire on an image as it isn't a focusable element. Not sure if my memory is correct as I can't find a reference to it now.
Has anyone found a suitable workaround or managed to achieve a similar result?

You can achieve this by using MenuFlyout. Once the image is tapped it will show delete button. if the pointer is tapped anywhere other than clicking on delete button it will be collapsed
<Image Source="ms-appx:///Assets/1.jpg" Tapped="Image_Tapped">
<Image.Resources>
<MenuFlyout x:Name="DeleteMenuFlyout">
<MenuFlyout.Items>
<MenuFlyoutItem x:Name="delete" Click="Delete_Click" Text="Delete" />
</MenuFlyout.Items>
</MenuFlyout>
</Image.Resources>
</Image>
//C#
private void Image_Tapped(object sender,TappedRoutedEventArgs e)
{
DeleteMenuFlyout.ShowAt(sender as FrameworkElement);
}

Related

Textbox event only fires the second time

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();
}

How to focus on an element after button click

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.

WPF Popup vs Tooltip

I have seen a lot of debate about when to use tooltip and when to use popup but I don't know which one is better for my case.
I have a button. When I click on it, the popup panel will appear and it has a lot of text and a small image (so it will be a quite big panel). The panel must stay there until I move my cursor OFF THE BUTTON (it must still close when the cursor is still on the panel but off the button).
<Button Click="clicked" MouseLeave="mouseleaved"/>
<Popup Name="mypopup">
<stuff>
</Popup>
private void clicked(object sender, RoutedEventArgs e) {
mypopopup.isopen = true;
}
private void mouseleaved(object sender, MouseEventArgs e) {
mypopup.isopen = false;
}
This is where I got to so far. The problem is that sometimes, the Popup appears on top of the button (which blocks the view of the button and so MouseLeave event kicks off, and Popup instantly disappears). I want the Popup to stay until i move the cursor away off the button.
So I did some google, and I think Tooltip may avoid this problem. But how to get Tooltip to appear on button click and not button hover?
Which one is better for me? Tooltip or Popup?
EDIT
I think I was not too clear with my question. I am asking which one i should use- Tooltip vs Popup based on MY SPECIFIC SITUATION (paragraph 2) and not in general. I think Popup is the right one to use but I have problems with using it (paragraph 3). so my question is can I solve this problem with Popup or should I use Tooltip better for this?
But how to get Tooltip to appear on button click and not button hover?
Handle the Click event for the Button and set the IsOpen property of the Popup to true:
private void Button_Click(object sender, RoutedEventArgs e)
{
popup1.IsOpen = true;
}
<Popup x:Name="popup1" StaysOpen="False">
<TextBlock>popup content...</TextBlock>
</Popup>
<Button Click="Button_Click" Content="op" />
Which one is better for me? Tooltip or Popup?
Popup is preferable whenever you want to customize the behaviour in any way.
Edit: If I understand your issue correctly, this should work:
<Button x:Name="button" Content="Button" Click="clicked" MouseLeave="mouseleaved"/>
<Popup Name="popup" PlacementTarget="{Binding ElementName=button}" StaysOpen="True" MouseLeave="mouseleaved">
<Border Background="Yellow">
<TextBlock>contents...</TextBlock>
</Border>
</Popup>
private void clicked(object sender, RoutedEventArgs e)
{
popup.IsOpen = true;
}
private void mouseleaved(object sender, MouseEventArgs e)
{
if (!button.IsMouseOver && !popup.IsMouseOver)
popup.IsOpen = false;
}

Global event handler for TextBox getting focus by mouse click

I have a situation when I want to detect when a TextBox, anywhere in the application, has been brought into focus by the user clicking on it with the mouse, or touch. I have "solved" this by adding a global event handler like this:
Application.Current.MainWindow.AddHandler(UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(txt_MouseLeftButtonUp), true);
...
void txt_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is TextBox)
{
// Do somthing
}
}
However, if the user clicks the edges of a textbox instead of in the middle, quite often an hosting control (Grid, Border etc.) receives the mouse event and somehow passes this on to the contained TextBox, that will handle it and receive focus. This makes the approach above fruitless as the TextBox will not be the e.OriginalSource in this case and I have found no way of identifying that a TextBox was brought into focus by click.
Deriving TextBox and overriding OnMouseDown for instance, will catch this event and I guess this path could be explored to find a solution to the problem but that would require me to use a custom TextBox everywhere.
Anyone out there with a nice solution for this?
This is an example that will trigger the problem. By clicking the edges of the TextBoxes, the grid will handle the mouse event and focus will be passed on to the TextBox.
<Grid>
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="Red">
<TextBox>2323</TextBox>
</Grid>
<Grid Margin="200,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="Red" Focusable="False">
<TextBox>2323</TextBox>
</Grid>
</Grid>
The GotMouseCapture event seems to work:
AddHandler(UIElement.GotMouseCaptureEvent,
new MouseEventHandler(OnGotMouseCapture), true);
...
void OnGotMouseCapture(object sender, MouseEventArgs e)
{
if (e.OriginalSource is TextBox)
{
// ...
}
}
When I click on TextBox elements with the mouse this event handler is fired, however focus changes made via keyboard do not fire the event.
Simply handle the GotFocus event for each TextBox.

StackOverflowException when trying to show a ContextMenu and clicking on its parent

I've encountered a weird behavior in WPF. Even though there are quite a few ways to avoid this problem, I'm trying to better understand why it's happening:
I created a new WPF application, just added a button which has a ContextMenu:
<Grid>
<Button x:Name="btnTest" Margin="10,10,10,10"
MouseEnter="BtnTest_OnMouseEnter" MouseLeave="BtnTest_OnMouseLeave">
<Button.ContextMenu>
<ContextMenu x:Name="myContext">
<TextBlock Text="Context Menu Text"></TextBlock>
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
In the code behind I use MouseEnter to show the ContextMenu and MouseLeave to hide it:
private void BtnTest_OnMouseEnter(object sender, MouseEventArgs e)
{
myContext.PlacementTarget = btnTest;
myContext.Placement = PlacementMode.Bottom;
myContext.IsOpen = true;
}
private void BtnTest_OnMouseLeave(object sender, MouseEventArgs e)
{
myContext.IsOpen = false;
}
So now - I see the ContextMenu under the button when the mouse is on the button and it hides when the mouse leaves the button.
BUT when I click the button I get an exception
An unhandled exception of type 'System.StackOverflowException'
occurred in WindowsBase.dll
Question is - Why is the Mouse Click, specifically, triggering this exception? I don't have any code of mine running on the Click event, yet without clicking an exception doesn't occur...
BTW: Same will happen if I replace the Button with an Image for instance, so it doesn't seem to be caused by a specific control...
Change your XAML like this:
<Grid>
<Popup x:Name="myContext">
<TextBlock Text="Context Menu Text"></TextBlock>
</Popup>
<Button x:Name="btnTest" Margin="10,10,10,10"
MouseEnter="BtnTest_OnMouseEnter" MouseLeave="BtnTest_OnMouseLeave">
</Button>
</Grid>
I think there is a loop of this sort going on in your code:
you enter the button, the popup shows
you click, popup hides (default behavior of contextmenu)
button gets focus, popup is shown again
What happens if you set the ´StaysOpen´ property of the ContextMenu? If you then dont get this behavior anymore my suspicion is correct.

Categories