Вывести окно на передний план в WPF


215

Как перенести мое приложение WPF на рабочий стол? Пока что я пробовал:

SwitchToThisWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle, true);

SetWindowPos(new WindowInteropHelper(Application.Current.MainWindow).Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);

Ни один из которых не выполняет работу ( Marshal.GetLastWin32Error()говорит, что эти операции успешно завершены, и атрибуты P / Invoke для каждого определения имеют SetLastError=true).

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

Изменить : я делаю это в сочетании с глобальной горячей клавишей.


Вы убедились, что MainWindow - это то окно, которое вам нужно? Из MSDN: MainWindow автоматически устанавливается со ссылкой на первый объект Window, экземпляр которого создается в AppDomain.
Тодд Уайт

Хорошая мысль, но это единственное окно в приложении.
Фактор Мистик

Можете ли вы дать немного больше контекстного кода?
Тодд Уайт

Ответы:


315
myWindow.Activate();

Попытки вывести окно на передний план и активировать его.

Это должно сработать, если я не правильно понял, и вы хотите, чтобы поведение всегда на вершине. В этом случае вы хотите:

myWindow.TopMost = true;

14
Я просто использовал myWindow.Show (), и иногда это не было на вершине. Я сразу же позвонил myWindow.Activate (), и это сработало.
Бермо

4
Активировать не работает на Windows XP иногда. Я рекомендую ответ @Matthew Xavier.
Лекс Ли

Немного странно, так как по умолчанию ShowActivation включен.
Гринольдман

1
Первый ответ хороший, спасибо за это! Но вторая строка кода, использующая Topmostсвойство, является плохой практикой, поскольку она может скрывать другие всплывающие диалоги и вести себя неожиданно.
Джонатан Перри

3
На самом деле это можно сделать следующим образом: как if (myWindow.WindowState == WindowState.Minimized) myWindow.WindowState = WindowState.Normal;ни странно, он также сохранит все развернутые окна и не вернет их в нормальное состояние.
r41n

168

Я нашел решение, которое выводит окно наверх, но оно ведет себя как обычное окно:

if (!Window.IsVisible)
{
    Window.Show();
}

if (Window.WindowState == WindowState.Minimized)
{
    Window.WindowState = WindowState.Normal;
}

Window.Activate();
Window.Topmost = true;  // important
Window.Topmost = false; // important
Window.Focus();         // important

1
Отличный намек! TopMost делает волшебство в Windows 7, если окно уже открыто, но ниже других окон.
gsb

Это тоже помогло мне. Спасибо gsb за дополнительный комментарий о том, как выглядит странное использование TopMost!
Джен

1
Спасибо - исправление было коротким и сладким.
code4life

2
В моем случае было достаточно Window.Activate () и Window.Focus (). Установка Window.TopMost не нужна.
яростный

6
Не используйте Window.Focus(). Это отвлечет внимание от того, что пользователь в настоящее время печатает в текстовом поле, что безумно расстраивает конечных пользователей. Приведенный выше код прекрасно работает без него.
Контанго

32

Если вам нужно, чтобы окно было впереди при первой загрузке, используйте следующее:

private void Window_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
}

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}

1
Если вы разрабатываете что-то похожее на Launchy ( launchy.net ) в C #, вы должны заметить, что этот ответ почти бесполезен.
Лекс Ли

21

Чтобы сделать это быстро копировать-вставить -
используйте этот DoOnProcessметод класса « метод для перемещения процесса» на передний план (но не для того, чтобы украсть фокус из других окон)

public class MoveToForeground
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);

    const int SWP_NOMOVE        = 0x0002;
    const int SWP_NOSIZE        = 0x0001;            
    const int SWP_SHOWWINDOW    = 0x0040;
    const int SWP_NOACTIVATE    = 0x0010;
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

    public static void DoOnProcess(string processName)
    {
        var allProcs = Process.GetProcessesByName(processName);
        if (allProcs.Length > 0)
        {
            Process proc = allProcs[0];
            int hWnd = FindWindow(null, proc.MainWindowTitle.ToString());
            // Change behavior by settings the wFlags params. See http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
            SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
        }
    }
}

НТН


6
+1 это единственный ответ, который мне пригодился. У меня есть приложение с одним ведущим и несколькими плавающими ведомыми окнами. После активации любого из них все остальные окна также должны быть выведены на передний план. Но не активировать / получить фокус, как подсказывает большинство ответов: это катастрофа, поскольку в этом случае окно, в котором щелкают в данный момент, нельзя щелкнуть, поскольку внезапно другое окно получает фокус.
Стийн

Любая причина не использовать process.MainWindowHandle?
Шрирам Шактивель

В моем случае я не хотел главное окно, но согласился, есть другие способы получить hWnd. FWIW HwndSourceобъект работал хорошо.
августа

21

Я знаю, что этот вопрос довольно старый, но я только столкнулся с этим точным сценарием и хотел поделиться решением, которое я реализовал.

Как упоминалось в комментариях на этой странице, некоторые из предложенных решений не работают на XP, которую я должен поддерживать в моем сценарии. Хотя я согласен с мнением @Matthew Xavier о том, что, как правило, это плохая практика UX, бывают случаи, когда это полностью правдоподобный UX.

Решение поднять окно WPF наверх было фактически предоставлено мне тем же кодом, который я использую для предоставления глобальной горячей клавиши. Статья в блоге Джозефа Куни содержит ссылку на примеры кода. которая содержит оригинальный код.

Я немного очистил и изменил код и реализовал его как метод расширения для System.Windows.Window. Я проверил это на XP 32-битной и Win7 64-битной, оба из которых работают правильно.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace System.Windows
{
    public static class SystemWindows
    {
        #region Constants

        const UInt32 SWP_NOSIZE = 0x0001;
        const UInt32 SWP_NOMOVE = 0x0002;
        const UInt32 SWP_SHOWWINDOW = 0x0040;

        #endregion

        /// <summary>
        /// Activate a window from anywhere by attaching to the foreground window
        /// </summary>
        public static void GlobalActivate(this Window w)
        {
            //Get the process ID for this window's thread
            var interopHelper = new WindowInteropHelper(w);
            var thisWindowThreadId = GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);

            //Get the process ID for the foreground window's thread
            var currentForegroundWindow = GetForegroundWindow();
            var currentForegroundWindowThreadId = GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);

            //Attach this window's thread to the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            //Set the window position
            SetWindowPos(interopHelper.Handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

            //Detach this window's thread from the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            //Show and activate the window
            if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
            w.Show();
            w.Activate();
        }

        #region Imports

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        [DllImport("user32.dll")]
        private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        #endregion
    }
}

Я надеюсь, что этот код поможет другим, кто столкнулся с этой проблемой.


Эй, смотри, там! Я боролся с этим в течение нескольких месяцев! Это работает для обеих моих ситуаций. Потрясающие! (Windows 7 x64)
mdiehl13

На самом деле, кажется, что это работает, только если я делаю это: App.mainWindow.Show (); SystemWindows.GlobalActivate (App.mainwindow); // Когда я удаляю первый .show (), он не
выводится

+1 для SetWindowPos (), я искал способ только вывести свое окно на передний план, не прерывая другие приложения и не крадя фокус. this.Activate () крадет фокус.
prettyvoid

Это сделало это для меня, и в моем случае весь смысл состоял в том, чтобы украсть фокус, как это случилось, когда пользователь взаимодействовал с определенным элементом. Так что спасибо большое, это, кажется, работает последовательно! только звонки, this.Activate()кажется, работают несколько раз.
Питер

13

Если пользователь взаимодействует с другим приложением, может оказаться невозможным вывести ваше приложение вперед. Как правило, процесс может ожидать установки окна переднего плана, только если этот процесс уже является процессом переднего плана. (Microsoft документирует ограничения в записи SetDNoregroundWindow () MSDN.) Это потому, что:

  1. Пользователь «владеет» передним планом. Например, было бы очень неприятно, если другая программа украла передний план, пока пользователь печатал, по крайней мере прерывая его рабочий процесс, и, возможно, вызывала непреднамеренные последствия, так как ее нажатия клавиш, предназначенные для одного приложения, были неверно истолкованы нарушителем, пока она не заметила изменение ,
  2. Представьте, что каждая из двух программ проверяет, является ли ее окно передним планом, и пытается установить его на передний план, если это не так. Как только запускается вторая программа, компьютер становится бесполезным, так как передний план отскакивает между ними при каждом переключении задач.

Хорошая точка зрения. Цель кода была в сочетании с глобальной горячей клавишей, и другие приложения так или иначе делают это.
Фактор Мистик

Приходится использовать PInvoke в C # для эмуляции того, что описано в этой статье, codeproject.com/Tips/76427/…
Лекс Ли,

тогда почему всплывающие диалоги с ошибками в выражениях остаются видимыми, когда я иногда переключаюсь в visual studio? : - /
Simon_Weaver

Саймон, я подозреваю, что всплывающие окна с ошибками, которые вы видите, являются «самыми верхними» окнами (дизайнерское решение, которое я не одобряю). Существует разница между окном переднего плана (которое принимает пользовательский ввод) и «самым верхним» окном в Z-порядке. Любое окно может сделать себя «самым верхним», что помещает его поверх всех не верхних окон, но не дает фокусировке оконной клавиатуры и т. Д. Способ, которым становится окно переднего плана.
Мэтью Ксавье

Трюк не работает для нескольких специальных окон. В окнах Visual Studio и командной строки должно быть что-то, что не позволяет другим окнам становиться окнами переднего плана.
Лекс Ли

9

Я знаю, что это поздний ответ, может быть полезным для исследователей

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }

9

Почему некоторые ответы на этой странице неверны!

  • Любой ответ, который использует window.Focus()неверно.

    • Зачем? Если появится всплывающее сообщение с уведомлением, оно window.Focus()будет отвлекать внимание от всего, что пользователь печатает в данный момент. Это безумно расстраивает конечных пользователей, особенно если всплывающие окна появляются довольно часто.
  • Любой ответ, который использует window.Activate()неверно.

    • Зачем? Это также сделает видимыми любые родительские окна.
  • Любой ответ, который пропущен, window.ShowActivated = falseявляется неправильным.
    • Зачем? Когда выскочит сообщение, оно будет отвлекать внимание от другого окна, что очень раздражает!
  • Любой ответ, который не использует Visibility.Visible чтобы скрыть / показать окно, является неправильным.
    • Зачем? Если мы используем Citrix, если окно не свернуто, когда оно закрыто, оно оставит странную черную прямоугольную задержку на экране. Таким образом, мы не можем использовать window.Show()и window.Hide().

По существу:

  • Окно не должно захватывать фокус от любого другого окна, когда оно активируется;
  • Окно не должно активировать своего родителя, когда оно показано;
  • Окно должно быть совместимо с Citrix.

MVVM Solution

Этот код на 100% совместим с Citrix (нет пустых областей экрана). Он протестирован как с обычным WPF, так и с DevExpress.

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

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

XAML - Присоединенное свойство

Добавьте это прикрепленное свойство к любому в UserControlпределах окна. Прикрепленное имущество будет:

  • Подождите, пока Loadedсобытие не будет запущено (в противном случае оно не может найти визуальное дерево, чтобы найти родительское окно).
  • Добавьте обработчик событий, который гарантирует, что окно является видимым или нет.

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

<UserControl x:Class="..."
         ...
         attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
             "{Binding EnsureWindowInForeground, Mode=OneWay}">

C # - вспомогательный метод

public static class HideAndShowWindowHelper
{
    /// <summary>
    ///     Intent: Ensure that small notification window is on top of other windows.
    /// </summary>
    /// <param name="window"></param>
    public static void ShiftWindowIntoForeground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Visible)
            {
                window.Visibility = Visibility.Visible;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = true;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }

    /// <summary>
    ///     Intent: Ensure that small notification window can be hidden by other windows.
    /// </summary>
    /// <param name="window"></param>
    public static void ShiftWindowIntoBackground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Collapsed)
            {
                window.Visibility = Visibility.Collapsed;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = false;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }
}

использование

Чтобы использовать это, вам нужно создать окно в вашей ViewModel:

private ToastView _toastViewWindow;
private void ShowWindow()
{
    if (_toastViewWindow == null)
    {
        _toastViewWindow = new ToastView();
        _dialogService.Show<ToastView>(this, this, _toastViewWindow, true);
    }
    ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow);
    HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow);
}

private void HideWindow()
{
    if (_toastViewWindow != null)
    {
        HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow);
    }
}

Дополнительные ссылки

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


5
«Код уровня предприятия» и несколькими строками позже catch (Exception) { }. Да, верно ... И он использует код, который даже не показан в ответе, как _dialogServiceили ShiftWindowOntoScreenHelper. Плюс просьба создать окно на стороне модели представления (которое в основном нарушает весь шаблон MVVM) ...
Kryptos

@Kryptos Это код уровня предприятия. Я напечатал это из памяти, и эта точная техника используется в большой компании FTSE100. Реальная жизнь несколько менее чиста по сравнению с идеальными моделями дизайна, к которым мы все стремимся.
Контанго

Мне не нравится тот факт, что мы сами храним экземпляр окна в модели представления, как отметил Криптос, который ломает весь смысл mvvm, возможно, это можно было бы сделать в codebehind вместо этого?
Игорь

1
@ Игорь Месарос Согласен. Теперь, когда у меня есть больше опыта, если бы мне пришлось делать это снова, я бы добавил Поведение и управлял им, используя объект Func<>, связанный с ViewModel.
контанго

7

У меня была похожая проблема с приложением WPF, которое вызывается из приложения Access через объект Shell.

Мое решение ниже - работает в XP и Win7 x64 с приложением, скомпилированным для цели x86.

Я бы предпочел сделать это, чем симулировать alt-tab.

void Window_Loaded(object sender, RoutedEventArgs e)
{
    // make sure the window is normal or maximised
    // this was the core of the problem for me;
    // even though the default was "Normal", starting it via shell minimised it
    this.WindowState = WindowState.Normal;

    // only required for some scenarios
    this.Activate();
}

4

Ну, так как это такая горячая тема ... вот что работает для меня. Я получил ошибки, если я не сделал это таким образом, потому что Activate () выдаст ошибку, если вы не видите окно.

Xaml:

<Window .... 
        Topmost="True" 
        .... 
        ContentRendered="mainWindow_ContentRendered"> .... </Window>

CodeBehind:

private void mainWindow_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
    this.Activate();
    _UsernameTextBox.Focus();
}

Для меня это был единственный способ заставить окно показывать сверху. Затем активируйте его, чтобы вы могли ввести текст в поле без необходимости фокусировки мышью. control.Focus () не будет работать, если окно не Active ();


2

Ну, я разобрался. Я звоню с помощью клавиатуры, используемой для реализации горячей клавиши. Вызов работает, как и ожидалось, если я поместил его в BackgroundWorker с паузой. Это клудж, но я понятия не имею, почему он изначально не работал.

void hotkey_execute()
{
    IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
    BackgroundWorker bg = new BackgroundWorker();
    bg.DoWork += new DoWorkEventHandler(delegate
        {
            Thread.Sleep(10);
            SwitchToThisWindow(handle, true);
        });
    bg.RunWorkerAsync();
}

Просто интересно: пробовали ли вы Window.Activate (как предложено Мортеном) и другие предложения? Они кажутся менее хакерскими, чем этот допущенный клудж.
Саймон Д.

Это было довольно давно, но да, в то время, когда я это пробовал
Factor Mystic

Это не работает на моей Windows XP. Я рекомендую ответ @Matthew Xavier.
Лекс Ли

2

Чтобы показать ЛЮБОЕ открытое окно, импортируйте эти DLL:

public partial class Form1 : Form
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);
    [DllImportAttribute("User32.dll")]
    private static extern int SetForegroundWindow(int hWnd);

и в программе Мы ищем приложение с указанным названием (напишите название без первой буквы (индекс> 0))

  foreach (Process proc in Process.GetProcesses())
                {
                    tx = proc.MainWindowTitle.ToString();
                    if (tx.IndexOf("Title of Your app WITHOUT FIRST LETTER") > 0)
                    {
                        tx = proc.MainWindowTitle;
                        hWnd = proc.Handle.ToInt32(); break;
                    }
                }
                hWnd = FindWindow(null, tx);
                if (hWnd > 0)
                {
                    SetForegroundWindow(hWnd);
                }

"Название вашего приложения БЕЗ ПЕРВОГО ПИСЬМА" Оф, хаки хаки хаки. Почему бы не использовать IndexOfправильно, вместо этого?
Гонки

1

Проблема может заключаться в том, что поток, вызывающий ваш код из ловушки, не был инициализирован во время выполнения, поэтому вызов методов во время выполнения не работает.

Возможно, вы могли бы попытаться выполнить Invoke, чтобы направить ваш код в поток пользовательского интерфейса, чтобы вызвать ваш код, который выводит окно на передний план.


1

Эти коды будут работать нормально все время.

Сначала установите активированный обработчик событий в XAML:

Activated="Window_Activated"

Добавьте строку ниже в свой блок конструктора главного окна:

public MainWindow()
{
    InitializeComponent();
    this.LocationChanged += (sender, e) => this.Window_Activated(sender, e);
}

А внутри активированного обработчика событий скопируйте эти коды:

private void Window_Activated(object sender, EventArgs e)
{
    if (Application.Current.Windows.Count > 1)
    {
        foreach (Window win in Application.Current.Windows)
            try
            {
                if (!win.Equals(this))
                {
                    if (!win.IsVisible)
                    {
                        win.ShowDialog();
                    }

                    if (win.WindowState == WindowState.Minimized)
                    {
                        win.WindowState = WindowState.Normal;
                    }

                    win.Activate();
                    win.Topmost = true;
                    win.Topmost = false;
                    win.Focus();
                }
            }
            catch { }
    }
    else
        this.Focus();
}

Эти шаги будут хорошо работать и перенесут все остальные окна в окно их родителей.


0

Если вы пытаетесь скрыть окно, например, вы минимизируете окно, я обнаружил, что с помощью

    this.Hide();

будет скрывать это правильно, а затем просто используя

    this.Show();

затем снова покажет окно как самый верхний элемент.


0

Просто хотел добавить другое решение этого вопроса. Эта реализация работает для моего сценария, где CaliBurn отвечает за отображение главного окна.

protected override void OnStartup(object sender, StartupEventArgs e)
{
    DisplayRootViewFor<IMainWindowViewModel>();

    Application.MainWindow.Topmost = true;
    Application.MainWindow.Activate();
    Application.MainWindow.Activated += OnMainWindowActivated;
}

private static void OnMainWindowActivated(object sender, EventArgs e)
{
    var window = sender as Window;
    if (window != null)
    {
        window.Activated -= OnMainWindowActivated;
        window.Topmost = false;
        window.Focus();
    }
}

0

Не забудьте не помещать код, который показывает это окно, в обработчик PreviewMouseDoubleClick, так как активное окно переключится обратно на окно, обработавшее событие. Просто поместите его в обработчик событий MouseDoubleClick или прекратите пузыриться, установив для e.Handled значение True.

В моем случае я обрабатывал PreviewMouseDoubleClick для Listview и не устанавливал e.Handled = true, тогда он вызывал событие MouseDoubleClick, которое снова фокусировалось на исходном окне.


-1

Я создал метод расширения, чтобы облегчить повторное использование.

using System.Windows.Forms;
    namespace YourNamespace{
        public static class WindowsFormExtensions {
            public static void PutOnTop(this Form form) {
                form.Show();
                form.Activate();
            }// END PutOnTop()       
        }// END class
    }// END namespace

Позвоните в форму конструктора

namespace YourNamespace{
       public partial class FormName : Form {
       public FormName(){
            this.PutOnTop();
            InitalizeComponents();
        }// END Constructor
    } // END Form            
}// END namespace

Привет Майк. Вы отвечаете на этот вопрос довольно поздно. Можете ли вы объяснить в своем ответе, почему этот подход отличается (и, возможно, лучше) от очень хороших ответов, которые уже были опубликованы на этот вопрос?
Ноэль Видмер

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

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

2
Этот вопрос был конкретно о WPF, но ваше решение для WinForms.
Брайан
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.