2016-03-15 3 views
0

Я использую Caliburn.Micro для приложения WPF.ListBox и Popup не работают вместе

Одна из возможностей, которую я использую, обертывает представление в элементе управления всплывающим окном и позволяет мне выбирать настройки.

Но я пришел к выводу, что это поведение я не могу решить.

В появившемся коде, когда я нажимаю кнопку, появляется всплывающее окно, и когда я нажимаю в другом месте на экране, он уходит, как ожидалось.

Когда я нажимаю на элемент в списке, всплывающее окно появляется, но не исчезает, если я нажимаю в другом месте окна. (он делает, хотя если я нажму где-нибудь еще, как другое приложение)

В принципе, я не могу создать PopUp с StaysOpen = false при обработке события выбранного элемента. Что я могу сделать, чтобы решить эту проблему?

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

ответ

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> 

Позвольте мне знать, если вам нужны какие-либо объяснения.

С уважением.

+0

Спасибо, я дам вам знать, если это сработает для меня, как только я смогу – mhttk

+0

это кажется прекрасным, но я закончил использовать несколько иной подход, так как у меня может быть несколько всплывающих окон одновременно. – mhttk

+0

@mhttk может ypu, пожалуйста, перефразировать? – Ilan