User control is not hiding in wpf - wpf

I created a UserControl like Popup which is displayed when user clicks on menu item.
If user clicks side that user control should be collapsed.
It works fine for me when user clicks side other than any control.
If I click on datagrid or listbox it is not hiding.
Here is my code:
<src:AddNewItemPopUp x:Name="PopUp" Margin="111,47,620,230" Panel.ZIndex="1" Visibility="Collapsed"/>
I took a button in click event I set PopUp visibility property to true
In my user control I have grid. In the mousedown event of grid I have written following code...
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
if (PopUp.Visibility == Visibility.Visible)
{
PopUp.Visibility = Visibility.Collapsed;
}
}
If I click on any control like a Button, DataGrid, ListBox that are placed in Grid Popup is not collapsed.

First Set Grid's Background Property, for example grid.Backgroung=Brushes.Transparent or in Xaml Backgroung = "Transparent"
Second Handle PreviewMouseDown event instead of MouseDown event.
The first one makes the mouse event to fire, when mouse is directly over the grid.
The second one makes the mouse event fire, when mouse is over an UIElement in the grid.

Try:
Visibility="Hidden"
that is:
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
if (PopUp.Visibility == Visibility.Visible)
{
PopUp.Visibility = Visibility.Hidden;
}
}
and also see:
http://msdn.microsoft.com/en-us/library/system.windows.visibility.aspx

Related

How to monitor "mouse leave" event?

On my window, there is a textbox, a combobox and a TextBlock.
Now I click the textbox to focus on it.
I want to monitor the event: when click other controls (the combobox, the TextBlock, even the empty area on the window) besides this textbox.
Are there any events that can handle it directly? Rather than binding mouseevent for each control.
You could handle the tunneling PreviewMouseLeftButtonDown of the parent window:
public MainWindow()
{
InitializeComponent();
PreviewMouseLeftButtonDown += (s, e) =>
{
if (e.Source != theTextBox)
{
MessageBox.Show("Click detected outside the TextBox!");
}
};
}

WPF: Toggle multiple Buttons by dragging the mouse over them

Is it possible to toggle the state of multiple ToggleButtons by dragging the mouse over them (with the left mouse button hold down)?
There isn't anything in the box that would support this, but you should be able to subscribe to MouseMove and toggle the state on if the button is pressed.
<ToggleButton Content="ToggleButton" MouseEnter="ToggleButtonMouseEnter" Width="80" HorizontalAlignment="Left"/>
private void ToggleButtonMouseEnter(object sender, MouseEventArgs e)
{
System.Windows.Controls.Primitives.ToggleButton tb = (System.Windows.Controls.Primitives.ToggleButton)sender;
if(e.LeftButton == MouseButtonState.Pressed) tb.IsChecked = !tb.IsChecked;
}

PopUp StaysOpen when control goes

In a Usercontrol Grid(Grid1) I have a textBox, two Buttons (Search and Save Buttons) and Two Popups(Popup1 and Popup2). Inside Popup2 there is a textBox and one button(Search). I wanted to hide the popups(both 1 and 2) when when the user click outside the Grid1. Rightnow I can hide the Popups but NOT able to click the button inside Popup2. As soon as I Click the SearchButton inside the Popup2 it hides Popups.
I have set the StaysOpen Property for both Popups to a bool prop like this: StaysOpen="{Binding PopupStaysOpen}"
Thanks.
-Menon
private void Grid1_LostFocus(object sender, RoutedEventArgs e)
{
(this.DataContext as ViewModel).PopupStaysOpen = false;
}

WPF: MouseEnter doesn't work on several buttons when mouse is pressed

I have a list of toggle-buttons in wpf and I want the user to be able to toggle several buttons by dragging over them. To do this, I used the MouseEnter-Event for each button. This does work, when I press the mousebutton outside the buttons and start dragging. But when I press the mousebutton on a button and start dragging, the MouseEnter-Event is only fired for the first button, where I pressed the mousebutton (also none of the other events like mouseover or mousemove are fired).
Here's the code:
public void AddButton()
{
ToggleButton btn = new ToggleButton();
btn.MouseEnter += VisibilityButton_Enter;
this.gridButtons.Children.Add(btn);
}
private void VisibilityButton_Enter(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed || e.RightButton == MouseButtonState.Pressed)
{
ToggleButton btn = sender as ToggleButton;
btn.IsChecked = !btn.IsChecked;
}
}
I found a solution to use "drag and drop" and the dragover-event, but I think there must be an easier solution?
As Kent mentioned, the ToggleButton captures the mouse. If we handle the PreviewMouseDown event ourselves we can prevent that. The rest is just keeping track of the mouse state so the we don't click twice during a single roll-over. Here is a behavior you can add to your button to enable roll-over clicking.
First add this namespace:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
and the corresponding reference to your project.
Then the XAML looks like this (notice the RollOverBehavior):
<Grid>
<ItemsControl>
<ItemsControl.ItemsSource>
<PointCollection>
<Point/>
<Point/>
<Point/>
<Point/>
<Point/>
</PointCollection>
</ItemsControl.ItemsSource>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton Width="25" Height="25">
<i:Interaction.Behaviors>
<local:RollOverBehavior/>
</i:Interaction.Behaviors>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
and here is the behavior itself:
public class RollOverBehavior : Behavior<ToggleButton>
{
bool mouseOver;
bool clicked;
protected override void OnAttached()
{
AssociatedObject.PreviewMouseLeftButtonDown += (s, e) =>
{
AssociatedObject.IsChecked = !AssociatedObject.IsChecked;
e.Handled = true;
};
AssociatedObject.MouseEnter += (s, e) =>
{
mouseOver = true;
clicked = false;
};
AssociatedObject.MouseLeave += (s, e) =>
{
mouseOver = false;
};
AssociatedObject.MouseMove += (s, e) =>
{
if (mouseOver && !clicked && e.LeftButton == MouseButtonState.Pressed)
{
AssociatedObject.IsChecked = !AssociatedObject.IsChecked;
clicked = true;
}
};
}
}
The problem is that the default behavior of the ToggleButton is to capture the mouse when the left mouse button is clicked. Because the mouse is captured, all mouse events are sent to the first ToggleButton.
Sounds like what you want to do is override this default behavior such that the mouse isn't captured, but to be honest I couldn't really follow exactly what it is you're trying to achieve.
I had the same problem with normal Buttons. The solution, that worked for me, is to set e.Handled = true in the PreviewMouseButtonDown event (I implemented this too). It seems, that just by down-click with the mouse, the previous action is not fully handled until the mouse button is released, so the MouseEnter event is not able to raise.

WPF ListBox drag & drop interferes with ContextMenu?

I'm implementing drag & drop from a ListBox, but I'm seeing some strange behaviour with a ContextMenu elsewhere in the window. If you open the context menu and then start a drag from the ListBox, the context menu closes but won't open again until after you perform another drag.
Does this make sense? Anybody got any ideas what might be going on?
<ListBox Grid.Row="0" ItemsSource="{Binding SourceItems}" MultiSelectListboxDragDrop:ListBoxExtension.SelectedItemsSource="{Binding SelectedItems}" SelectionMode="Multiple" PreviewMouseLeftButtonDown="HandleLeftButtonDown" PreviewMouseLeftButtonUp="HandleLeftButtonUp" PreviewMouseMove="HandleMouseMove"/>
<ListBox Grid.Row="1" ItemsSource="{Binding DestinationItems}" AllowDrop="True" Drop="DropOnToDestination" />
<Button Grid.Row="2">
<Button.ContextMenu>
<ContextMenu x:Name="theContextMenu">
<MenuItem Header="context 1"/>
<MenuItem Header="context 2"/>
<MenuItem Header="context 3"/>
</ContextMenu>
</Button.ContextMenu>
Button with context menu
</Button>
...
public partial class Window1
{
private bool clickedOnSourceItem;
public Window1()
{
InitializeComponent();
DataContext = new WindowViewModel();
}
private void DropOnToDestination(object sender, DragEventArgs e)
{
var viewModel = (WindowViewModel)e.Data.GetData(typeof(WindowViewModel));
viewModel.CopySelectedItems();
}
private void HandleLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var sourceElement = (FrameworkElement)sender;
var hitItem = sourceElement.InputHitTest(e.GetPosition(sourceElement)) as FrameworkElement;
if(hitItem != null)
{
clickedOnSourceItem = true;
}
}
private void HandleLeftButtonUp(object sender, MouseButtonEventArgs e)
{
clickedOnSourceItem = false;
}
private void HandleMouseMove(object sender, MouseEventArgs e)
{
if(clickedOnSourceItem)
{
var sourceItems = (FrameworkElement)sender;
var viewModel = (WindowViewModel)DataContext;
DragDrop.DoDragDrop(sourceItems, viewModel, DragDropEffects.Move);
clickedOnSourceItem = false;
}
}
}
It seemed to be something to do with the mouse capture!?
The normal sequence of events during a drag goes something like this...
The PreviewMouseLeftButtonDown
handler gets called and
ListBox.IsMouseCaptureWithin is
false.
The PreviewMouseMove handler
gets called. By this time
ListBox.IsMouseCaptureWithin is true.
During the PreviewMouseMove handler
DragDrop.DoDragDrop gets called and
sometime during this the mouse
capture is released from the ListBox.
But, what seems to happening for a drag started when the context menu is open is...
The PreviewMouseLeftButtonDown
handler gets called and
ListBox.IsMouseCaptureWithin is
false.
The PreviewMouseMove handler gets
called. But this time
ListBox.IsMouseCaptureWithin is
still false.
Sometime after the end of the
PreviewMouseMove handler the
ListBox then gets the mouse capture
(ListBox.IsMouseCaptureWithin
becomes true)
The result of this is that after the drag, the ListBox still has the mouse capture so any clicks on the button to open the context menu are actually going to the listbox not the button.
Adding the following code to the start of the PreviewMouseLeftButtonDown handler seems to help by swallowing up the click that closes that context menu rather than trying to start a drag from it...
if (!contextMenuCloseComplete)
{
sourceElement.CaptureMouse();
return;
}
...with the contextMenuCloseComplete bool getting set in handlers for the context menu's Closed and Opened events.
Does that make sense? Does anyone understand where this mouse capture behaviour is coming from?

Resources