Как заставить перерисовать процесс, чьим родителем является панель управления? - PullRequest
1 голос
/ 11 июня 2019

Мне было поручено создать модуль запуска приложений, на котором размещаются приложения Winforms и WPF, а также веб-приложения с несколько иной методологией.Пользователю предоставляется список приложений, которые они могут запустить, и они «захватываются» при запуске и помещаются в панель на форме с помощью SetParent, чтобы сделать панель родителем процессов MainWindowHandle.Похоже, этот бит работает хорошо, и приложения при запуске захватываются и отображаются на данной панели.

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

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

По сути, теперь я в своем уме и попробовал следующие собственные методы User32 и .NET;Invalidate (в форме, на панели, на элементе управления вкладками, на котором размещены оба из них) Обновите Refresh SendMessage с множеством параметров, включая попытку «вам не следует этого делать» WM_PAINT.RedrawWindow с флагами UpdateNow и Invalidate.

Ничто из вышеперечисленного не имеет какого-либо видимого различия, и только когда я физически щелкаю по панели или перемещаю окно, приложение будет вести себя и перерисовывать себя.

Кто-нибудь еще произвел что-нибудь подобное и нашел решение проблемы перерисовки / перерисовки?Я обыскивал все сферы Google / Bing / Duck Duck Go, пытаясь найти ответ, но безрезультатно.

Надеюсь, у одного из вас есть ответ.

Следующий код представляетОсновная часть функции заключается в том, что он запускает процесс и захватывает дескриптор главного окна процесса и устанавливает его родительский элемент для элемента управления панели в стандартном окне WinForms.Я, вероятно, должен отметить, что стандартное окно WinForms «болота» само «размещено» внутри приложения с использованием библиотеки ( EasyTabs ).Что, я считаю, не вызывает никаких проблем.

Пример:

// Try to acquire a the process.
ProcessStartInfo startInfo = new ProcessStartInfo(path);

try
{
    startInfo.UseShellExecute = false;
    startInfo.CreateNoWindow = true;
    startInfo.WindowStyle = ProcessWindowStyle.Normal;

    Process.StartInfo = startInfo;
    Process.EnableRaisingEvents = true;
    Process.Exited += TabManagerContainerForm_ProcessExited;

    Process.Start();

    if (Process != null)
    {
        // Wait until the process has created a main window or exited.
        while (Process.MainWindowHandle == IntPtr.Zero && !Process.HasExited)
        {
            Thread.Sleep(100);
            Process.Refresh();
        }

        if (!Process.HasExited) // We have acquired a MainWindowHandle
        {
            // Capture the Process's main window and show it inside the applicationPanel panel control.
            SetParent(Process.MainWindowHandle, applicationPanel.Handle);

            // Change the captured Process's window to one without the standard chrome. Itʼs provided by our tabbed application.
            SetWindowLong(Process.MainWindowHandle, (int)WindowLongFlags.GWL_STYLE, (int)WindowStyles.WS_VISIBLE); 
        }
        else // Process has exited.
        {
            if (Process.MainWindowHandle == IntPtr.Zero) Log.Information("{0} failed to execute.", Process.ProcessName);

            throw new FailedProcessException(string.Format("{0} failed to execute.", path));
        }
    }
    else
    {
        throw new Exception(string.Format("Invalid path: {0}", path));
    }
}
catch (Exception ex) when (!(ex is FailedProcessException)) // Catch everything but FailedProcessExceptions. FPEs are simply passed up the chain.
{
    Log.Error(ex.Message);
    throw;
}

1 Ответ

1 голос
/ 12 июня 2019

Резюме:

Проблема возникает при подключении приложения к Panel на вкладке, которая не является видимой в данный момент.

Решение:

Добавить WS_CHILD флаг для вызова на SetWindowLong:

SetWindowLong(Process.MainWindowHandle, (int)WindowLongFlags.GWL_STYLE, (int)(WindowStyles.WS_VISIBLE | WindowStyles.WS_CHILD));

подробности:

Я попытался воспроизвести пример в вопросе (без использования EasyTabs ). Я использовал простой Form с одним Panel. Нажатием кнопки я вызываю простое приложение WPF и присоединяю его к Panel. Это работает хорошо, это оказывает немедленно. Единственной проблемой, которую я обнаружил, было положение окна WPF, которое было случайным. Я исправил это с помощью вызова SetWindowPos (используя pinvoke ) следующим образом:

SetWindowPos(Process.MainWindowHandle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.IgnoreResize);

Чем я пытался использовать TabControl с двумя вкладками, каждая из которых содержит Panel и двумя кнопками, каждая при нажатии, запускает другое приложение WPF для одной из Panels. Я обнаружил, что когда вкладка (TabPage) не является видимой вкладкой, возникает проблема - запущенное приложение не отображается до тех пор, пока не будет нажата Panel. Я решил эту проблему, добавив флаг WS_CHILD к вызову SetWindowLong. Я не уверен, почему, но это работает ...

Мой код:

// Capture the Process's main window and show it inside the applicationPanel panel control.
SetParent(Process.MainWindowHandle, applicationPanel.Handle);

// Change the captured Process's window to one without the standard chrome. Itʼs provided by our tabbed application.
SetWindowLong(Process.MainWindowHandle, (int)WindowLongFlags.GWL_STYLE, (int)(WindowStyles.WS_VISIBLE | WindowStyles.WS_CHILD));

// Change the Process's window position to the top-left corner of the panel
SetWindowPos(Process.MainWindowHandle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.IgnoreResize);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...