【问题标题】:WPF: Close a secondary window when application shutdown without "programmer" interventionWPF:在没有“程序员”干预的情况下关闭应用程序关闭辅助窗口
【发布时间】:2023-03-24 04:33:01
【问题描述】:

这在标题中很难解释,如果有人想改变它就可以了。

我有一种情况,在 WPF 中,我创建了一个对程序员透明的“隐藏”窗口。 我的意思是这个窗口是在静态构造函数中创建的,隐藏并移动到屏幕之外,它的宽度和高度为 0。这是因为我正在使用这个窗口来执行一些互操作操作并允许所有的处理程序有人可能需要的 WndProcs 覆盖(有一个委托列表处理应该覆盖 WndProc 的方法)。

希望你能理解我所说的(这并不容易),我的问题是当我创建一个 WPF 项目并启动它时,如果我关闭主窗口(这不是透明创建的 给程序员),我希望我的应用程序关闭。但是,使用我创建的代码不会发生这种情况,除非我使用 Application.Current.Shutdown();

有什么方法可以在不调用该方法的情况下解决此问题?我想要一种透明的方式,其他程序员甚至不应该注意到(它是一个库,不应该以这种方式改变工作程序的行为)。

感谢您的任何建议,在这里您可以看到一些代码sn-ps:

lib创建的窗口

public class InteropWindow : Window
{
    public HwndSource Source { get; protected set; }

    private static InteropWindow _Instance;

    static InteropWindow()
    {
        _WndProcs = new LinkedList<WndProcHandler>();
        _Instance = new InteropWindow();
    }

    private static WindowInteropHelper _InteropHelper;
    public static WindowInteropHelper InteropHelper
    {
        get
        {
            if (_InteropHelper == null)
            {
                _InteropHelper = new WindowInteropHelper(_Instance);
                _InteropHelper.EnsureHandle();
            }
            return _InteropHelper;
        }
    }

    public static IntPtr Handle { get { return InteropHelper.Handle; } }

    private InteropWindow()
    {
        Opacity = 0.0;
        //We have to "show" the window in order to obtain hwnd to process WndProc messages in WPF
        Top = -10;
        Left = -10;
        Width = 0;
        Height = 0;
        WindowStyle = WindowStyle.None;
        ShowInTaskbar = false;
        ShowActivated = false;
        Show();
        Hide();
    }

    private static LinkedList<WndProcHandler> _WndProcs;
    public static void AddWndProcHandler(WndProcHandler handler)
    {
        _WndProcs.AddLast(handler);
    }
    public static void RemoveWndProcHandler(WndProcHandler handler)
    {
        _WndProcs.Remove(handler);
    }

    private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        IntPtr result = IntPtr.Zero;
        foreach (WndProcHandler handler in _WndProcs)
        {
            IntPtr tmp = handler(hwnd, msg, wParam, lParam, ref handled);
            if (tmp != IntPtr.Zero)
            {
                if (result != IntPtr.Zero)
                    throw new InvalidOperationException(string.Format("result should be zero if tmp is non-zero:\nresult: {0}\ntmp: {1}", result.ToInt64().ToString(), tmp.ToInt64().ToString()));
                result = tmp;
            }
        }
        return result;
    }

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        Source = PresentationSource.FromVisual(this) as HwndSource;
        Source.AddHook(WndProc);
        OnWindowInitialized(null, e);
    }

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        if (Source != null)
            Source.RemoveHook(WndProc);
        OnWindowClosed(null, e);
    }

    private static void OnWindowInitialized(object sender, EventArgs e)
    {
        if (WindowInitialized != null) WindowInitialized(sender, e);
    }

    private static void OnWindowClosed(object sender, EventArgs e)
    {
        if (WindowClosed != null) WindowClosed(sender, e);
    }

    public static event EventHandler WindowInitialized;

    public static event EventHandler WindowClosed;
}

使用 wpf 创建的普通窗口(从项目创建的基本窗口)

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        ExClipboard.ClipboardUpdate += new RoutedEventHandler(ExClipboard_ClipboardUpdate);
        Closed += new EventHandler(MainWindow_Closed);
    }

    private void MainWindow_Closed(object sender, EventArgs e)
    {
        //InteropWindow.Dispose();
        App.Current.Shutdown(0);
    }
}

更新 1:

要回答您的答案,不,我想避免程序员使用我的库进行任何干预,所以理想的解决方案是在我的库中订阅一些 Application.Exit 事件并关闭我的窗口,显然我不能使用 Application.Exit 因为应用程序由于我的窗口没有关闭而没有关闭

也许有一种方法可以计算属于应用程序的所有窗口?我也可以用它做点什么

【问题讨论】:

    标签: c# wpf interop window wndproc


    【解决方案1】:

    如果你有一个主窗口,你不能将Application.ShutdownMode设置为OnMainWindowClose吗?

    默认值为 OnLastWindowClose,这很可能是您看到此行为的原因。

    【讨论】:

      【解决方案2】:

      这是一个便宜的黑客,但我认为这可能会实现你所追求的......

      在您的库中,您需要引用 xaml 依赖项(PresentationCore、PresentationFramework、System.Xaml 和 WindowsBase)

      在你的库的静态构造函数中,你可以添加类似的东西

      Application.Current.MainWindow.Closed += new EventHandler(MainWindow_Closed);
      
      static void MainWindow_Closed(object sender, EventArgs e)
      {
          Dispose();
      }
      

      在哪里 dispose 关闭您的窗口 (_Instance.Close()) 并处理任何其他清理调用

      【讨论】:

      • 干得好伙计,你的 hack 效果很好,正是我想要的 :)
      • 将 App.xaml 中的 ShutDownMode 设置为 OnMainWindowClose。
      • @JesseSeger 这个想法(对于这种情况)是在库中处理它,而不是依赖最终开发人员的干预。为这个问题提供的其他答案将是正常执行此操作的最佳方法,但不适用于此特定情况。
      • 根据提问者设定的限制,您会从哪里触发该呼叫?自从我在 .Net 中思考以来已经有一段时间了 - 所以我很想知道我是不是很简单。
      • 您可以从任何地方调用它。在这种情况下,在 MainWindow_Closed 中。它会杀死整个应用程序,包括所有其他打开的窗口。
      【解决方案3】:

      从概念上讲,唯一想到的是事件消息通知服务,其中,第二个窗口正在侦听或等待消息关闭,而第一个窗口发送消息使其关闭。这也需要使用 MVVM 模式。我不完全确定这一点,我也不确定这是否符合你不让其他程序员知道的想法。

      这是一篇关于它的博客文章: Sending notifications in WPF MVVM applications

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多