성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - Windows Forms 응용 프로그램의 자식 컨트롤 부하</h1> <p> 아래와 같은 질문이 있군요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# 많은 Control(Label 300개) Update 관련 문의 ; <a target='tab' href='https://www.sysnet.pe.kr/3/0/5540'>https://www.sysnet.pe.kr/3/0/5540</a> </pre> <br /> 종종, Windows 응용 프로그램의 특성을 잘 모르시는 분들이 계셔서 한 번은 정리해야 할 필요가 있는 듯해서 이렇게 글을 써봅니다. ^^<br /> <br /> 우선, Window라는 자원은 다소 무거운 자원입니다. Window 하나에 <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/winmsg/about-window-procedures'>Window Procedure</a>가 붙고, 이와 함께 다소 자원 한계가 뚜렷한 GDI 리소스도 할당이 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Pushing the Limits of Windows: USER and GDI Objects – Part 1 ; <a target='tab' href='https://techcommunity.microsoft.com/t5/windows-blog-archive/pushing-the-limits-of-windows-user-and-gdi-objects-8211-part-1/ba-p/723881'>https://techcommunity.microsoft.com/t5/windows-blog-archive/pushing-the-limits-of-windows-user-and-gdi-objects-8211-part-1/ba-p/723881</a> Pushing the Limits of Windows: USER and GDI Objects – Part 2 ; <a target='tab' href='https://techcommunity.microsoft.com/t5/windows-blog-archive/pushing-the-limits-of-windows-user-and-gdi-objects-8211-part-2/ba-p/723897'>https://techcommunity.microsoft.com/t5/windows-blog-archive/pushing-the-limits-of-windows-user-and-gdi-objects-8211-part-2/ba-p/723897</a> </pre> <br /> 여기서 재미있는 점은, Window는 꼭 창 형식으로 뜨는 것뿐만 아니라 윈도우 내에서 자식 컨트롤로 생성하는 <a target='tab' href='Windows Controls'>Label, Edit나 Button 등의 컨트롤</a>들도 모두 하나의 Window라는 점입니다. 따라서, Label을 300개 만들었다는 것은 화면에 300개의 윈도우를 띄운 것이나 다름없습니다.<br /> <br /> 300개의 Label에 텍스트를 업데이트하는 것이 별다른 부하로 여겨지지 않을 듯해도, 화면에 300개의 윈도우를 띄워놓고 하나의 프로세스가 그 윈도우들에 텍스트를 업데이트해야 한다고 생각하면 좀 부담스럽지 않나요? ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> 잠시 과거를 좀 회상해 보겠습니다. ^^<br /> <br /> 예전에 Internet Explorer가 웹 페이지를 렌더링하면서 <SELECT />를 Window 컨트롤로 구현하던 것을, 단순히 그리는 것으로 바꾼 적이 있습니다. 그러니까, 원래 이렇게 나오던 SELECT가,<br /> <br /> <img alt='window_attr_0.png' src='/SysWebRes/bbs/window_attr_0.png' /><br /> <br /> IE 업데이트 이후 윈도우 영역을 벗어나면 다음과 같이 잘려 나오게 된 것입니다.<br /> <br /> <img alt='window_attr_1.png' src='/SysWebRes/bbs/window_attr_1.png' /><br /> <br /> 왜냐하면, 전자의 경우는 SELECT가 <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/controls/combo-boxes'>ComboBox 컨트롤</a>로 생성되었기 때문에 부모 윈도우 영역을 벗어나서도 보일 수 있었지만, 후자의 경우에는 윈도우 내에 Draw 함수 등을 통해 그려진 것이기 때문에 윈도우를 벗어날 수 없었던 것입니다.<br /> <br /> 결국 이 문제는, SELECT가 평소에는 그려지다가 버튼이 눌려 펼쳐질 때는 순간적으로 윈도우를 생성해 목록을 보이는 식으로 바뀌면서 해결이 되었습니다.<br /> <br /> 사실, IE가 이렇게 바꿀 수밖에 없었던 것은 점점 더 웹 페이지가 복잡해지면서 내부에 INPUT 요소가 늘어나는 것들을 전부 Window로 대체하기에는 리소스 낭비가 심했기 때문입니다.<br /> <br /> 이러한 노력은, ActiveX Control에서도 볼 수 있습니다. 일반적으로 ActiveX는 Window 자식 컨트롤로 생성되지만 이것 역시 다량으로 생성되면 리소스 부하가 발생할 수 있으므로, m_bWindowOnly 속성을 제어하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > CComControlBase::m_bWindowOnly ; <a target='tab' href='https://learn.microsoft.com/en-us/cpp/atl/reference/ccomcontrolbase-class'>https://learn.microsoft.com/en-us/cpp/atl/reference/ccomcontrolbase-class</a> </pre> <br /> 윈도우 없이 그려지는 방식으로 동작하도록 바꿀 수 있습니다. 물론, 저 속성을 단순히 바꾸는 것으로 기존의 코드가 그대로 윈도우 없는 환경에서 동작하는 것은 아닙니다. 윈도우가 없다는 이유로 내부의 코드를 바꿔야 하는 등의 꽤 까다로운 코드 변환 작업이 필요합니다. (사실, 저 역시 한창 ActiveX를 만들 때조차 단 한 번도 Windowless 컨트롤을 만들어 본 적이 없습니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그렇다면, 이것을 어떻게 해야 할지 답이 나왔군요. ^^<br /> <br /> 맞습니다. Windowless로 만들어야 합니다. 300개의 Label 컨트롤을 만들 것이 아니라, 300개의 텍스트 출력을 <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.onpaint'>OnPaint</a>에서 그릴 수 있는 단 하나의 컨트롤을 만들어 제어를 하는 것입니다.<br /> <br /> 혹은, WPF로 응용 프로그램을 바꾸는 것도 도움이 될 수 있습니다. 실제로 다음과 같이 동일한 동작을 하도록 바꿔보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded"> <Grid> <UniformGrid x:Name="grid"></UniformGrid> </Grid> </Window> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Threading; namespace WpfApp1 { public partial class MainWindow : Window { public int count; public System.Threading.Timer displayTimer; public MainWindow() { InitializeComponent(); } <span style='color: blue; font-weight: bold'>List<Label> labels = new List<Label>();</span> private void Window_Loaded(object sender, RoutedEventArgs e) { for (int i = 0; i < 300; i++) { <span style='color: blue; font-weight: bold'>Label lbl = new Label(); labels.Add(lbl); grid.Children.Add(lbl);</span> } count = 0; displayTimer = new System.Threading.Timer(Callbacktimer); displayTimer.Change(1, 500); } void Callbacktimer(object state) { <span style='color: blue; font-weight: bold'>Dispatcher.Invoke(() => labels.ForEach((lbl) => lbl.Content = count));</span> count++; } } } </pre> <br /> Label 컨트롤들이 Window가 아닌 그려지는 방식이기 때문에 부하가 좀 덜 하긴 합니다. 하지만 그래도 WPF의 DependencyProperty와 Dispatcher의 특성상 윈도우 이동 시 (Windows Forms보다는 덜하지만) 약간의 끊김 현상이 있습니다.<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1840&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
6179
(왼쪽의 숫자를 입력해야 합니다.)