How to click controls inside Popup with StaysOpen as False - wpf

I have a Popup with a ListView inside. I'd like to set StaysOpen as False so that it properly closes when I click away from the popup. However, this means that all mouse events are intercepted. As such, I don't get any mouse events inside my ListView.
Here's my current setup. I've removed all styling to make it easier to see what's going on.
<Popup Name="puSearchResults" StaysOpen="False"
AllowsTransparency="True"
LostFocus="puSearchResults_LostFocus"
LostKeyboardFocus="puSearchResults_LostKeyboardFocus"
LostMouseCapture="puSearchResults_LostMouseCapture" >
<ListView Name="lvSearchResults"
MouseLeftButtonDown="lbSearchResults_MouseLeftButtonDown"
SelectionChanged="lvSearchResults_SelectionChanged"/>
</Popup>
In this case, MouseLeftButtonDown only works if I set StaysOpen to True, but then the Popup doesn't disappear if I click away.
Ideas?

I would add mouse events to the ListView or to the objects in your ListView's data templete.
Then you could do this:
private void lvSearchResults_MouseEnter(object sender, MouseEventArgs e)
{
puSearchResults.StaysOpen = true;
}
private void lvSearchResults_MouseLeave(object sender, MouseEventArgs e)
{
puSearchResults.StaysOpen = false;
}
EDIT
Similar question that should help: Close Wpf Popup On click of item of its own control template

Related

Custom window drag handler interferes with scrollviewer bar drag

I have a window with window style set to None that handles OnPreviewMouseDown, OnPreviewMouseUp, and OnMouseMove so that the window can be dragged from anywhere.
The windows code behind looks like this:
bool inDrag;
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonDown(e);
inDrag = true;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (inDrag && e.LeftButton == MouseButtonState.Pressed)
{
this.DragMove();
}
}
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonUp(e);
if (inDrag)
{
inDrag = false;
}
}
Now problem is I have a large menu in this window that has a scroll bar which works with the scroll wheel and by clicking to a position on the scrollviewer but not when clicking and dragging the scroll bar itself. Also if I click and hold and move my cursor not on top of the window the scrolling works again. This has led me to believe that the above dragging implementation is blocking the scrollviewers drag functionality.
I tried manually raising the event with .RaiseEvent(e) in OnMouseMove but this causes a stack overflow exception when I move my mouse over the window.
How can I get my Scrollviewer to respond to mouse movements without removing my click and drag window behavior?
<!--ScrollViewer subscribed to PreviewMouseDown to set inDrag to false-->
<ScrollViewer Visibility="Visible" Mouse.PreviewMouseDown="ScrollViewer_PreviewMouseDown">
<!--The Grid fill all the available space and is subscribed to PreviewMouseDown event to set inDrag to true-->
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Mouse.PreviewMouseDown="Grid_PreviewMouseDown" Background="Transparent">
<!--My menu-->
</Grid>
</ScrollViewer>
Note that if there is "blank space" (no Background set including that of the Content),
the PreviewMouseDown event won't be raised despite the subscription.
If needed, to work around that you can set the Background of the Grid to Transparent and the event will be raised even on seemingly blank space.

How to stop FocusManager from Moving the focus outside an open Popup when using IsFocusScope option

I have two controls a ToolBar and a TextBox. The ToolBar has a Button which opens a Popup with another Button in it.
Current behavior: if i click inside the TextBox and it becomes focused and then click the button from ToolBar which opens a Popup the TextBox is still focused and receives all Keyboard input.
Now i know this is the default behavior for items inside a FocusScope which the ToolBar is, but i don't need this behavior when a popup is open. How can i avoid it ?
Here is the example:
<Window x:Class="WpfApplication67.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
</Window.Resources>
<StackPanel HorizontalAlignment="Left" Width="400">
<ToolBar>
<ToggleButton Name="openButton">Open Popup</ToggleButton>
<Popup Focusable="True"
Placement="Right"
StaysOpen="False"
IsOpen="{Binding IsChecked, ElementName=openButton, Mode=TwoWay}"
PlacementTarget="{Binding ElementName=openButton}">
<StackPanel
Width="100"
Height="100"
Background="DarkGray"
Focusable="True">
<Button>More</Button>
</StackPanel>
</Popup>
</ToolBar>
<TextBox Text="Set focus on this..." />
</StackPanel>
EDIT:
I'm striving to find an explanation about Who moves the focus on button click inside a nested FocusScope and How i can stop some Buttons (like the one inside a Popup) from doing it.
You mainly have three requirements (correct me if am wrong):
If pop up is opened, focus should be inside popUp i.e. on StackPanel.
On close of popUp, focus should retained back to textBox.
When button inside popUp is clicked, focus should not leave the popUp.
Let's pick these requirements one by one.
If pop up is opened, focus should be inside popUp i.e. on StackPanel.
Like I mentioned in the comments, put focus on stackPanel on Opened event of PopUp:
private void Popup_Opened(object sender, EventArgs e)
{
stackPanel.Focus();
}
On close of popUp, focus should retained back to textBox.
Hook Closed event and put focus back on TextBox:
private void Popup_Closed(object sender, EventArgs e)
{
textBox.Focus();
}
When button inside popUp is clicked, focus should not leave the popUp.
Now, comes the tricky part. As mentioned in the comments as soon as you click on button inside popUp, focus is moved outside of PopUp.
What you can do prevent is to attach a handler to PreviewLostKeyboardFocus event of stackPanel. In handler check for condition if keyBoard focus is within popUp, set e.Handled = true so that event gets handled here only and no bubble event is raised which will force the keyboard focus outside of stackPanel.
That being said in case you have another TextBox inside stackPanel besies button, handling event won't allow you to move focus within popUp as well. To avoid such situations you can check if new focused element doesn't belong within stackPanel then only handle the event.
Here's the code to achieve that (add handler on PreviewLostKeyboardFocus event of StackPanel):
private void stackPanel_PreviewLostKeyboardFocus(object sender,
KeyboardFocusChangedEventArgs e)
{
var newFocusedChild = e.NewFocus as FrameworkElement;
bool isMovingWithinPanel = newFocusedChild != null
&& newFocusedChild.Parent == stackPanel;
// If keyboard focus is within stackPanel and new focused element is
// outside of stackPanel boundaries then only handle the event.
if (stackPanel.IsKeyboardFocusWithin && !isMovingWithinPanel)
e.Handled = true;
}
In this situation, there are two ways, both options have been added in the handler of Click event for openButton.
First
The easiest option, it is clear focus for your keyboard, like this:
private void openButton_Click(object sender, RoutedEventArgs e)
{
Keyboard.ClearFocus();
}
Second
A more universal method it is move Focus to the parent:
private void openButton_Click(object sender, RoutedEventArgs e)
{
FrameworkElement parent = (FrameworkElement)MyTextBox.Parent;
while (parent != null && parent is IInputElement && !((IInputElement)parent).Focusable)
{
parent = (FrameworkElement)parent.Parent;
}
DependencyObject scope = FocusManager.GetFocusScope(MyTextBox);
FocusManager.SetFocusedElement(scope, parent as IInputElement);
}
For the latter case, I created attached behavior to make it more convenient to use, which can be founded here:
Set focus back to its parent?
Edit
If you want to be when you close Popup focus back to the TextBox, then add handlers of events Opened and Closed for Popup like this:
private void MyPopup_Opened(object sender, EventArgs e)
{
Keyboard.ClearFocus();
StackPanelInPopup.Focus();
}
private void MyPopup_Closed(object sender, EventArgs e)
{
MyTextBox.Focus();
}

Prevent hyperlink Click event from bubbling up

I'm designing a windows Phone app. I have a Hyperlink object in a RichTextBox, in a Grid. The Grid had a Tap event, and the Hyperlink has a Click event.
Clicking the Hyperlink also raises the parent Grid's Tap event. How can I prevent this?
I would use e.Handled in the Click handler, but RoutedEventArgs do not have a Handled property in Silverlight for Windows Phone... I also tried walking the logical tree to look for the original source, but the click appears to originate from a MS.Internal.RichTextBoxView control (e.OriginalSource)...
I don't think there is any good way from within the Click handler itself. The following state management can work though:
XAML:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Tap="ContentPanel_Tap_1">
<RichTextBox Tap="RichTextBox_Tap_1">
<Paragraph>
fdsfdfdf
<Hyperlink Click="Hyperlink_Click_1">fdsfdsfsaf</Hyperlink>
fsdfsdfa
</Paragraph>
</RichTextBox>
</Grid>
and the code:
bool RtbTapHandled = false;
private void Hyperlink_Click_1(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Hyperlink");
RtbTapHandled = true;
}
private void RichTextBox_Tap_1(object sender, System.Windows.Input.GestureEventArgs e)
{
if (RtbTapHandled)
{
e.Handled = true;
}
RtbTapHandled = false;
System.Diagnostics.Debug.WriteLine("RTB_Tap");
}
private void ContentPanel_Tap_1(object sender, System.Windows.Input.GestureEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Content_Tap");
}
In this case if you click on the RichTextBox you'll get callbacks from both RichTextBox_Tap_1 and ContentPanel_Tap_1, but if you click on the Hyperlink you'll get Hyperlink_Click_1 and RichTextBox_Tap_1 though it'll be handled at that level and stopped.

POPUP on Button right click + WPF

I have a ListBox that is bound to a list of items. The ListBoxItem is bound to a datatemplate of type Button.
On the click of button, I do some action (another window is shown). So i have bound to the Command of the button.
Now my requirement is that i show a POPUP (with some buttons in popup) to the right click of the button.
How would i be able to do this in MVVM ?
Girija
You can simply catch MouseUp event from ListBox.ItemTemplate and set Popup.IsOpen there:
private void SomeTemplateElement_MouseUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right)
puMyPopup.IsOpen = true;
}
Popup is a view element, so I don`t think there`s a reason to open it through viewmodel commands.

Is it possible to set a mouselistener in WPF?

Can i set a mouselistener (Clicked) in WPF?
Simple,
Just a Click attribute to your xaml control
Assign it a handler
Define the handler in your xaml.cs
In your xaml,
<Button Click="Button_Click"></Button>
In your xaml.cs,
private void Button_Click(object sender, RoutedEventArgs e)
{
//What should be done when you click the control
}
There are loads of mouse events available. Check MSDN for the list of mouse events supported in WPF
If te user clicked where?
If you have a button(or window or pretty much anything else) you simpy add the MouseDown() eventhandler....

Resources