Ответ 1
Если вы прочитаете пост Раймонда Чена, вы, вероятно, найдете его таким же раздражающим, как я. Вы только "возможно, что-то не так", потому что вы делаете то, на что не способен Windows.
В моем приложении при первом посещении пользователем страницы вкладки я создаю и размещаю все элементы управления на этой странице. Это занимает заметное количество времени - на странице может легко быть 50 элементов управления. Поэтому я не отбрасываю элементы управления на закладке после ее заполнения, если это вообще возможно, и оставляю закрытие наборов страниц вкладок до пользователя.
Как это бывает, некоторые пользователи никогда не хотят закрывать какие-либо наборы страниц вкладок. Почему я должен их заставлять? С моим пользовательским интерфейсом они могут быстро перемещаться к любому из 300 + наборов транзакций, за которые они отвечают за управление. Их машины достаточно быстры, и у них достаточно памяти, чтобы сделать это очень отзывчивым. Единственная проблема заключается в том, что Windows не может ее поддерживать.
Почему я использую элементы управления, а не некоторые другие технологии пользовательского интерфейса? Потому что они работают. Мне нужно поддерживать фокусные события, порядок табуляции, события проверки, динамическую компоновку и привязку данных - пользователи фактически управляют тысячами записей в десятках таблиц в DataSet в памяти. Объем разработки, который я должен был бы сделать - скажем - реализовать что-то, используя элементы управления без окон, является астрономическим.
Я только "делаю это неправильно", потому что 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. Затем я проверяю, не работает ли я на окнах. Если да, я отбрасываю элементы управления на странице с последними используемыми закладками и продолжаю делать это, пока у меня не будет достаточно оконных дескрипторов снова.