我使用Caliburn.Micro作为WPF应用程序。
我正在使用的一项功能包含弹出控件中的视图,让我选择设置。
但我得出的结论是,这是一种我无法解决的行为。
在我点击按钮后面的代码中出现一个弹出窗口,当我点击屏幕上的其他地方时,它会按预期消失。
当我点击列表中的某个项目时,弹出窗口会出现,但如果我点击窗口上的其他位置,则不会消失。 (但如果我点击其他地方,就像其他应用程序一样)
基本上,在处理选定的项目事件时,我无法创建具有StaysOpen = false行为的PopUp。我该怎么做才能解决这个问题?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox Name="ListBox" Width="250" HorizontalAlignment="Left" SelectionChanged="ListBox_SelectionChanged">
</ListBox>
<Button Name="Button" HorizontalAlignment="Right" Content="ShowPopUp" Click="Button_Click" />
</Grid>
</Window>
和背后的代码
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.ListBox.ItemsSource = new System.Collections.ObjectModel.ObservableCollection<MainWindowItem>()
{
new MainWindowItem {Name = "Test 001" },
new MainWindowItem {Name = "Test 002" },
new MainWindowItem {Name = "Test 003" },
};
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selection = this.ListBox.SelectedItem as MainWindowItem;
if (selection == null)
{
return;
}
var popUp = new System.Windows.Controls.Primitives.Popup();
popUp.Child = new TextBox { Text = selection.Name , MinWidth = 200 , MinHeight = 32};
popUp.StaysOpen = false;
popUp.AllowsTransparency = true;
popUp.PlacementTarget = sender as FrameworkElement;
popUp.IsOpen = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var popUp = new System.Windows.Controls.Primitives.Popup();
popUp.Child = new TextBox { Text = "This is button Clicked" , MinWidth = 200, MinHeight = 32 };
popUp.StaysOpen = false;
popUp.AllowsTransparency = true;
popUp.PlacementTarget = sender as FrameworkElement;
popUp.IsOpen = true;
}
}
public class MainWindowItem
{
public string Name { get; set; }
public string Value { get; set; }
}
}
答案 0 :(得分:1)
嗨,请尝试下一个解决方案。它基于鼠标按下事件挂钩(from here),每次发生时都会折叠弹出窗口(并重置列表项目选择)。
代码
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public static readonly DependencyProperty SelectedProperty = DependencyProperty.Register(
"Selected", typeof (object), typeof (MainWindow), new PropertyMetadata(default(object)));
//property to monitor selection
public object Selected
{
get { return (object) GetValue(SelectedProperty); }
set { SetValue(SelectedProperty, value); }
}
private Popup _popUp;
public MainWindow()
{
InitializeComponent();
_popUp = new Popup {IsOpen = false};
ListBox.ItemsSource = new System.Collections.ObjectModel.ObservableCollection<MainWindowItem>()
{
new MainWindowItem {Name = "Test 001" },
new MainWindowItem {Name = "Test 002" },
new MainWindowItem {Name = "Test 003" },
};
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
//will stop hookig here
private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
Unloaded -= OnUnloaded;
Loaded -= OnLoaded;
MouseHook.MouseAction -= MouseHookOnMouseAction;
MouseHook.Stop();
}
//will collapse the popup and reset selection
private void MouseHookOnMouseAction(object sender, EventArgs eventArgs)
{
Selected = null;
_popUp.IsOpen = false;
}
//will start hookig here
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
MouseHook.MouseAction += MouseHookOnMouseAction;
MouseHook.Start();
}
//here is your logic without any changes
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selection = ListBox.SelectedItem as MainWindowItem;
if (selection == null)
{
return;
}
_popUp.Child = new TextBox { Text = selection.Name, MinWidth = 200, MinHeight = 32 };
_popUp.StaysOpen = false;
_popUp.AllowsTransparency = true;
_popUp.PlacementTarget = sender as FrameworkElement;
_popUp.IsOpen = true;
}
//here is your logic without any changes
private void Button_Click(object sender, RoutedEventArgs e)
{
_popUp.IsOpen = false;
_popUp.Child = new TextBox { Text = "This is button Clicked", MinWidth = 200, MinHeight = 32 };
_popUp.StaysOpen = false;
_popUp.AllowsTransparency = true;
_popUp.PlacementTarget = sender as FrameworkElement;
_popUp.IsOpen = true;
}
}
public class MainWindowItem
{
public string Name { get; set; }
public string Value { get; set; }
}
/// <summary>
/// Mouse hooking helper
/// </summary>
public static class MouseHook
{
public static event EventHandler MouseAction = delegate { };
/// <summary>
/// Starts hooking
/// </summary>
public static void Start()
{
_hookID = SetHook(_proc);
}
/// <summary>
/// Stops hooking
/// </summary>
public static void Stop()
{
UnhookWindowsHookEx(_hookID);
}
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
//actually set a hook
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
IntPtr hook = SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle("user32"), 0);
if (hook == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();
return hook;
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
//is the mouse hook callback
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseAction(null, new EventArgs());
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
XAML代码
<Window x:Class="WPFPopupStrangeIssueSOHelpAttempt.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" x:Name="This">
<Grid>
<ListBox Name="ListBox" Width="250" HorizontalAlignment="Left"
SelectedItem="{Binding ElementName=This, Path=Selected, UpdateSourceTrigger=PropertyChanged}"
SelectionChanged="ListBox_SelectionChanged">
</ListBox>
<Button Name="Button" HorizontalAlignment="Right" Content="ShowPopUp" Click="Button_Click" />
</Grid></Window>
如果您需要任何解释,请告诉我。
问候。