Если вы прочитаете пост Раймонда Чена, вы, вероятно, найдете его таким же раздражающим, как и я. Вы только «вероятно делаете что-то неправильно», потому что вы делаете то, на что не способна Windows.
В моем приложении, когда пользователь впервые посещает вкладку, я создаю и размещаю все элементы управления на этой странице. Это занимает заметное количество времени - на странице может быть 50 элементов управления. Поэтому я не сбрасываю элементы управления на вкладке после ее заполнения, если это вообще возможно, и оставляю закрытые наборы вкладок на усмотрение пользователя.
Как это бывает, некоторые пользователи никогда не хотят закрывать любые наборы вкладок. Почему я должен заставлять их? Благодаря моему пользовательскому интерфейсу они могут очень быстро переходить к любому из 300+ наборов транзакций, которыми они управляют. Их машины достаточно быстрые и имеют достаточно памяти, чтобы все это было очень отзывчивым. Единственная проблема в том, что Windows не может это поддерживать.
Почему я использую элементы управления, а не какую-то другую технологию пользовательского интерфейса? Потому что они работают . Мне нужно поддерживать события фокуса, порядок табуляции, события проверки, динамическое расположение и привязку данных - пользователи фактически управляют тысячами записей в десятках таблиц в наборе данных в памяти. Степень развития, которую я должен был бы выполнить, скажем, для реализации чего-либо с использованием элементов управления без окон, астрономическая.
Я только "делаю это неправильно", потому что Windows жестко ограничивает количество дескрипторов окон, которые она может поддерживать. Это жесткое ограничение основано на нескольких десятилетних предположениях о том, как может быть построен пользовательский интерфейс компьютера. Это не я "делаю что-то не так".
В любом случае, мое решение состоит из двух частей.
Во-первых, класс, который может сообщить вам, сколько обработчиков окна использует ваш процесс:
using System;
using System.Runtime.InteropServices;
namespace StreamWrite.Proceedings.Client
{
public class HWndCounter
{
[DllImport("kernel32.dll")]
private static extern IntPtr GetCurrentProcess();
[DllImport("user32.dll")]
private static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags);
private enum ResourceType
{
Gdi = 0,
User = 1
}
public static int GetWindowHandlesForCurrentProcess(IntPtr hWnd)
{
IntPtr processHandle = GetCurrentProcess();
uint gdiObjects = GetGuiResources(processHandle, (uint)ResourceType.Gdi);
uint userObjects = GetGuiResources(processHandle, (uint)ResourceType.User);
return Convert.ToInt32(gdiObjects + userObjects);
}
}
}
Во-вторых, я поддерживаю кеш-объект, использованный на моей странице-вкладке реже всего недавно. .NET Framework не предоставляет универсальный класс кэша LRU, поэтому я создал один, который вы можете получить здесь , если он вам нужен. Каждый раз, когда пользователь посещает вкладку, я добавляю ее в LRU Cache. Затем я проверяю, не хватает ли мне оконных ручек. Если да, я выбрасываю элементы управления на вкладке с наименее недавно использованной вкладкой и продолжаю делать это до тех пор, пока у меня не будет достаточно оконных дескрипторов.