Canvas 의 사용 용도에 따라 눈금선이 필요한 경우가 있다. (Grid, Panel 등도 방법은 동일하다)

주로 그림판이나 이미지 관련 기능을 구현할 때 필요로 할텐데, 이를 구현해보자.


파워포인트의 눈금선 기능을 참고하자.



방법은 격자 무늬의 VisualBrush (혹은 DrawingBrush) 를 생성하고, 이를 컨트롤의 Background 로 지정하는 것이다.


상하, 좌우 각각 50pixel 간격의 격자를 생성하는 코드는 다음과 같다.


물론 위의 Brush 를 Resource 에 선언하고, Key 값을 통해 필요한 부분에서 사용하거나, xaml 측이 아닌 c# 측에서 선언하여 사용하는 방법도 가능하다.


위의 코드의 출력물은 다음과 같다.







WPF에서 이미지를 로드했을 때, 이미지의 품질이 떨어져 보이는 경우가 있다. 문서나 그래프가 포함된 이미지를 로드하면 확연히 그 차이가 보이는데, 그 이유는 품질 상의 이유로 렌더링 시 이미지의 품질을 낮추기 때문이다.


이는 'RenderOptions.BitmapScalingMode' 라는 의존속성을 변경하여 해결할 수 있다.

해당 속성은 기본으로 'Unspecified' 로 지정되어 있으며, 이는 품질이 떨어지는 대신 처리 속도가 빠르다.

이미지의 품질을 높이기 위해서는 BitmapScalingMode 라는 속성을 'HighQuality' 로 변경하면 되는데, 

xaml 에서 변경할 수도 있고, cs 측에서 다음의 함수를 호출하여 변경할 수도 있다.


RenderOptions.SetBitmapScalingMode(this, BitmapScalingMode.HighQuality);



그 차이를 비교하기 위해, 그래프와 텍스트가 포함된 이미지를 각각 기본 셋팅과 HighQuality 로 하여 불러왔다.

그래프와 텍스트를 구별하는데 확연한 차이가 있음을 확인할 수 있다.




화면을 통채로 캡쳐하고 싶은 경우가 있다.

이 때는 RenderTargetBitmap 객체를 사용하여 화면을 Bitmap으로 만들고 이를 저장하는 방법을 이용한다.


Canvas 객체를 파일로 저장하는 코드는 다음과 같다.



RenderTargetBitmap 객체를 통해 Visual 을 Bitmap으로 만들고, 이를 파일로 기록하는 방법이다.

Visual 클래스를 상속받은 객체들에 대해 위의 방법을 적용할 수 있다.

이 포스팅에서는


1. 선택된 행, 열 버튼에 표시하기

2. 행, 열 선택 시 라우팅 이벤트 발생


의 과정을 진행하겠다.


----------------------------------------------

1. 선택된 행, 열 버튼에 표시하기


다시 Generic.xaml 로 돌아가자.

1. ToggleButton 내부에 적당히 행, 열을 표시하도록 TextBlock 들을 만든다.

2. 각각의 TextBlock 의 Text 를 'Row', 'Column' 의존속성과 바인딩 시킨다.

  - 이 때, Row, Column 은 int 형 의존속성으로, 바로 바인딩 시킬 수 없다. 따라서 컨버터(Converter)를 사용한다.

  - 컨버터의 사용은 이전의 포스팅([WPF] Binding (바인딩) - Converter (컨버터))을 참고한다.



완료한 후 실행하면 다음과 같다.




----------------------------------------------

2. 행, 열 선택 시 라우팅 이벤트 발생


라우팅 이벤트를 만들고 발생시키는 과정은 이전의 포스팅 ([WPF] Custom Routed Event (라우팅 이벤트 만들기)) 에서 다룬 적이 있기 때문에 자세한 설명은 생략하도록 한다.


포스팅과 동일한 방법으로 라우팅 이벤트를 생성하고, 

사각형이 클릭되었을 때 해당 이벤트를 발생시키도록 한다.

(앞에서 정의한 MouseLeftButtonUp 이벤트 핸들러에 추가하면 된다)



----------------------------------------------



여기까지 진행하면 행, 열을 선택할 수 있는 '행열 선택기' 가 완성되었을 것이다.

이외에 필요한 기능은 별도로 작성하여 사용하면 되겠다.


이외에 필요한 컨트롤이 있다면 위와 비슷한 과정으로 진행하여 만들 수 있고,

ColorPicker, Spinner, Calculator 등의 다양한 컨트롤들이 이미 ExtendedToolkit 에 포함되어 있다.

코드도 공개가 되어 있으니 이를 참조하여 새로 만들 수도 있을 것이다.






이번 포스팅에서는


1. 선택된 행, 열의 갯수를 지정하는 의존속성(Dependency Property) 생성

2. 작은 사각형(CustomRectangle) 에 마우스 이벤트 구현


을 진행하도록 하겠다.


---------------------------------------------------

1. 선택된 행, 열의 갯수를 지정하는 의존속성(Dependency Property) 생성


의존속성은 이전 포스팅에서도 다루었지만 쉽게 생성하여 일반 전역변수처럼 사용할 수 있다.


다음과 같이 행(Row), 열(Column) 에 해당하는 의존속성을 생성하도록 한다.





여기에 덧붙여, 앞의 과정에서 사각형들을 생성할 때 사용했던 변수들(MaxRows, MaxColumns, RectangleSize, ...) 등도 의존속성으로 생성하여, 추후 변경이 쉽게 가능하도록 생성하였다.


---------------------------------------------------

2. 작은 사각형(CustomRectangle) 에 마우스 이벤트 구현


사각형들 위에서 마우스가 움직일 때마다 사각형들을 선택 혹은 해제하도록 하는 과정이 필요하다.

이를 위해서 앞에서 CreateRectangles() 함수 내부에서 생성한 CustomRectangle 각각에 이벤트를 연결하는데, 

연결할 이벤트는 MouseEnter, MouseLeftButtonUp 의 2개이다.


MouseEnter의 경우 마우스가 이동할 때마다 사각형들을 선택/해제 하도록 하고

MouseLeftButtonUp 의 경우 해당 사각형에 맞는 행, 열의 갯수를 선택하도록 한다.


각 사각형들마다 Row, Column 값을 가지고 있으므로, 

한 사각형에 MouseEnter 이벤트가 발생하면, 해당 사각형보다 Row, Column 이 작은 사각형들을 하이라이트 해주고,

한 사각형에 MouseLeftButtonUp 이벤트가 발생하면, 해당 사각형의 Row, Column 값을 1. 에서 생성한 의존 속성에 넣어주면 된다.




* 위에 언급한 것 외에 팝업을 닫고, Custom RoutedEvent 를 발생시키는 등의 작업이 필요할 수 있다.


---------------------------------------------------

여기까지 완료한 후 실행한 결과는 다음과 같다.









이번 포스팅에서는


1. 팝업창 내부의 구조를 구현하고

2. 작은 사각형들을 동적으로 생성한다.


----------------------------------------------------------

1. 팝업창 내부의 구조


이제 팝업창 내부에 행, 열을 선택하는 화면을 구현해보자.


팝업창 상단에는 현재 선택된 행, 열의 갯수가 보여지도록 TextBlock 을 넣고

하단에는 사각형들을 배치할 'UniformGrid'를 하나 넣어준다.


여기까지 넣으면 간단한 구조는 다음과 같다


<Popup>

<Grid>

<TextBlock />

<UniformGrid />

</Grid>

</Popup>


----------------------------------------------------------

2. 작은 사각형들 생성


작은 사각형들을 생성하여 위에서 생성한 UniformGrid에 차곡차곡 넣어주어야 한다.


간단한 과정은 다음과 같다.

1. 먼저 UniformGrid 에 Row, Column 을 원하는 값으로 지정한다.

2. 해당 UniformGrid에 Row x Column 개 만큼의 사각형을 생성하여 Children으로 추가한다.


이 과정을 실행하는 시점은, Generic.xaml 에 정의된 Template가 적용되는 시점으로 하는 것이 바람직하며

이는 OnApplyTemplate() 함수를 override 하여 사용하면 된다.


이 과정을 코드로 작성하면 다음과 같다.



MaxRows, MaxColumns, RectangleSize, RectangleMargin, RectangleColor 등은 몇 칸을 어느 정도의 크기와 색으로 만들지에 대한 변수이며, 

CustomRectangle 은 'Rectangle' 에 2개의 int 형 변수 :  Row, Column 을 추가한 객체이다.


----------------------------------------------------------

여기까지 완료하고 실행시켜보면 다음과 같은 화면을 볼 수 있다.






이제 본격적으로 컨트롤을 만들어보자.


프로젝트를 만들고, 새 아이템 추가를 해서 'Custom Control(WPF)'를 선택해서 추가한다.

이름은 일단 RowColumnSelector 라고 지정하였다.


생성하면 RowColumnSelector.cs 파일 하나와, Themes폴더가 생기고 Themes 폴더 안에 Generic.xaml 이라는 파일이 생성되는 것을 확인할 수 있다.

RowColumnSelector.cs 파일에서 해당 컨트롤의 동작을 구현하고, Generic.xaml 파일에서 해당 컨트롤의 뷰를 구현하게 된다.


Generic.xaml 파일을 보면 다음과 같은 코드가 작성되어 있다.



우리가 필요로 하는 건 앞에서 언급했듯이 

1. 팝업을 열기 위한 버튼(토글버튼)

2. 행, 열을 선택하기 위한 팝업 

이므로 각각을 작성해서 넣는다



ToggleButton과 Popup 컨트롤들을 각각 넣고, 

Popup 컨트롤의 IsOpen 속성을 ToggleButton의 IsChecked 속성과 바인딩한다.


확인을 위해 간단히 크기와 배경을 지정하여 다음과 같이 작성하였다.




여기까지 작성된 'RowColumnSelector' 를 MainWindow 에 넣고 실행시켜보면 다음과 같다.





버튼을 클릭하면 팝업이 나타나고, 팝업이 포커스를 잃으면 사라지도록 구현되었다.


이제 팝업에 원하는 기능을 구현하도록 하자.






WPF에 기본으로 제공하지 않는 컨트롤이 필요할 때가 있다. 이 때 기존의 것들을 억지로 조합하는 것보다 새로운 컨트롤을 생성하는 편이 더 쉬울 수 있다.


앞으로 몇 개의 포스팅을 통해 직접 만들어 사용했던 '행열 선택기' 컨트롤을 만드는 과정을 정리하려 한다.


우선 '행열 선택기(RowColumn Selector)' 라고 이름붙인 컨트롤은 Word나 한글에서 표를 삽입할 때 사용하는 컨트롤로, 역시 표를 생성할 때 행의 갯수, 열의 갯수를 선택하고자 할 때 사용하였다.




숫자가 아니라 도형을 통해 직관적으로 표의 모양을 선택할 수 있다는 장점을 갖고 있다.



먼저 이 컨트롤을 만들기 위한 구성요소를 생각해보면, 크게는

1. 팝업을 띄우기 위한 버튼

2. 팝업창 

으로 이루어져 있고, 팝업창 은 다시

2-1. 타이틀바

2-2. 사각형 선택 영역 

로 나누어져 있다.


다음 포스팅에서 간단히 뼈대를 만들어보도록 한다 !



+ Recent posts