Я пытаюсь использовать 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 в библиотеке классов, не внедряя его из кода пользовательского интерфейса, который будет использовать библиотеку?
Какой дескриптор окна вы хотите получить в своей библиотеке классов? Мы можем вызывать API-интерфейсы взаимодействия из приложения .NET. Это полезно?
Спасибо, @SimonMourier. Это отвечает на мой вопрос. Не могли бы вы создать ответ, и я могу отметить его как правильный :)
@YangXiaoPo-MSFT, это не сработает, поскольку у меня нет объекта Window в библиотеке классов (который в примере передается как параметр this), поскольку Window будет создано в проекте, использующем мою библиотеку.
Будете ли вы использовать тип проекта «Библиотека классов (WinUI 3 на рабочем столе)» для расположения вашего класса «PrintManager»? В этом типе проекта можно было бы использовать типы, связанные с пользовательским интерфейсом, такие как «Окно».
@Martin, да, я бы использовал «Библиотеку классов (WinUI 3 на рабочем столе)», но моя библиотека не будет отвечать за создание окна приложения. Итак, несмотря на то, что тип Window доступен, мне нужно получить текущее окно приложения. Так что, если это возможно, я хотел бы знать, что ..
Вам нужно будет передать правильный экземпляр окна в библиотеку пользовательского интерфейса из вашего основного приложения.
Вы можете предоставить экземпляр главного окна в своем классе «Приложение» как статическое общедоступное свойство, например: stackoverflow.com/a/73110313/4424024 Затем вы можете получить к нему доступ, используя класс App везде в вашем основном проекте. И затем вы можете использовать этот экземпляр при вызове проекта библиотеки пользовательского интерфейса. Например. HelperFromLibrary.MethodThatUsesWindow(App.MainWindow).
@Martin К сожалению, в моем случае я не разрабатываю основное приложение. Я просто разрабатываю библиотеку, и люди будут строить ее поверх нее. Но я согласен с тем, что мне придется ввести правильный экземпляр окна.





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