Reputation: 8940
I have a ToolBar
in my application which causes Problems.
I have "DropDown" Buttons inside the ToolBar
(ToggleButton
+ Popup
) Those DropDowns work properly if they are on the Visible Part of the ToolBar
, they do not work properly if they are located in the ToolBarOverflowPanel
.
If i Open a DropDown in the ToolBarOverflowPanel
the Popup
does not seem to receive focus. There are still hover effects (opposing to the behaviour of the same Popup
in the visible toolbar which seems to consume all Mouse
Events) and i can still click any other DropDown which opens the next Popup
while the initial one stays open.
The following code is a full working sample to reproduce the behaviour.
<Window x:Class="ToolbarProblem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350"
Width="525">
<StackPanel>
<ToolBar ItemsSource="{Binding Items}">
<ToolBar.ItemTemplate>
<DataTemplate >
<StackPanel VerticalAlignment="Center"
Orientation="Horizontal">
<ToggleButton Name="ToggleButton"
ToolTip="ToolTip"
IsChecked="{Binding ElementName=ContextActionPopup, Path=IsOpen, Mode=TwoWay}"
ClickMode="Release">
<TextBlock Text="ICON"/>
</ToggleButton>
<Popup Name="ContextActionPopup"
StaysOpen="False">
<Border x:Name="Border"
Background="White"
Padding="1"
Visibility="Visible">
<TextBlock Text="Content" />
</Border>
</Popup>
</StackPanel>
</DataTemplate>
</ToolBar.ItemTemplate>
</ToolBar>
</StackPanel>
namespace ToolbarProblem
{
using System.Collections.Generic;
public partial class MainWindow
{
public MainWindow()
{
this.InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
public class MainWindowViewModel
{
public List<object> Items { get; } = new List<object>
{
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object()
};
}
}
I did tried the following approaches without any success:
Popup.Focus
ToggleButton.ClickMode
to everything possiblePopup.StaysOpen
property to true does seem to work, but is
of course inappropriate for my targetUpvotes: 0
Views: 405
Reputation: 5666
I am afraid that your XAML will never work properly. You can find the reason in the Popup
control code. If you set the StaysOpen
property to false, the Popup
when opening, will call this private method (just use ILSpy to inspect):
private void EstablishPopupCapture()
{
if (!this._cacheValid[1] && this._popupRoot.Value != null && !this.StaysOpen && Mouse.Captured == null)
{
Mouse.Capture(this._popupRoot.Value, CaptureMode.SubTree);
this._cacheValid[1] = true;
}
}
So if there is no other control that is capturing mouse events (i.e. Mouse.Captured == null
) your popup will capture them
to determine when one of these events occurs outside the Popup control.
as MSDN remarks. Please, note that Capture
method and Captured
properties are static, so just one control at a time can capture by using Mouse
class.
Now just take a look to the Toolbar
default style: you will find that its Popup
control, named "OverflowPopup", has its StaysOpen
property set to false.
So when you click on the overflow thumb, the "OverflowPopup" calls the EstablishPopupCapture
while it is opening. In this case Mouse.Captured
is null so it can capture mouse events.
After a while you click on a ToggleButton
which is inside the "OverflowPopup" (so it will continue to stay open). Now your Popup - while opening - calls EstablishPopupCapture
, but this time Mouse.Captured
is not null. So it is not able to listen to mouse events by using Mouse
class.
I guess you should consider changing your XAML or adopting a different solution (for example you can write your own template for your Toolbars in order to set OverflowPopup's StaysOpen
property to true).
This is a simplified explanation, but the fact of the matter is that it is not possible to have two or more opened popups with StaysOpen set to false: they simply cannot work as expected. Just try to run this XAML:
<StackPanel Orientation="Horizontal">
<Button Content="I am button 1" Name="btn1" Height="20" />
<Button Content="I am button 2" Name="btn2" Height="20" />
<Popup StaysOpen="False" IsOpen="True" PlacementTarget="{Binding ElementName=btn1}">
<TextBlock Text="Popup1" Margin="6" Background="Red" />
</Popup>
<Popup StaysOpen="False" IsOpen="True" PlacementTarget="{Binding ElementName=btn2}">
<TextBlock Text="Popup2" Margin="6" Background="Red" />
</Popup>
</StackPanel>
And you will see that Popup2 will not work as it should do.
Upvotes: 2