Получить дескриптор окна в библиотеке классов WinUI3

Я пытаюсь использовать PrintManager в проекте библиотеки классов WinUI3. Но с WinUI в настоящее время мы можем использовать PrintManager только в том случае, если у нас есть дескриптор окна (HWND), в отличие от UWP, где мы могли бы просто использовать ForCurrentView() без каких-либо параметров.

Вот что-то похожее (разница в том, что они вызывают сам PrintManager в проекте UI, а не другую библиотеку классов) https://github.com/marb2000/PrintSample. В этом мы получаем HWND, используя приведенный ниже API:

var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);

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

Можем ли мы получить дескриптор Windows в библиотеке классов, не внедряя его из кода пользовательского интерфейса, который будет использовать библиотеку?

В приложении WinUI3 (или настольном приложении) у вас может быть несколько окон, поэтому вам придется каким-то образом передать окно, поскольку больше нет концепции «текущего» окна/представления. Например stackoverflow.com/a/71440820/403671

Simon Mourier 01.11.2022 17:27

Какой дескриптор окна вы хотите получить в своей библиотеке классов? Мы можем вызывать API-интерфейсы взаимодействия из приложения .NET. Это полезно?

YangXiaoPo-MSFT 02.11.2022 02:55

Спасибо, @SimonMourier. Это отвечает на мой вопрос. Не могли бы вы создать ответ, и я могу отметить его как правильный :)

Shantanu Methikar 02.11.2022 07:23

@YangXiaoPo-MSFT, это не сработает, поскольку у меня нет объекта Window в библиотеке классов (который в примере передается как параметр this), поскольку Window будет создано в проекте, использующем мою библиотеку.

Shantanu Methikar 02.11.2022 07:23

Будете ли вы использовать тип проекта «Библиотека классов (WinUI 3 на рабочем столе)» для расположения вашего класса «PrintManager»? В этом типе проекта можно было бы использовать типы, связанные с пользовательским интерфейсом, такие как «Окно».

Martin 03.11.2022 12:57

@Martin, да, я бы использовал «Библиотеку классов (WinUI 3 на рабочем столе)», но моя библиотека не будет отвечать за создание окна приложения. Итак, несмотря на то, что тип Window доступен, мне нужно получить текущее окно приложения. Так что, если это возможно, я хотел бы знать, что ..

Shantanu Methikar 03.11.2022 13:09

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

Martin 03.11.2022 13:25

Вы можете предоставить экземпляр главного окна в своем классе «Приложение» как статическое общедоступное свойство, например: stackoverflow.com/a/73110313/4424024 Затем вы можете получить к нему доступ, используя класс App везде в вашем основном проекте. И затем вы можете использовать этот экземпляр при вызове проекта библиотеки пользовательского интерфейса. Например. HelperFromLibrary.MethodThatUsesWindow(App.MainWindow).

Martin 03.11.2022 13:32

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

Shantanu Methikar 03.11.2022 15:23
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
125
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В приложении WinUI3 (или, в более общем смысле, в настольном приложении Windows) у вас может быть несколько окон, в отличие от UWP, где у вас может быть только одно окно.

Вот почему больше нет концепции «текущего» окна/представления.

Итак, вы должны передать Window (или его дескриптор напрямую) своим функциям, например, что-то вроде этого Как получить дескриптор окна текущего WinUI 3 MainWindow со страницы во фрейме в элементе управления NavigationView в MainWindow

Другое решение, если вы уверены, например, что есть только одно окно, состоит в том, чтобы получить его дескриптор, просмотрев список окон для текущего процесса (вы также можете фильтровать по текущему потоку и т. д.). Вот некоторый код C# с вызовами взаимодействия, который делает это:

// get all windows in the process  
var tops = Win32Window.GetProcessWindows();

// get the first WinUI3 window, its class name is fixed as far as we know
var firstWinUI3 = tops.FirstOrDefault(w => w.ClassName == "WinUIDesktopWin32WindowClass");

// utility class that wraps a win32 window
public class Win32Window
{
    public Win32Window(IntPtr handle)
    {
        Handle = handle;
        ThreadId = GetWindowThreadProcessId(handle, out var processId);
        ProcessId = processId;
    }

    public IntPtr Handle { get; }
    public int ThreadId { get; }
    public int ProcessId { get; }
    public string ClassName => GetClassName(Handle);
    public string Text => GetWindowText(Handle);
    public bool IsEnabled => IsWindowEnabled(Handle);

    public override string ToString()
    {
        var s = ClassName;
        var text = Text;
        if (text != null)
        {
            s += " '" + text + "'";
        }
        return s;
    }

    public static IReadOnlyList<Win32Window> GetTopLevelWindows()
    {
        var list = new List<Win32Window>();
        EnumWindows((h, l) =>
        {
            list.Add(new Win32Window(h));
            return true;
        }, IntPtr.Zero);
        return list.AsReadOnly();
    }

    public static IReadOnlyList<Win32Window> GetProcessWindows()
    {
        var process = Process.GetCurrentProcess();
        var list = new List<Win32Window>();
        EnumWindows((h, l) =>
        {
            var window = new Win32Window(h);
            if (window.ProcessId == process.Id)
            {
                list.Add(window);
            }
            return true;
        }, IntPtr.Zero);
        return list.AsReadOnly();
    }

    private static string GetWindowText(IntPtr hwnd)
    {
        var sb = new StringBuilder(1024);
        GetWindowText(hwnd, sb, sb.Capacity - 1);
        return sb.ToString();
    }

    private static string GetClassName(IntPtr hwnd)
    {
        var sb = new StringBuilder(256);
        GetClassName(hwnd, sb, sb.Capacity - 1);
        return sb.ToString();
    }

    private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);

    [DllImport("user32", SetLastError = true)]
    private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

    [DllImport("user32")]
    private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);

    [DllImport("user32")]
    public static extern bool IsWindowEnabled(IntPtr hwnd);

    [DllImport("user32", CharSet = CharSet.Unicode)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

    [DllImport("user32", CharSet = CharSet.Unicode)]
    public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
}

Другие вопросы по теме