как изменить состояние главного окна в одном экземпляре с помощью .Net Core

#c# #wpf #.net-core

#c# #wpf #.net-core

Вопрос:

Я пытаюсь оставить свое приложение только с одним экземпляром.

Код работает нормально, но я хочу манипулировать окном, которое уже открыто.

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

 public partial class App : Application {

private static Mutex _mutex = null;

protected override void OnStartup(StartupEventArgs e)
{
    const string appName = "MyAppName";
    bool createdNew;

    _mutex = new Mutex(true, appName, out createdNew);

    if (!createdNew)
    {
        Application.Current.Shutdown();
    }

    base.OnStartup(e);
}          
 

}

в OnStartup я попытался вызвать окно с помощью MainWindow.WindowState = WindowState.Normal; , но в этом вызове произошел сбой, отметив систему ошибок.Windows.Приложение.MainWindow.get возвращает значение null.

Комментарии:

1. Используйте Win32 PostMessage из дублирующего дочернего процесса для отправки сообщения исходному процессу (через его дескриптор главного окна).

Ответ №1:

Я создал пример проекта для приложения с одним экземпляром в WPF. Может быть, полезно:

Приложение с одним экземпляром Wpf

Вам нужны следующие собственные методы:

 public static class NativeMethod
{
    public static IntPtr BroadcastHandle => (IntPtr)0xffff;
    public static int ReactivationMessage => RegisterWindowMessage("WM_SHOWME");

    [DllImport("user32")]
    public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
    [DllImport("user32")]
    public static extern int RegisterWindowMessage(string message);
}
 

В главном окне приложения добавьте привязку к оконным сообщениям, и когда вы получили сообщение об активации, вы должны вывести главное окно поверх других окон. Вот так:

 public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        RegisterWndProcCallback();
    }

    private void RegisterWndProcCallback()
    {
        var handle = new WindowInteropHelper(this).EnsureHandle();
        var hock = new HwndSourceHook(WndProc);
        var source = HwndSource.FromHwnd(handle);

        source.AddHook(hock);
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == NativeMethod.ReactivationMessage)
            ReactivateMainWindow();

        return IntPtr.Zero;
    }

    private void ReactivateMainWindow()
    {
        if (WindowState == WindowState.Minimized)
            WindowState = WindowState.Normal;

        Topmost = !Topmost;
        Topmost = !Topmost;
    }
}
 

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

 public partial class App
{
    private static readonly Mutex _singleInstanceMutex =
        new Mutex(true, "{40D7FB99-C91E-471C-9E34-5D4A455E35E1}");

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        if (_singleInstanceMutex.WaitOne(TimeSpan.Zero, true))
        {
            Current.MainWindow = new MainWindow();
            Current.MainWindow.Show();
            Current.MainWindow.Activate();

            _singleInstanceMutex.ReleaseMutex();
        }
        else
        {
            NativeMethod.PostMessage(
                NativeMethod.BroadcastHandle,
                NativeMethod.ReactivationMessage,
                IntPtr.Zero,
                IntPtr.Zero);

            Current.Shutdown();
        }
    }
}