Windows에 대한 관심이 짙어져서 정리한 것을 기록합니다.
WinUI3, Windows SDK, Windows App SDK 차이점
Windows SDK와 Windows App SDK는 다르다.
이 문서에서 설명하고 있다.
또한, Windows App SDK의 기능 중 한 가지로 WinUI3가 포함된 것 같다.
따라서, WPF에서 Windows App SDK를 참조하면 WinUI3를 사용할 수 있다.
다만 Windows App SDK는 Windows 10 1809 빌드 이상에서만 사용할 수 있으므로, 당연하게도 Windows App SDK를 사용한 WPF Windows Application은 Windows 7, Vista, XP 같은데서 실행할 수 없다. (확실한가?)
그럼 WPF만 쓰면되지 Windows App SDK는 왜 쓰는가?
WPF에서 UWP의 기능을 가져다 쓰는 것과 같은 이유라고 생각한다.
WPF는 .NET 개발자들 사이에서 완성도가 높은 구조적인 우수한 기술로 불리지만, 최대의 단점은 시기를 잘못타서 Web개발로 개발 패러다임이 변화하는 시점에 탄생하여, 참고할만한 이론적인 자료 및 공개된 리소스가 적다는 것이다.
그래서 WPF에서 UI적으로 우수한 디자인, 신박한 기능을 사용하기 위해서는 CustomControl을 이용해서 한땀한땀 장인 정신을 가지고 구현해야한다.
디자인 공수를 줄이고 적당히 어느정도 이쁘게 만들고 싶을 때 사용하는 대표적인 WPF UI 테마 라이브러리 3대장은,
가 있다. 하지만 위 라이브러리들을 써본 WPF 개발자들은 대부분 말하지만 치명적이지는 않아도 UI 잔버그 가 있다. 그래서 위 3가지를 쓰는 것을 선호하지 않는 WPF 개발자도 꽤 많다.
그래서 말인데 WPF는 UWP의 컨트롤과 WinUI3 의 Control 들을 가져다 사용할 수 있다.
개인적으로 Windows Forms에서 WPF로 넘어오면서 가장 망설여지는 것 중 하나는 UI Component의 빈약한 지원일 것 같다.
Windows Forms에서는 UI 커스터마이징이 불편한 대신 Microsoft에서 기본 컨트롤을 아주 많이 지원해준다.
기본 컨트롤이 못생겼어도 일단은 위지윅처럼 마우스로 끌어다가 쉽게 디자인이 가능하다.
하지만 WPF는 위지윅처럼 마우스로 끌어다가 쓸 수 있는 것은 같아도, XAML의 도입으로 직접 화려한 디자인을 할 수 있도록 구성되었기 때문에 Windows Forms처럼 기본 컨트롤이 많이 없다.
이럴 때 UWP의 컨트롤이나 WinUI3의 컨트롤을 가져다가 사용하면 현재 Windows의 테마와 일치하는 현대적인 Windows Application을 개발할 수 있다.
Carousel 같은 이쁜 회전목마 컨트롤도 한땀한땀 구현하거나 DevExpress같은 서드파티 기술을 구매해야 하지만 문서 처럼 UWP에 이미 구현되어 있으므로 그냥 사용할 수 있는 것 같다.
WinUI3를 사용하기 위한 Windows App SDK는 아직 태어난지 얼마 안되었고, 얼마 안되는 레퍼런스이지만 WinRT를 사용한 UWP의 자료들이 더 많으므로, WPF에서 WinRT, UWP의 레퍼런스를 찾아보고 원하는 기술을 사용하면서 그것들을 똑같이 Windows App SDK와 WinUI3로 바꿔보면 연습이 될 것 같다.
탐구과제
-
WPF에서 UWP 기술을 사용할 수 있는 XAML Islands 기술에 대해서 연구해볼 것.
-
실제로 언급된 3대장 UI 테마 라이브러리들만큼 사용하기 쉽게 되어있는지 WPF에서 UWP 및 WinUI3 컨트롤을 사용해 볼 것.
Windows 10 이상의 환경에서 UI 프로세스 미러링을 할 일이 있어서 자료를 찾아봤다.
가장 쉬운 접근은 전통적인 방식인 Timer를 이용해서 Win32 API를 이용해서 Window Handle을 따와서 프로세스의 UI 영역을 일정 간격으로 Capture 하는 것이다.
이 방법은 직관적이고 쉽지만 타이머 주기만큼 부자연스럽게 보이기 때문에 더 나은 방법을 원했고, WPF에서 DirectX 기술과 UWP 기술을 이용해서 미러링하는 Microsoft의 예제를 찾았다.
위의 예제를 실행해서 Button을 이용하던지 Combobox를 이용하던지 Window Handle이 존재하는 UI Process를 선택하면 프로세스의 화면이 출력된다.
DirectX를 써서 그런건지 반응속도도 아주 우수하다.
하지만 위 예제를 들여다보면 다른 프로세스의 화면을 렌더링 해주는 부분이 그냥
<Grid Grid.Column="1">
<Rectangle Fill="WhiteSmoke" />
</Grid>
이렇게 되어있다.
WPF에서는 UI Element에 엑세스하기 위해서는 x:Name을 지정해야하는데 이름도 없고, 특정 포지션에 출력하라는 코드도 찾을 수 없었다.
Snoop을 이용해서 위 소스를 UI 디버깅 했더니, 역시 다른 프로세스를 이용해서 Rendering 하는 부분이 전혀 탐지되지 않았다.
다만 예측할 수 있었던 것은 Composition, Compositor 라는 Composite[합성의(형용사)]에서 파생되는 단어들이 계속 반복되고 있었고, 혹시 DirectX나 다른 것에서 만든 Image를 WPF Application에 합성(Composition)해주는 것인가 해서 Compositor를 찾아보니, 아래 문서를 찾을 수 있었다.
WPF에서 시각적 계층 사용 - Windows apps | Microsoft Learn
위 예제를 실행해도 역시 snoop으로 사각형들이 탐지되지 않는다.
그러나 2가지 의문이 생겼는데,
- Windows.UI.Composition API는 Windows App SDK???
위에서 언급한대로 Windows.UI.Composition API는 UWP 의 시각적 계층 리소스인 것인데, 아래 사진처럼 Windows App SDK의 하위 카테고리로 문서가 있다.
궁금해서 Windows App SDK에서 Composition API 있는지 찾아봤는데, Microsoft.UI.Composition API로서 동일한 이름으로 Compositor Class도 존재했다.
- 예제에서 사용하는 UWP의 UI Component인 GraphicsCapturePicker가 있는데, 이 UI는 창을 열어 둔 채로 프로세스를 종료되도 살아있다.
작업관리자를 통해 확인했을 때도 별도의 Process로 잡혔다. 그러면 서로 다른 Process라는 것인데 객체에서 리턴을 받듯이 사용할 수 있는 원리가 궁금하다.
마지막으로, 위 예제는 SharpDX라는 .NET에서 사용 가능한 DirectX 기술을 사용하고 있지만 해당 기술은 기술자의 부재 및 기여자의 부재로 readonly가 되어 legacy 기술이 되버렸다.
그래서 대안기술로 Vortice.Windows 라는 기술이 있는데 이것을 사용한 Composition은 아직 동일한 예제가 없고 Github에 Issue만 존재한다.
참고 자료
탐구 과제
-
Windows App SDK와 WinRT, UWP의 아직 모르는 포함 관계파악
-
해당 예제의 Windows.UI.Composition을 Microsoft.UI.Composition으로 변경해볼 것.
-
SharpDX를 Vortice.Windows로 바꿔볼 것.
-
GraphicsCapturePicker 객체는 어떤 원리로 별도의 프로세스로 존재할 수 있는 것인지 알아볼 것.
=> 이 문서에서 설명하는 것이 이해가 잘 안가지만, WindowsGraphicsCapture API는 Windows OS에서 관리하는 자원에 접근하기 위해 Application의 직접적인 접근이 아닌 API를 통한 접근을 유도하기 위한 목적으로 Spoof를 방지했다고 설명하는 것 같다. 따라서 OS에서 관리하는 자원이 맞다.
WPF UI를 조금씩 보고 있는데 이것은 MVVM에서 View가 ViewModel을 참조해도 된다는 입장인 듯 예제에서 보란 듯이 Page에 대해 ViewModel을 Generic으로 받는 인터페이스를 구현 중이다.
wpfui/src/Wpf.Ui/Controls/NavigationView/INavigableView.cs at main · lepoco/wpfui (github.com)
View는 ViewModel을 참조해도 되는데… 어떤 점 때문이에요?
View가 ViewModel을 참조해서는 안된다는 관점도 있기 때문에 적어 놓은 것입니다.
저도 들어가서 코드를 받아 빌드해서 실행해 보았는데
매끄럽게 잘 돌아가고 코드 또한 흥미로운(?) 코드 입니다.
대충 보았을때
<Grid Grid.Column="1">
<Rectangle Fill="WhiteSmoke" />
</Grid>
Main View에서 위 부분은 랜더링과 직접 적인 연관은 없고
그냥 캡쳐로 표시 되는 영역만 하얀색으로 표시 처리만 해주는 코드 입니다.
실제로 캡쳐된 Surface가 비주얼상 랜더링 처리되는 영역 지정은 다음 코드 같습니다.
Main Loaded 이밴트 핸들러에서
ControlsGrid 컨트롤의 Width 사이즈를 구해서
InitComposition()
메서드로 전달 하는데요
해당 메서드를 보면 WPF 최상위 부모 윈도우의 핸들을 가져와서 랜더링을 하기 위해 CompositionTarget 객체를 생성합니다.
그리고 최상위에 비주얼 트리를 붙입니다.
그 비주얼 트리의 Size와 Offset을 보면 위에서 전달 받은 ControlsGrid 컨트롤의 사이즈 음수X좌표와 위치로 지정하고 있습니다.
이후 저 비주얼트리에 계속 랜더링 하는 것으로 보여집니다.
나중에 다른 프로젝트에서 사용할 수 있을 것 같네요 !
요런 정보 감사합니다.