WPF: закрыть вторичное окно, когда приложение закрывается без вмешательства «программиста» - PullRequest
2 голосов
/ 17 июля 2011

Это довольно сложно объяснить в заголовке, если кто-то захочет изменить это, то все в порядке.

У меня есть ситуация, когда в WPF я создаю "скрытое" окно, которое прозрачно для программиста. Я имею в виду, что это окно создано в статическом конструкторе, скрыто и перемещено за пределы экрана, а его ширина и высота равны 0. Это потому, что я использую это окно, чтобы выполнить некоторые операции взаимодействия и разрешить своего рода обработчики для всех WndProcs переопределить, что кто-то может потребовать (есть список делегатов, который обрабатывает методы, которые должны переопределить WndProc).

В надежде, что вы понимаете, что я сказал (это нелегко), моя проблема в том, что когда я создаю проект WPF и запускаю его, если я закрываю главное окно (которое не прозрачно создано ) программисту), я хочу, чтобы мое приложение закрылось. Однако с кодом, который я создал, этого не произойдет, если я не использую Application.Current.Shutdown ();

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

Спасибо за любые предложения, здесь вы можете увидеть некоторые фрагменты кода:

Окно, созданное 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, потому что приложение не закрывается из-за того, что мое окно не закрывается

Может быть, есть способ рассчитать все окна, которые принадлежат приложению? Я тоже могу что-то сделать с этим

Ответы [ 3 ]

3 голосов
/ 17 июля 2011

Если у вас есть главное окно, вы не можете установить Application.ShutdownMode на OnMainWindowClose ?

Значением по умолчанию является OnLastWindowClose, что наиболее вероятно, поэтомувы видите это поведение.

2 голосов
/ 18 июля 2011

Это дешевый хак, но я думаю, что это может достичь того, что вы ищете ..

В вашей библиотеке вам нужно будет ссылаться на зависимости xaml (PresentationCore, PresentationFramework, System.Xaml и WindowsBase)

В статическом конструкторе для вашей библиотеки вы можете добавить что-то вроде

Application.Current.MainWindow.Closed += new EventHandler(MainWindow_Closed);

static void MainWindow_Closed(object sender, EventArgs e)
{
    Dispose();
}

Где утилита закрывает ваше окно (_Instance.Close ()) и обрабатывает любые другие вызовы очистки

1 голос
/ 17 июля 2011

С концептуальной точки зрения, единственное, что приходит на ум, - это служба уведомления о событиях, в которой второе окно прослушивает или ожидает сообщения для закрытия, а первое окно отправляет сообщение для его закрытия.Это также требует использования шаблона MVVM.Я не совсем уверен в этом, и я также не уверен, что это относится к вашей идее не сообщать другим программистам.

Вот статья в блоге: Отправка уведомлений в WPF MVVMприложения

...