【问题标题】:WPF global open/close dialog event?WPF全局打开/关闭对话框事件?
【发布时间】:2012-12-15 17:14:41
【问题描述】:

在我的 WPF 应用程序中,我想订阅一些事件/callbeck/无论何时在我的应用程序中打开(和关闭)一个对话框窗口都会告诉我。

我找到了窗口集合,但这是一个简单的容器,它似乎没有提供任何订阅方式。

我也尝试使用事件处理程序,但似乎没有一个事件告诉我我需要什么。

有什么想法吗?

【问题讨论】:

    标签: wpf events dialog event-handling


    【解决方案1】:

    不使用基类的一种方法是将处理程序添加到 MainWindow deactivated

    如果打开一个新窗口,主窗口将失去焦点 = 你的“新窗口事件”

    private readonly List<Window> openWindows = new List<Window>();
    
    public void ApplicationMainWindow_Deactivated(object sender, EventArgs e)
    {
        foreach (Window window in Application.Current.Windows)
        {
            if (!openWindows.Contains(window) && window != sender)
            {
                // Your window code here
                window.Closing += PopupWindow_Closing;
                openWindows.Add(window);
            }
        }
    }
    
    private void PopupWindow_Closing(object sender, CancelEventArgs e)
    {
        var window = (Window)sender;
        window.Closing -= PopupWindow_Closing;
        openWindows.Remove(window);
    }
    

    【讨论】:

    • 如果用户点击另一个正在运行的应用程序,这也会被触发吗?
    【解决方案2】:

    如果不为所有窗口创建基类,您可以在其中挂钩打开的事件(或手动将打开的事件添加到每个窗口),我不确定您如何知道何时创建新窗口.

    可能有更优雅的方法,但您可以轮询Application.Current.Windows 以查看是否创建了任何新窗口,同时跟踪您找到的窗口。

    这是一个粗略的示例,它将演示如何使用 DispatchTimer 轮询新窗口、跟踪找到的窗口并挂钩到关闭的事件。

    代码背后

    public partial class MainWindow : Window
    {
        private DispatcherTimer Timer { get; set; }
    
        public ObservableCollection<Window> Windows { get; private set; }
    
        public MainWindow()
        {
            InitializeComponent();
    
            // add current Window so we don't add a hook into it
            Windows = new ObservableCollection<Window> { this };
    
            Timer = new DispatcherTimer( DispatcherPriority.Background );
            Timer.Interval = TimeSpan.FromMilliseconds( 500 );
            Timer.Tick += ( _, __ ) => FindNewWindows();
            Timer.Start();
    
            this.WindowListBox.ItemsSource = Windows;
            this.WindowListBox.DisplayMemberPath = "Title";
        }
    
        private void FindNewWindows()
        {
            foreach( Window window in Application.Current.Windows )
            {
                if( !Windows.Contains( window ) )
                {
                    window.Closed += OnWatchedWindowClosed;
                    // inserting at 0 so you can see it in the ListBox
                    Windows.Insert( 0, window );
                    Feedback.Text = string.Format( "New Window Found: {0}\r\n{1}",
                                                    window.Title, Feedback.Text );
                }
            }
        }
    
        private void OnWatchedWindowClosed( object sender, EventArgs e )
        {
            var window = (Window)sender;
            Windows.Remove( window );
            Feedback.Text = string.Format( "Window Closed: {0}\r\n{1}",
                                            window.Title, Feedback.Text );
        }
    
        private void CreateWindowButtonClick( object sender, RoutedEventArgs e )
        {
            string title = string.Format( "New Window {0}", DateTime.Now );
            var win = new Window
                        {
                                Title = title,
                                Width = 250,
                                Height = 250,
                                Content = title,
                        };
    
            win.Show();
            e.Handled = true;
        }
    }
    

    XAML

    <Grid>
        <ListBox Name="WindowListBox"
                    Width="251"
                    Height="130"
                    Margin="12,12,0,0"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Top" />
        <TextBox Name="Feedback"
                    Width="479"
                    Height="134"
                    Margin="12,148,0,0"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Top"
                    VerticalScrollBarVisibility="Auto" />
        <Button Name="CreateWindowButton"
                Width="222"
                Height="130"
                Margin="269,12,0,0"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Click="CreateWindowButtonClick"
                Content="Create New Window"
                FontSize="20" />
    </Grid>
    

    单击并创建任意数量的新窗口;然后关闭它们。你会看到反馈,因为它发生。当然,自从DispatchTimer 的间隔设置为 500 毫秒以来,每当创建新窗口时都会有 500 毫秒的延迟。

    【讨论】:

      【解决方案3】:

      您可以在 App.cs 中注册一个类处理程序,如此处所示

      https://gist.github.com/mwisnicki/3104963

          ...
          EventManager.RegisterClassHandler(typeof(UIElement), FrameworkElement.LoadedEvent, new RoutedEventHandler(OnLoaded), true);
          EventManager.RegisterClassHandler(typeof(UIElement), FrameworkElement.UnloadedEvent, new RoutedEventHandler(OnUnloaded), true);
          ...        
      
          private static void OnLoaded(object sender, RoutedEventArgs e)
          {
              if (sender is Window)
                  Console.WriteLine("Loaded Window: {0}", sender);
          }
      
          private static void OnUnloaded(object sender, RoutedEventArgs e)
          {
              if (sender is Window)
                  Console.WriteLine("Unloaded Window: {0}", sender);
          }
      

      上面的链接似乎在实例上注册了一个空处理程序以使事情正常工作。

      【讨论】:

      • 我认为这是针对该问题显示的解决方案中“最干净”的。我不确定 Loaded / Opened 和 Unloaded / Closed 在语义上是否完全等效,但它们似乎足够接近。这就是我正在使用的方法。
      【解决方案4】:

      我从未听说过任何全局打开/关闭事件。

      应该可以做到,但前提是您可以控制所有窗口的打开和关闭。就像您构建一个所有对话框窗口都继承自的“基本窗口”(自然继承“窗口”)一样。

      然后,您会在“基本窗口”上有一个静态事件,您可以从基本窗口的打开和关闭/关闭(或卸载)事件触发该事件,将“this”作为“sender”发送。 您可以在 App.xaml.cs 类中附加到该静态事件。

      这是一个 hack,但它是可能的。

      【讨论】:

      • 恐怕这不是我的解决方案。有些代码我无法更改,所以我不能为每个对话框使用一个共同的基础。
      • 请问,仅凭我自己的好奇心,您需要这个做什么?
      • 基于 GUI 的自动化软件测试。当然我也想控制对话框。
      • 啊。然后,您应该查看 Visual Studio 2012 中有关单元测试的新内容。此类内容可能会受到原生支持 :-)
      猜你喜欢
      • 1970-01-01
      • 2015-12-30
      • 2013-06-21
      • 1970-01-01
      • 1970-01-01
      • 2015-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多