8월, 2018의 게시물 표시

[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에 굵은 글씨를 그대로 넣어도 현재 아이피만 표시될 뿐, 다른 글자가 나타나지 않는 것이었죠.   그래서 구글링을 열심히 하다가 도저히 방법이 안 보여서, 편법을 썼습니다. 그리고 편법이긴 하지만, 하자 없이 완벽하게 작동합니다. 아래를 보시죠.

[C#] double형 오차, Round Off 대체 방법 및 decimal 리터럴 사용 방법

Double의 반올림 에러(Round-off) 대체 방법   우선 이 방법은 제목에도 적혀있듯, 해결 방법이 아닌 대체 방법을 서술합니다.   왜 대체 방법일수밖에 없느냐면, 구조적으로 double형은 반올림 오류가 발생할 수밖에 없기 때문입니다. 아래를 보시죠. var a = 2.42; var b = a + 0.01; Console.WriteLine(b);   위를 실행하면 아마 콘솔에 정상적으로 2.43이 출력될 겁니다. 하지만 정말 그럴까요? 디버그를 통해 b 변수의 값을 조사해보면, 실제로는 2.4299999999999997 라는 값이 저장된 것을 확인할 수 있습니다. 한 번 확인해봅시다. var a = 2.42; for (var i = 0; i < 100; i++) a += 0.01; Console.WriteLine(a);   콘솔에 어떤 값이 출력되시나요? 하나 확실한 것은, 3.42는 아닐 겁니다. 출력된 값은 3.41999999999998 이죠. 이유는 바로 반올림 에러 입니다.   위 링크와 double, float이 구현되는 방식을 보시면 왜 이런 문제가 생기는지 알 수 있을 겁니다. 하지만 C#에서는 이러한 문제를 해결하기 위해 decimal 형을 지원합니다. decimal형은 MSDN 문서 에서 보듯, round off 오류가 일어나지 않기 때문에 정밀도가 요구되는 작업에서 사용하면 좋습니다.   문제는, decimal형은 그 크기가 16바이트이며, 연산 속도도 double에 비해 느립니다. 테스트 결과, 0부터 1,000,000까지 0.1씩 더하는, 총합 천만 회의 루프에서 double은 0.03초, decimal은 0.23초로 decimal이 7배 이상 느린 것으로 확인되었습니다.   따라서, double의 기본 정밀도 보장 범위 내의 변동에서 문제가 없는 프로그램이라면 double형을, 성능과 자원을 더 할당해서라도 정밀도가 보장돼야 하는 프로그램에서는 decimal을 사용하시면 되겠

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

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

[PowerShell] 특정 디렉토리 내 파일의 확장자 일괄 변경

  제목대로, 이번엔 파워쉘에서 특정 디렉토리 내의 확장자를 일괄 변경하는 방법에 대해 써보려 합니다.   파워쉘이 없던 시절엔 명령 프롬프트의 ren 명령어로 이러쿵 저러쿵 사용했던 것 같은데, 잘 기억이 안 나는 바람에 이렇게 된 거, 파워쉘로 해보자 하며 찾아본 결과입니다.   DIR 명령어는 Get-ChildItem 혹은 GCI 명령어로도 대체 가능합니다. DIR | Rename-Item -NewName { [System.IO.Path]::ChangeExtension($_.Name, ".확장자") }   당연히 DIR 옆의 | 기호는 파이프 기호입니다. 대충 동작하는 과정은, 1. Get-ChildItem으로 현재 디렉토리 내의 모든 파일/폴더를 가져옴 2. 1. 의 각 항목에 대해 Rename-Item 명령어를 실행 3. Rename-Item 명령어의 -NewName 인수에 따라, 새 이름을 적용 4. 바뀔 이름은 각 항목이서 확장자만 확장자 로 바꾼 문자열이 됨