Немодальные WinForms FontDialog? - PullRequest
1 голос
/ 27 мая 2010

Можно ли отображать диалоговое окно WinForms «Выбор шрифта» немодально? Или есть другой инструмент выбора шрифта, отличный от стандартного, который можно использовать немодально?

В нашем приложении много окон, и пользователям, которым часто нужно прерывать то, что они делают, и переключаться в другое окно, чтобы что-то посмотреть. Если они используют кнопку панели задач для переключения окон, это может привести к сценариям «скрытого диалога» с модальными диалогами, где пользовательский интерфейс не отвечает, но не сразу понятно почему, потому что модальный диалог, который захватил фокус, находится позади другое окно.

Ответы [ 2 ]

1 голос
/ 27 мая 2010

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

http://www.pinvoke.net/default.aspx/user32.getdesktopwindow

Один из способов установить Owner - создать собственный пользовательский класс, который наследуется от FontDialog, а затем установить владельца с помощью метода protected CommonDialog.RunDialog, но могут быть и другие. *

Редактировать: На самом деле, возможно, можно просто отправить дескриптор рабочего стола в качестве параметра ShowDialog ...

0 голосов
/ 07 июля 2010

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

К счастью, - это способ обойти эту проблему. Я использовал BackgroundWorker, чтобы перенаправить вызов на ShowDialog на рабочий поток, позволяя продолжить поток GUI. Класс оболочки async FontDialog выглядит следующим образом:

public class FontDialogAsync
{
    public event EventHandler<NewFontChosenEventArgs> NewFontChosen;

    private readonly IWin32Window parentHandle;
    private readonly BackgroundWorker fontDialogWorker = new BackgroundWorker();

    private class WindowWrapper : IWin32Window
    {
        public WindowWrapper(IntPtr hWnd)
        {
            Handle = hWnd;
        }

        public IntPtr Handle { get; private set; }
    }

    public FontDialogAsync(IWin32Window parent)
    {
        parentHandle = new WindowWrapper(parent.Handle);
        fontDialogWorker.DoWork += FontDialogWorkerDoWork;
        fontDialogWorker.RunWorkerCompleted += FontDialogWorkerRunWorkerCompleted;
    }

    private class FontDialogAsyncArgs
    {
        public readonly IWin32Window ParentForm;
        public readonly Font InitialFont;

        public FontDialogAsyncArgs(IWin32Window parent, Font initFont)
        {
            ParentForm = parent;
            InitialFont = initFont;
        }
    }

    public void Show(Font font)
    {
        if (!fontDialogWorker.IsBusy) fontDialogWorker.RunWorkerAsync(new FontDialogAsyncArgs(parentHandle, font));
    }

    private static void FontDialogWorkerDoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            var args = (FontDialogAsyncArgs)e.Argument;
            var fontDialog = new FontDialog { Font = args.InitialFont };
            var result = fontDialog.ShowDialog(args.ParentForm);
            e.Result = (result == DialogResult.Cancel) ? null : fontDialog.Font;
        }
        catch (Exception ex)
        {
            UtilitiesAndConstants.ReportExceptionToCommonLog(ex);
        }
    }

    private void FontDialogWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e1)
    {
        if (e1.Result == null) return;
        if (NewFontChosen != null) NewFontChosen(this, new NewFontChosenEventArgs((Font)e1.Result));
    }
}

[Обратите внимание, что вам нужно скрыть дескриптор родительского окна внутри экземпляра WindowWrapper, чтобы среда выполнения не вызывала исключение между потоками.]

Класс EventArgs выглядит следующим образом:

public class NewFontChosenEventArgs : EventArgs
{
    public readonly Font FontChosen;
    public NewFontChosenEventArgs(Font newFont)
    {
        FontChosen = newFont;
    }
}

... и вы используете это так:

    private FontDialogAsync nonBlockingFontDialog;
    public void SetFont() 
    {
        if (nonBlockingFontDialog == null) 
        {
            nonBlockingFontDialog = new FontDialogAsync(ParentForm);
            nonBlockingFontDialog.NewFontChosen += NonBlockingFontDialogNewFontChosen;
        }
        nonBlockingFontDialog.Show(Font);
    }

Где ParentForm - это экземпляр Windows.Form, к которому вы хотите привязать диалог. Результирующий диалог будет модальным по отношению к родителю (то есть вы не сможете ничего сделать с родителем, не отключив сначала диалог), но остальная часть пользовательского интерфейса приложения будет работать нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...