라벨이 WPF인 게시물 표시

WPF에서 폰트 설치 없이 외부 폰트를 사용하는 방법

WPF에서 폰트 설치 없이 외부 폰트를 사용하는 방법 외부 폰트 사용: WPF 앱에서 폰트 설치 없이 사용하기 WPF(Windows Presentation Foundation) 앱 개발 중 외부 폰트를 사용해야 하는 상황이 발생할 수 있습니다. 흔한 경우는 아니지만, 특정 디자인 요구사항이나 클라이언트 요청에 따라 외부 폰트를 적용해야 할 때가 있습니다. 외부 폰트는 시스템에 기본적으로 설치되어 있지 않은 폰트를 의미하며, 앱 실행 시 폰트 설치 없이 사용할 수 있도록 하는 것이 중요합니다. 외부 폰트가 필요한 경우 대부분의 WPF 앱은 설치 파일 형태로 배포되기 때문에, 설치 과정에서 폰트를 함께 설치할 수 있습니다. 하지만, 포터블 방식으로 배포되는 앱의 경우, 관리자 권한이 없을 경우 폰트 설치가 불가능하므로 외부 폰트를 사용해야 합니다. 외부 폰트 사용 방법: 폰트 리소스 활용 외부 폰트를 사용하는 가장 효율적인 방법은 폰트 파일을 어셈블리 리소스에 포함시키는 것입니다. 이렇게 하면 폰트 설치 없이 앱 실행 시 폰트를 로드하여 사용할 수 있습니다. 1. 폰트 파일을 프로젝트에 포함: 원하는 폰트 파일(.ttf)을 WPF 프로젝트에 추가하고, 빌드 작업을 "리소스"로 설정합니다. XML <ItemGroup> <Resource Include="Fonts\내폰트.ttf" /> </ItemGroup> 2. FontFamily 속성에 폰트 로드: 컨트롤(예: TextBlock)의 FontFamily 속성에 리소스에 포함된 폰트를 로드하여 사용합니다. 이때, 주의할 점은 폰트 파일명이 아닌 실제 폰트 이름 을 사용해야 한다는 것입니다. XML <TextBlock FontFamily="Fonts/#Pretendard Variable" /> 주의 사항: 폰트 이름 확인: 폰트 파일을 탐색기...

WPF Prism에서 AutoMapper 사용하기

WPF Prism에서 AutoMapper 사용하기 AutoMapper AutoMapper는 서로 다른 두 클래스를 보다 쉽게 매핑하기 위해 사용하는 라이브러리이다. 내 경우(그리고 많은 오픈소스 프로젝트의 경우) 모델과 DTO 사이의 매핑을 손쉽게 처리하기 위해 주로 사용된다. Prism Prism 프레임워크, 또는 라이브러리 1 는 이전 포스트 에서 자세히 다룬 바 있다. 다시 간략하게 정리하자면 MVVM 기반 프로젝트 개발을 더 쉽게 할 수 있도록 도와주는 프레임워크이다. Prism에서 AutoMapper DI하기 ASP.NET 프로젝트에서 AutoMapper 사용은 정말 쉽다. 애초에 AutoMapper에서 확장 메서드를 제공하기 때문에 서비스를 구성할 때 해당 메서드를 호출하고, AutoMapper.Profile 을 상속받은 클래스를 만들어 아무 곳에다가 배치해놓은 뒤 실행하면 된다. 그러나 Prism용 확장 메서드는 자체적으로 제공되지 않으므로 직접 만들어 써야 한다. IAutoMapperProvider interface 일단 DI를 위해 사용할 인터페이스부터 구성한다. public interface IAutoMapperProvider { IMapper GetMapper ( ) ; } AutoMapperProvider class 이제 위 인터페이스를 상속한 AutoMapperProvider 클래스를 작성한다. public class AutoMapperProvider : IAutoMapperProvider { private readonly MapperConfiguration _configuration ; public AutoMapperProvider ( IContainerProvider containerProvider ) { _configuration = new MapperConfiguration ( config ...

프리즘 생산성 도구들

프리즘 생산성 도구들 생산성 도구 현재 프리즘은 Visaul Studio 및 Visual Studio Mac과 연동해 WPF, UWP, 네이티브 iOS 및 Xamarin.Forms를 사용한 Android 앱을 개발하기 위한 매우 생산적인 개발자 워크플로우를 지원한다. 코드 스니펫, 아이템 템플릿, 프로젝트 템플릿을 사용해 빠르게 프리즘 앱 제작을 시작할 수 있다. 현재 다음과 같은 도구를 사용할 수 있다. Prism Template Pack Prism Template Studio Prism Extensibility Pack Prism Template Pack 프리즘 템플릿 팩은 프리즘을 사용한 WPF 및 Xamarin.Forms 개발을 위한 여러 코드 스니펫, 아이템 템플릿 및 프로젝트 템플릿을 포함하고 있다. Snippets propp - Property, with a backing field, that depends on BindableBase private string _fieldName ; public string PropertyName { get { return _fieldName ; } set { SetProperty ( ref _fieldName , value ) ; } } cmd - Creates a DelegateCommand property with Execute method private DelegateCommand _fieldName ; public DelegateCommand CommandName = > _fieldName ? ? ( _fieldName = new DelegateCommand ( ExecuteCommandName ) ) ; void ExecuteCommandName ( ) { } c...

프리즘 프레임워크 시작하기

프리즘 프레임워크 시작하기 프리즘 다운로드 및 설치 이번 글에서는 프리즘을 다운로드하고 설치하는 방법을 의역해 옮기도록 하겠다. 전체적인 프리즘 릴리즈 노트는 깃헙 페이지 에서 확인할 수 있다. 프리즘 소스 코드 다운로드 및 셋업 프리즘 소스 코드에서 셋업을 진행하기 위해서는 다음과 같은 단계를 따른다. 시스템 요구 사항 설치 프리즘 소스 코드 및 문서 다운로드 및 압축 해제 컴파일 및 샘플 실행 1단계. 시스템 요구 사항 설치 프리즘은 윈도우 8 데스크탑, 윈도우 7, 비스타, 2008 OS에서 작동하도록 디자인되었다. 1 이 가이드에서 빌드된 WPF 앱은 .NET Framework 4.5를 필요로 한다. 1 2 프리즘 라이브러리를 사용하기 전, 다음과 같은 요구 사항이 설치되어야만 한다. .NET Framework 4.5 또는 그 이상의 버전 MS Visual Studio 2017 이상의 버전(2019 권장) 3 Prism.Forms를 사용하려면 Xamarin 워크로드가 반드시 설치되어야 함 4 2단계. 프리즘 소스 코드 및 문서 다운로드 및 압축 해제 프리즘 리포지토리 를 fork하면 손쉽게 진행할 수 있다. 샘플 코드는 다음과 같다. WPF 샘플 Xamarin.Forms 샘플 위 단계 대신 Prism 관련 NuGet 패키지 를 설치해도 된다. 3단계. 샘플 컴파일 및 실행 모든 샘플은 프리즘 NuGet 참조를 사용하므로 각 솔루션에서 직접 컴파일하고 실행할 수 있다. 문서가 구버전이라 이렇게 적혀 있으나 프리즘 8은 윈도우 10, 11을 지원하고 오히려 8.1 이하를 지원할 계획이 없다고 한다. ↩︎ ↩︎ 현재 시점의 최신 프리즘(버전 8)은 .NET 7에서도 잘 돌아간다. ↩︎ 글을 쓰는 현재 VS2022에서도 문제없이 잘 돌아간다. ↩︎ Visual Studio Installer에서 Xamarin 워크로드를 활성화하고 설치하면 된다. ↩︎ ...

WPF - 프리즘 프레임워크

WPF - 프리즘 프레임워크 C#/WPF. 불편해. Node.JS 개발을 하다 보니 WPF 개발이 참 난감해졌다. 예전에는 당연히 이 정도 기능을 코딩하려면 미리 만들어놓은 라이브러리가 없을 때 이만큼의 시간이 걸리는 건 당연하지 라고 생각했었는데, 리액트와 NextJS 등을 사용하다가 WPF 개발 쪽으로 돌아가려니 도저히 못해먹겠다 싶은 생각 뿐이었다. 아, 이건 이런 HTML 태그와 이런 CSS를 쓰면 쉽게 가능한데… 아, 저건 이러이러한 타입스크립트로 쉽게 되는데… 이런 경우가 너무 많이 생긴다는 것이다. 이럴 때 사용할 수 있는 라이브러리나 프레임워크가 있나 찾아보다가 발견하게 된 것이 프리즘이다. 일단, 아직 한 번도 프리즘을 사용해보지 않았으므로 공식 문서를 의역하면서 하나씩 알아가보고자 한다. Prism: XAML 앱용 프레임워크 프리즘은 느슨하게 결합된 관리와 테스트가 용이한 XAML 앱용 프레임워크이다. 1 프리즘을 사용하면 MVVM, DI, commands, EventAggregator 등등 여러 디자인 패턴들의 구현을 제공받게 된다. 대상 플랫폼 프리즘은 .NET Standard 및 .NET 4.5 또는 4.8 버전에서 사용할 수 있도록 크로스 컴파일되어 제공된다. 또한 WPF, Xamarin Forms, 버전 8의 경우 UNO에서 사용할 수 있다. 단, 8버전 이후로 Silverlight나 윈도우 8/8.1/윈도우 폰 8.1, UWP에 대한 지원 계획은 없다고 한다. 이 경우엔 이전 버전 을 사용하라고 권하고 있다. https://prismlibrary.com/docs/index.html ↩︎

WPF의 컨버터가 호출되지 않을 때 체크해보세요.

  제 경우에는 BoolToVisibilityConverter를 만들어서 쓰고 있었습니다. LambdaConverters 패키지를 사용해 간편하게 만들어서요.   해당 컨버터는 bool   소스의 값을 bool ConverterParameter 에 따라 Visibility 로 변경해주는 역할을 합니다.   패러미터가 true일 때엔 소스가 true 라면 Visible , 아니라면 Collapsed 를 반환하지만   패러미터가 false일 때엔 반대로 소스가 true 라면  Collapsed , 아니라면 Visible 을 반환하는 식입니다.   문제는, 이 컨버터를 사용하려 할 때에 발생했습니다. <DataGrid Binding="{IsRecordExists}", Converter="{x:Static cvt:VisibilityConverters.BoolToVisibilityConverter}", ConverterParameter=True} />   위와 같이 작성하고 테스트를 해보았으나 의도한 바와 전혀 다르게 작동하는 모습을 보였습니다.   왜 의도한 것과 다르게 작동하는지 알아보기 위해 이것 저것 테스트하다가, 컨버터의 Convert 메서드쪽에 브레이크포인트를 걸고 디버그를 돌려보니, 아예 Convert 메서드 쪽으로 진입조차 하지 않는 것을 확인하게 되었죠. 소리 없는 암살자   이건 제가 LambdaConverter 패키지를 사용해서 생긴 문제일 수도 있습니다만, 아무튼 정말 아무런 메세지도, 경고도, 에러도 없이 그냥 메서드 자체가 호출되지 않고 넘어가더군요.   이는 생각보다 심각한 문제였습니다. 에러도 없고 경고도 없어서 이것 저것 쓸데 없는 오만가지를 다 건드리다가 심지어 WPF의 버그인가? 라는 생각도 잠시 스쳐 들 정도였으니까요.   아무튼 그래서 왜 그럴까... 하고 생각하다가 문득 떠오른 것이 있었습니다. 패러미터는 기본적으로...

[WPF] x:Name 지정 없이 특정 컨트롤을 기본적으로 포커스된 상태로 설정하기

Focus   어떤 프로그램이든 사용자 경험은 중요한 부분입니다. 그중 개인적으로 기본이라고 생각하는 것이 바로 포커싱입니다. 윈도우가 부모 창의 가운데, 혹은 적절한 위치에서 팝업하는 것 부터 시작해서 핵심 컨트롤에 포커스가 맞춰지는 것까지. 사용자가 눈을 최대한 적게 굴리고, 마우스를 최대한 적게 움직이며, 키보드를 최대한 적게 입력하게 설계하는 것이 중요합니다.   Focus 설정 은, 다들 아시겠지만 텍스트박스와 같이 커서가 옮겨갈 수 있는 컨트롤에 커서를 옮겨주는 역할 을 합니다. 예를 들어서 로그인 창이 있다고 생각해보죠. 로그인 창엔 아이디, 비밀번호, 아이디 저장, 비밀번호 저장, 로그인 등의 텍스트박스 및 체크박스, 버튼이 있을 겁니다. 그럼 사용자가 로그인 창에서 처음으로 볼 곳 은 어디일까요? 아이디 텍스트 박스 죠.  그럼 여러분은 로그인 창이 떴을 때, 아이디 텍스트 박스에 포커스가 설정 되도록 해야 합니다.   물론 대부분 바로 이해하시겠지만, 이렇게 설명하면 잘 이해가 되지 않으실 분을 위해 반대로 얘기해보죠. 만약 여러분이 네이버에 로그인 화면에 접속하려고 한다고 가정해봅시다. 네이버 메인 페이지에 들어가서, 로그인 버튼을 누릅니다. 그럼 로그인 페이지로 이동하게 됩니다. 헌데 여기서 만약 기본 포커싱이 ID 텍스트 박스가 아닌 패스워드 텍스트 박스로 되어있다면? 혹은 로그인 버튼으로 되어있다면?   전자의 경우 로그인 페이지로 넘어왔으니 당연히 아이디를 입력할 수 있을 것이라 생각하고 아이디를 honjasal...까지 입력하고 뭔가 이상함을 발견하게 될 것입니다. 패스워드에 입력되고 있었던 것이죠! 그럼 여러분은 깊은 빡침을 느끼며 패스워드를 지우고 Shift-Tab 혹은 마우스 클릭으로 아이디 텍스트박스를 선택하고 다시 입력할 겁니다.   후자의 경우 아예 입력조차 안 되죠. 뭐, 차라리 지우는 수고가 덜어지니 전자보단 나을지도?   아무튼, 이래서 사...

[WPF] MenuItem Header 바인딩시 StringFormat이 작동 안 할 경우 대체 방법

StringFormat?   Binding에서 StringFormat의 지원은 .NetFramework 3.0부터 시작되었습니다. 단순이 바운드된 객체의 값을 보여줄 뿐 아니라, StringFormat 옵션을 통해 더 다양한 옵션으로 텍스트를 표시할 수 있게 되었죠. 예를 들면 아래와 같습니다. // StringFormat이 없을 때 <TextBlock Text="{Binding SomeDateTime}" /> // => DateTime이 문화권에 따라 표시됨. 예: 2018-08-20 04:23:43 // StringFormat 사용시 <TextBlock Text="{Binding SomeDateTime, StringFormat='yyyy년 MM월 dd일 HH시'}" /> // => 2018년 08월 20일 04시   이는 당연히 문자열 자체에도 사용할 수 있어서 아래와 같이 prefix 또는 suffix를 덧붙이는 작업이 가능하게 됩니다. // SomeText = "가나다라마" <TextBlock Text="{Binding SomeText, StringFormat='PREFIX {0} SUFFIX'}" /> // => PREFIX 가나다라마 SUFFIX   참 간편하죠? 문제 발생   그렇게 편하게 사용하던 중, 문제가 발생했습니다. Menu 하위의 MenuItem의 Header 속성에 IPAddress를 바인딩시켜 "현재 아이피는 {0} 입니다." 를 표시되게 하고 싶었는데, StringFormat에 굵은 글씨를 그대로 넣어도 현재 아이피만 표시될 뿐, 다른 글자가 나타나지 않는 것이었죠.   그래서 구글링을 열심히 하다가 도저히 방법이 안 보여서, 편법을 썼습니다. 그리고 편법이긴 하지만, 하자 없이 완벽하게 작동합니다. 아래를 보시죠. ...

[WPF] WPF 창에 투명도를 적용하는 방법

  WPF 창에 투명도를 적용해야 하는 상황이 생겨서 윈폼에서 사용하듯 Opacity 를 적용시켰습니다. 하지만 투명도를 낮추면 Background 에 적용된 SolidColorBrush 의 색상을 따라 어두워질 뿐, 투명도가 적용되지는 않았습니다.   그래서 Background에 적용된 SolidColorBrush의 Alpha값을 낮춰보았지만 역시 적용이 되지 않았죠. 그래서 구글링을 했는데, 생각지도 못하게 간단한 해결책이 있었습니다.   Background 의 SolidColorBrush 를 설정할 필요는 전혀 없었습니다. 단 하나, 프로퍼티를 True로 설정하면 되는 것이었죠. <Window <!-- ... --> AllowsTransparency="True" > </Window>   위와 같이 AllowsTransparency 속성을 True 로 설정해준 뒤, Opacity 값을 변경하면 정상적으로 창에 투명도가 적용된 것을 확인하실 수 있을 겁니다.

[C#/WPF] System.Windows.Controls.Primitives 네임스페이스

https://msdn.microsoft.com/ko-kr/library/system.windows.controls.primitives(v=vs.110).aspx   해당 네임스페이스의 클래스들은 지원되는 컨트롤 XAML에서 아래와 같이 사용 가능합니다. 예: TabControl.TabItem의 Selected 이벤트를 개별로 설정해야 할 경우 <TabControl> <TabItem Header="SampleTab" Selector.Selected="SampleTab_Selected" /> </TabControl>   위와 같이 하면 TabContorl.SelectedIndex에서 TabItem의 Name을 지정해 일일히 찾는 수고를 덜고 TabItem에 바로 Selected 이벤트 핸들러를 지정할 수 있습니다.   그 외에 제가 자주 쓴 항목은 아직까진 없지만 해당 네임스페이스의 클래스들을 유용히 쓸 분이 충분히 많이 계실 것 같아 공유합니다.

[C#/WPF] TextBox.Text 에 Binding된 속성이 즉시 업데이트되지 않는 경우

포커스를 잃을 때만 업데이트되는 TextBox.Text Binding   방금 TextBox.Text에 따라 WebBrowser.NavigateToString()을 호출하려 하는 중, 괜히 Binding을 쓰고 싶어서 TextBox.Text에 Binding Html을 걸어놓고 디버그를 해보니 텍스트가 입력될 때가 아니라, 텍스트박스의 포커스를 잃을 때 Html 프로퍼티가 업데이트되는 현상 을 발견했습니다.   제 목적은 실시간으로 WebBrowser에 TextBox에 입력된 HTML을 렌더링하는 작업이기 때문에 매우 곤란한 상황이죠.   하지만 언제나 그렇듯, 답은 매우 간단했습니다. Binding.UpdateSourceTrigger 프로퍼티   Binding 클래스에는 UpdateSourceTrigger 라는 프로퍼티가 있습니다. 이름에서 알 수 있듯, 언제 원본의 값을 업데이트할지 결정하는 녀석이죠. 기본값은 Default이며 Default는 Binding이 적용될 DependencyProperty를 만들 때 설정한 기본값 으로 동작합니다.   Binding.UpdateSourceTrigger 프로퍼티에 들어갈 수 있는 값은 UpdateSourceTrigger 열거형 의 값들인데요, 아래와 같습니다. public enum UpdateSourceTrigger { Default, PropertyChanged, LostFocus, Explicit, }   Default 는 위에서 말씀드렸듯, DependencyProperty를 만들 때 설정한 기본값입니다.   PropertyChanged 는 해당 DependencyProperty에 변경이 생길 때 원본을 업데이트합니다.   LostFocus 는 DependencyProperty를 지닌 컨트롤이 포커스를 잃을 때 원본을 업데이트합니다.   Explicit ...

[C#/WPF] LambdaConverters, Binding 컨버터를 람다로 손쉽게 만들어보자

이미지
  이 동영상에서는 LambdaConverters 를 사용해 IValueConverter를 간단하게 람다식으로 구현하는 방법에 대해 설명합니다.   핵심 내용만 정리하면 아래와 같습니다. // 람다 컨버터 제작 public static class HsConverters { // One-way Binding public static readonly IValueConverter PresentConverter = ValueConverter.Create (b => str.Value.Equals("있음")); // Two-way Binding public static readonly IValueConverter PresentConverterTwoWay = ValueConverter.Create (b => str.Value.Equals("있음"), str => str.Value.Equals("있음")); // One-way To Source Binding public static readonly IValueConverter PresentConverterOneWayToSource = ValueConverter.Create (null, str => str.Value.Equals("있음")); } <!-- XAML --> <TextBox Text="{Binding BoolValue, Converter={x:Static myNamespace:HsConverters.PresentConverterTwoWay}}" />

[C#/WPF] Window의 크기를 테두리가 아닌 내부 영역 기준으로 설정하는 방법 (사이즈에 맞추는 방법과 동일)

이미지
  WPF를 가지고 놀다 보면 불편한 점이 하나 있습니다. WinForm으로 코딩할 땐 그냥 디자이너나 InitializeComponent() 이후 ClientSize를 설정하면 윈도우 버전/테마마다 다른 테두리 두께와 상관없이 렌더링 영역의 크기를 설정할 수 있었는데, WPF에서는 그렇다 할 프로퍼티가 보이지 않고, 있더라도 불편하게 많은 줄의 코드를 추가해야 한다는 것이죠.   하지만, 약간의 꼼수만 있다면 언제나 그렇든 매우 간편하게 해결할 수 있습니다. 렌더링 영역이 16:9인 가로 120의 윈도우를 만들고 싶다   16:9 = 120:67.5 이므로 세로를 68로 설정해야 합니다. 우선, 항상 하듯 Window 의 Width 와 Height 를 120과 68로 설정해볼까요?   보시다시피 창 자체의 크기 가 120x68로 설정되었고, 렌더링되는 내부의 크기는 그보다 작게 설정 되었습니다.   뭐, 스택오버플로우나 이곳저곳 돌아다니다 보면 제가 쓰려는 이 방법 말고도 코드 도입부에 4줄정도 추가해 내부 사이즈를 조정하는 방법이 있긴 합니다만, 너무 길고 귀찮으므로 간단하게 XAML 선에서 해결을 봅시다. Window의 Width , Height  속성을 제거한다. Window의 SizeToContent 속성을 SizeToContent.WidthAndHeight 로 설정한다. Window의 첫 번째 자식 요소의 Width 와 Height 를 고정으로 설정한다. (여기선 120, 68)   위와 같이 하면 일단 시작 시 클라이언트의 영역은 원한 대로 설정됩니다. (120*68)   그러나, 치명적인 문제 가 하나 생기는데요, 윈도우의 크기가 변해야 할 상황이 생기는 경우(리사이즈 등), 내부 엘리먼트가 고정 크기이기 때문에 변하지 않고 그대로 유지 됩니다.   다이얼로그 나 기타 고정된 사이즈의 윈도우 에는 위 3단계로 충분하지만...

[C#/WPF] 객체의 속성을 Binding해서 사용하는 방법

  UserVo라는 로그인 정보를 담는 객체를 위한 클래스가 있습니다. UserId, UserPw, UserName 등 여러 유저 정보가 들어있죠.   회원가입 윈도우의 코드에는 이 UserVo 클래스의 객체가 UserVo라는 속성으로 정의돼 있습니다.   저는 이 속성 값을 그대로 Binding시켜 사용하려고 했습니다. 여기저기 구글링도 하고 스택오버플로우도 뒤져보고 했지만 키워드를 이상하게 선정했는지 작동하는 코드를 찾을 수 없었습니다.   그래서 혼자서 DataContext도 바꿔보고, Binding Source 및 Path도 바꿔보고 하다가 Source를 UserVo로, Path를 UserId, UserPw, UserName, ...으로 해서 일단 작동하게 하긴 했는데 아예 XAML에 몰아서 하는 방법 도 있어서 올립니다. // XAML <Window.Resources> <local:UserVo x:Key="UserVo" /> </Window.Resources> <!-- ... --> <TextBox Text={Binding Source={StaticResource UserVo}, Path={UserId} />   현재 윈도우 객체의 리소스에 UserVo 클래스의 인스턴스를 추가 하고, Binding할 때 Source를 리소스에 있는 인스턴스로, Path를 인스턴스의 프로퍼티명으로 설정하는 작업입니다. // MyWindow.cs public partial class MyWindow : Window { public UserVo UserVo => (UserVo) this.Resources["UserVo"]; // ... }   그리고 코드에서도 사용할 수 있게 public 한정자로 UserVo를 선언하고, x:Key 로 할당한 "UserVo"라는 이름의 리소스를 참조하게 합니다. ...

[C#/WPF] StackPanel, DockPanel 등 특정 패널 내의 내용을 스크롤 할 수 있게 하는 방법

  ScrollViewer로 감싸면 됩니다. <ScrollViewer> <StackPanel> <!-- 스크롤을 벗어날 정도로 긴 콘텐츠 --> </StackPanel> </ScrollViewer>   물론, XAML 에디터에서, 혹은 문서 개요에서 ScrollViewer를 선택하면 여러 옵션을 조정할 수 있습니다.

[C#/WPF] Stream을 사용해 Image를 BitmapImage로 변환할 때 에러 해결 방법

System.Drawing.Image를 System.Windows.Media.Imaging.BitmapImage로   안녕하세요. 오늘은 아주 기초적이지만 놓치기 쉽다고 생각되는 부분(을 겪은 제 상황)을 알려드리겠습니다.   방금 한 일은, WPF DataGridCell에 마우스를 올리면 상위 DataGridRow의 Item의 Image를 ToolTip으로 보여주는 작업인데요, 해당 프로그램은 처음에 WinForms 어플리케이션으로 만들었다가 WPF로 컨버전하는 중이기 때문에 System.Drawing.Image를 WPF에서 사용할 수 있는 BitmapImage로 바뀌어야 만 했습니다.   해당 방법은 구글링하면 아주 손쉽게 찾을 수 있었는데, 문제는 본문에 놓친 부분이 댓글에 적혀 있었단 것을 몰랐다는 겁니다. 본문에는 아래와 같이 하라고 쓰여있었습니다. public static BitmapImage ToWpfBitmapImage(this Image image) { if (image == null) return null; var bimg = new BitmapImage(); var ms = new MemoryStream(); image.Save(ms, image.RawFormat); bimg.BeginInit(); bimg.StreamSource = ms; bimg.EndInit(); return bimg; }   네. 하지만 당연하게도 에러를 뿜어냈습니다. 에러가 안 났다면 제가 이 글을 쓰고 있지도 않았겠죠. 뭐 헤더가 손상되었을 수 있습니다  이런 에러를 뿜더라고요. 에러 원인 분석   에러가 나는 원인을 찾으려고 해당 E...

[C#/WPF] Preview 이벤트와 일반 이벤트

  방금 코딩을 하다가 문득 PreviewMouseDown 이벤트와 MouseDown 이벤트의 차이가 무엇일까 궁금해서 알아보고 글을 씁니다.   WPF 의 RoutedEvent 는 엘리먼트 트리의 여러 컨트롤이 이벤트에 반응할 수 있게 해주는 기능을 제공한다고 합니다. 예를 들어 아래와 같은 구조의 윈도우를 디자인했다고 생각해봅시다. 1. Window 1-1. StackPanel 1-1-1. Button   그리고 버튼을 누를 경우, 아래와 같은 순서로 이벤트가 발생한다고 하네요. PreviewMouseDown - Window   PreviewMouseDown - StackPanel PreviewMouseDown - Button MouseDown - Button MouseDown - StackPanel MouseDown - Window   이 Preview  이벤트들은 Tunneling 이라는 동작을 한다고 합니다. 그 뒤, 일반 이벤트(Preview가 붙어있지 않은 이벤트)가 역순으로 다시 발생하는 것이죠.   만약 EventArgs  매개 변수의 Handled  속성을 true 로 설정하면, 터널링과 버블링이 멈춥니다. 이런 터널링과 버블링을 라우팅 전략 이라고 한다고 하네요.   이러한 라우팅 전략은 다양한 상황에 대처할 수 있게 해준다고 합니다. 예를 들어 아래와 같은 상황이죠. 모든 StackPanel의 하위 엘리먼트들이 MouseDown 이벤트를 받지 않게 한다. ( StackPanel.PreviewMouseDown  이벤트 핸들러에서  EventArgs.Handled 를 true 로 설정하면 됩니다) 다른 어떤 컨트롤도 아닌 Window  컨트롤에서만 발생한 KeyDown  이벤트를 처리하고 싶다. ( Window.KeyDown  이벤트 핸들러에서 처리하면 됩니다)...