AX Agent 창 드래그 성능 개선 및 레이아웃 재계산 지연 처리
Some checks failed
Release Gate / gate (push) Has been cancelled

- ChatWindow에 WM_ENTERSIZEMOVE/WM_EXITSIZEMOVE 감지를 추가해 창 이동·리사이즈 루프를 별도로 관리함
- 이동 중에는 루트 visual을 BitmapCache로 전환하고 무거운 transcript/layout 재계산을 지연시켜 드래그 버벅임을 줄임
- SizeChanged에서 주제 스크롤/반응형 레이아웃/메시지 재렌더를 즉시 수행하지 않고 종료 시 한 번만 반영하도록 정리함
- README와 DEVELOPMENT 문서에 변경 목적과 검증 결과를 로컬 시각 기준으로 기록함
- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ (경고 0, 오류 0)
This commit is contained in:
2026-04-06 15:28:29 +09:00
parent 421a2c97f9
commit d45698d397
3 changed files with 63 additions and 0 deletions

View File

@@ -35,6 +35,9 @@ public partial class ChatWindow : Window
private bool _isStreaming;
private bool _sidebarVisible = true;
private double _sidebarExpandedWidth = 262;
private bool _isInWindowMoveSizeLoop;
private bool _pendingResponsiveLayoutRefresh;
private CacheMode? _cachedRootCacheModeBeforeMove;
private string _selectedCategory = ""; // "" = 전체
private readonly Dictionary<string, string> _tabSelectedCategory = new(StringComparer.OrdinalIgnoreCase)
{
@@ -274,6 +277,9 @@ public partial class ChatWindow : Window
KeyDown += ChatWindow_KeyDown;
MouseMove += (_, _) =>
{
if (_isInWindowMoveSizeLoop)
return;
if (TokenUsagePopup?.IsOpen == true)
CloseTokenUsagePopupIfIdle();
};
@@ -389,6 +395,12 @@ public partial class ChatWindow : Window
};
SizeChanged += (_, _) =>
{
if (_isInWindowMoveSizeLoop)
{
_pendingResponsiveLayoutRefresh = true;
return;
}
UpdateTopicPresetScrollMode();
if (UpdateResponsiveChatLayout())
RenderMessages(preserveViewport: true);
@@ -1067,6 +1079,15 @@ public partial class ChatWindow : Window
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 0x0231) // WM_ENTERSIZEMOVE
{
BeginWindowMoveSizeLoop();
}
else if (msg == 0x0232) // WM_EXITSIZEMOVE
{
EndWindowMoveSizeLoop();
}
// WM_GETMINMAXINFO — 최대화 시 작업 표시줄 영역 확보
if (msg == 0x0024)
{
@@ -1087,6 +1108,42 @@ public partial class ChatWindow : Window
return IntPtr.Zero;
}
private void BeginWindowMoveSizeLoop()
{
if (_isInWindowMoveSizeLoop)
return;
_isInWindowMoveSizeLoop = true;
_pendingResponsiveLayoutRefresh = false;
if (Content is UIElement rootElement)
{
_cachedRootCacheModeBeforeMove = rootElement.CacheMode;
rootElement.CacheMode = new BitmapCache();
}
}
private void EndWindowMoveSizeLoop()
{
if (!_isInWindowMoveSizeLoop)
return;
_isInWindowMoveSizeLoop = false;
if (Content is UIElement rootElement)
rootElement.CacheMode = _cachedRootCacheModeBeforeMove;
_cachedRootCacheModeBeforeMove = null;
if (_pendingResponsiveLayoutRefresh)
{
_pendingResponsiveLayoutRefresh = false;
UpdateTopicPresetScrollMode();
if (UpdateResponsiveChatLayout())
RenderMessages(preserveViewport: true);
}
}
private void BtnMinimize_Click(object sender, RoutedEventArgs e) => WindowState = WindowState.Minimized;
private void BtnMaximize_Click(object sender, RoutedEventArgs e)
{