Upload
phoooo
View
1.651
Download
1
Embed Size (px)
DESCRIPTION
Charles Petzold's WPF Chapter 19-20
Citation preview
Keywords• WPF• XML• XAML• Window 엘리먼트• 프로퍼티• 약간은 불필요한 시도
19 장 XAML
XAML [zæ:mɛl]
• WPF (Window Presentation Foundation)– 인터페이스와 비즈니스 로직을 분명히 구분– 응용 프로그램 서비스의 호스트를 통일 : 인터페이스 , 애니메이션 , 3D, 오디오 등
• XML (Extensible Markup Language)
• XAML (Extensible Application Markup Language)– 마이크로소프트에서 구조값과 객체를 초기화하는데 사용하기 위해 만든 선언형 XML 기반 언어– WPF 의 사용자 인터페이스를 위한 언어– 런타임 속성– 편집 도구의 자유 : 비주얼 스튜디오 , 익스프레션 블렌드 , 메모장– 의사소통 : 개발자와 디자이너 간에 콘텐츠를 자유롭게 공유하고 편집 가능– C# 코드로 표현 가능– System.Windows.Controls
<Button Foreground=“Yellow” FontSize=“24pt”>Hello, XAML!
</Button>
Button btn = new Button();btn.Foreground = Brushes.Yellow;btn.FontSize = 32; // 장치 독립적 단위btn.Content = “Hello, XAML!”
Stand Alone XAML
• 두 문서에 같은 엘리먼트 이름을 서로 다른 목적으로 사용하는 경우– WPF 프로그래머의 XAML 문서 & 셔츠 버튼 제조업자의 XML 문서
xmlns: XML 네임스페이스 속성– 엘리먼트와 자식 엘리먼트에게 적용– 유일하고 영속적 , URL 을 사용하는 것이 일반적
• 예제 XamlStackPanel.xaml• PresentationHost.exe
– 인터넷 익스플로러에 의해 호스팅될 수 있는 Page 타입의 객체를 생성– 로드된 XAML 을 실제 StackPanel, Button 등 객체로 변환한 후 이 객체를 Page 의 컨텐트 프로퍼티에 저장
http://schemas.microsoft.com/winfx/2006/xaml/presentation
<Button Foreground=“Yellow” FontSize=“24pt”>Hello, XAML!
</Button>
페이지 속성 변경• 예제 XamlPage.xaml
– Page 를 루트 엘리먼트로 생성하고 WindowTitle 프로퍼티에 원하는 텍스트를 설정– StackPanel 을 Page 의 자식으로 생성
• Window 를 루트 엘리먼트로 한 스탠드얼론 XAML 은 불가능– PresentationHost.exe 는 스탠드얼론 XAML 파일의 루트 엘리먼트를 어떤 것의 자식으로 만듦– Window 객체는 그 어떤 것의 자식도 될 수 없음– 루트 엘리먼트는 Window 를 제외하고 FrameworkElement 를 상속받는 것이면 어떤 것도 가능
XamlReader.Load
• XamlReader.Load 메소드– System.Windows.Markup 네임스페이스– XAML 을 파싱해 초기화된 객체로 전환– XamlWriter.Save 는 객체로부터 XAML 을 생성– Stream 객체나 XmlReader 객체를 받음
string strXaml ="<Button xmlns='http://schemas.microsoft.com/winfx/2006/" +" xaml/presentation'" +" Foreground='LightSeaGreen' FontSize='24pt'>" +"Click me!" +"</Button>";
StringReader strreader = new StringReader(strXaml);XmlTextReader xmlreader = new XmlTextReader(strreader);object obj = XamlReader.Load(xmlreader);
XAML 을 리소스로 사용하기• LoadXamlResource.xml
– Button 객체에 Name 속성 포함
• LoadXamlResource.cs
– Stream 객체가 XamlReader.Load 의 인자가 되어 반환되는 객체 (StackPanel) 를 Win-dow 의 Content 프로퍼티에 할당
– 일단 객체가 XAML 로부터 변환되어 창의 비주얼 트리의 일부가 되면 FindName 메소드를 사용해서 엘리먼트 트리상에서 특정한 이름으로 찾는 것이 가능
– 실행 시에 로드한 XAML 에게 이벤트 핸들러를 연결할 수 있는 가장 간단한 방법
<Button Name="MyButton" HorizontalAlignment="Center" Margin="24">
Hello, XAML!</Button>
Uri uri = new Uri("pack://application:,,,/LoadXamlRe-source.xml");Stream stream = Application.GetResourceStream(uri).Stream;FrameworkElement el = XamlReader.Load(stream) as FrameworkEle-ment;Content = el;
Button btn = el.FindName("MyButton") as Button;
if (btn != null)btn.Click += ButtonOnClick;
Window 가 루트인 Xaml• LoadXamlWindow.xml
• LoadXamlWindow.cs
– PresentationHost.exe 는 XAML 을 어떤 것의 자식으로 변환– 여기서는 XAML 리소스가 Window 임을 인식 , Window 를 상속받거나 Window 자체를 직접
생성하지 않음– 버튼 클릭 이벤트 핸들러를 비주얼 트리 속에서 찾아 연결하지 않고 Window 의 AddHandler 를
호출해 연결– Main 메소드는 Application 의 Run 메소드에 Window 객체를 인자로 전달
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen-tation" Title="Load Xaml Window" SizeToContent="WidthAndHeight" ResizeMode="CanMinimize">
Uri uri = new Uri("pack://application:,,,/LoadXamlWindow.xml");Stream stream = Application.GetResourceStream(uri).Stream;Window win = XamlReader.Load(stream) as Window;
win.AddHandler(Button.ClickEvent, new RoutedEventHandler(ButtonOnClick));
app.Run(win);
XAML 을 C# 에서 로드하기
• 파일명은 XmlTextReader 생성자로 바로 전달
• 객체가 Window 이면 모달리스 대화상자처럼 보임
XmlTextReader xmlreader = new XmlTextReader(dlg.FileName);object obj = XamlReader.Load(xmlreader);
if (obj is Window){
Window win = obj as Window;win.Owner = this;win.Show();
}
Elseframe.Content = obj;
XAML• 실제 애플리케이션에서는 XAML 을 소스 코드와 함께 컴파일 하는 것이 보편적 , 효율적
– XAML 안에 이벤트 핸들러 이름을 직접 명시 가능
• 지금까지 본 XAML– WPF 의 클래스와 프로퍼티만을 사용– 그러나 XAML 은 WPF 만을 위한 마크업 언어는 아님 ( 예 : Windows Workflow Foundation,
WPF)– http://schemas.microsoft.com/winfx/2006/xaml: XAML 명세
– WPF 에서 사용
– XAML 고유 엘리먼트와 속성을 위한 네임스페이스는 관례적으로 접두어 x 와 함께 선언– 고유 엘리먼트와 속성이 많지 않아 WPF 관련 네임스페이스가 기본
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml/presentation
Class 속성• Class 속성
– XAML 파일의 루트 엘리먼트– XAML 이 프로젝트 일부로 컴파일될 때만 사용 가능
• CompileXamlWindow.xaml
– XAML 과 비하인드 코드는 하나의 클래스
x:Class="MyNamespace.MyClasName"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen-tation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="Petzold.CompileXamlWindow.CompileXamlWindow">
namespace Petzold.CompileXamlWindow{
public partial class CompileXamlWindow : Window{
…}
}
• BAML ( 바멜 )– XAML 의 바이너리 형태
• CompileXamlWindow.g.cs– XAML 로부터 산출된 코드– Lstbox 와 elips 가 선언– InitializeComponent()– XAML 을 코드와 함께 컴파일했을 때만 가능
public CompileXamlWindow(){
InitializeComponent(); // XAML 엘리먼트 속성 설정 , 이벤트 핸들러 연결…}
void ButtonOnClick(object sender, RoutedEventArgs args){
Button btn = sender as Button; // 생략가능…
}
자신의 클래스를 XAML 내에서 사용• 다른 네임스페이스 선언
– 반드시 소문자– http: 와 유사– 사용하기 전에 선언– src ( 소스코드 ) 가 자주 쓰임
• UseCustomClass.xaml• UseCustomClass.cs
– ColorGridBox 가 상속받은 ListBox 로 바꾸면 생략가능– 데이터 바인딩을 정의하면 SelectionChanged 이벤트 핸들러를 완전히 XAML 파일 속으로
넣을 수 있음 (23 장 )
xmlns:stuff=“clr-namespace:MyNamespace”
<stuff:MyControl …>
using Petzold.SelectColorFromGrid;…void ColorGridBoxOnSelectionChanged(object sender, SelectionChangedEventArgs args){
ColorGridBox clrbox = args.Source as ColorGridBox;…
}
XAML 에서 사용자 정의 클래스 정의• CenteredButton.xaml
• UseCustomXamlClass.xaml
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen-tation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="Petzold.UseCustomXamlClass.CenteredButton" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="12" />
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen-tation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:src="clr-namespace:Petzold.UseCustomXamlClass" x:Class="Petzold.UseCustomXamlClass.UseCustomXamlClass" Title = "Use Custom XAML Class"> <StackPanel Name="stack"> <src:CenteredButton>Button A</src:CenteredButton> <src:CenteredButton>Button B</src:CenteredButton> <src:CenteredButton>Button C</src:CenteredButton> <src:CenteredButton>Button D</src:CenteredButton> <src:CenteredButton>Button E</src:CenteredButton> </StackPanel></Window>
Cont’d• UseCustomXamlClass.cs
public UseCustomXamlClass(){
InitializeComponent();
for (int i = 0; i < 5; i++){
CenteredButton btn = new CenteredButton();btn.Content = "Button No. " + (i + 1);stack.Children.Add(btn);
}}
명확한 Main 이 사라지는 현상• MyApplication.xaml
– ApplicationDefinition 으로 빌드 작업 설정
– StartupUri 는 Main 함수에서 호출되는 Run 메소드를 대체 , 초기 Window 객체 띄움
• MyApplication.cs
– MyApplication.g.cs 파일에서는 Main 메소드 있음– 삭제가능
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen-tation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="Petzold.IncludeApplicationDefinition.MyApplication" StartupUri="MyWindow.xaml" />
namespace Petzold.IncludeApplicationDefinition{ public partial class MyApplication : Application { }}
코드가 없는 프로젝트• XAML 속에 데이터 바인딩을 가지고 있는 경우• XAML 애니메이션을 사용하는 경우
• XamlOnlyApp.xaml
– 컴파일 시 클래스 자동 생성
• XamlOnlyWindow.xaml
– BAML
실제 구조는 코드를 가진 프로젝트와 유사
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen-tation" StartupUri="XamlOnlyWindow.xaml" />
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen-tation" Title="Compile XAML Only" SizeToContent="WidthAndHeight" ResizeMode="CanMinimize"> <StackPanel>
… </StackPanel></Window>
XAML 파일 속에 C# 코드 넣기• 앞의 CompileXamlOnly 프로젝트와 유사
• EmbeddedCodeWindow.xaml
– 필드 정의는 불가능– using 등의 문제 해결 위해 System.Reflection 네임스페이스의 클래스 숙지
<Window> <StackPanel> … <x:Code> <![CDATA[
… void ListBoxOnSelection(object sender, SelectionChangedEventArgs args) { string strItem = lstbox.SelectedItem as string; System.Reflection.PropertyInfo prop = typeof(Brushes).GetProperty(strItem); elips.Fill = (Brush)prop.GetValue(null, null); } ]]> </x:Code> </StackPanel></Window>
응용• 리소스에 이미지 파일 추가
• DesignXamlButtonWindow.xaml
<Button HorizontalAlignment="Center“ VerticalAlignment="Center“ Margin="24"> <StackPanel> <Polyline Stroke="Black" Points="0 10,10 0,20 10,30 0,40 10,50 0, 60 10,70 0,80 10,90 0,100 10" />
<Image Margin="0,10,0,0" Source="BOOK06.ICO" Stretch="None" />
<Label HorizontalAlignment="Center"> _Read Books! </Label>
<Polyline Stroke="Black" Points="0 0,10 10,20 0,30 10,40 0,50 10, 60 0,70 10,80 0,90 10,100 0" /> </StackPanel></Button>
20 장 프로퍼티와 속성
동적 XAML Reader• XamlCruncher 프로젝트
• XamlCruncherAssemblyInfo.cs– 프로그램 정보
• XamlCruncherSettings.cs
public Dock Orientation = Dock.Left; // TextBox 와 Frame 위치제어public int TabSpaces = 4; // 탭 키를 누를 때 삽입할 공백개수public string StartupDocument = // 처음 나오는 XAML 을 설정 "<Button xmlns=\"http://schemas.microsoft.com/winfx" + "/2006/xaml/presentation\"\r\n" + " xmlns:x=\"http://schemas.microsoft.com/winfx" + "/2006/xaml\">\r\n" + " Hello, XAML!\r\n" + "</Button>\n";
// 생성자 . 폰트 지정public XamlCruncherSettings(){
FontFamily = "Lucida Console";FontSize = 10 / 0.75;
}
XamlCruncher.cs• XamlCruncher.cs
– Window 의 컨텐트가 될 Grid 를 생성– Xaml 이라는 최상위 메뉴와 하위 메뉴 생성
// DockPanel 을 찾은 후 그것에서 TextBox 를 제거DockPanel dock = txtbox.Parent as DockPanel;dock.Children.Remove(txtbox);
// Grid 생성 , 3 개의 열과 행Grid grid = new Grid();dock.Children.Add(grid);
// Xaml 을 최상위 메뉴로 삽입MenuItem itemXaml = new MenuItem();itemXaml.Header = "_Xaml";menu.Items.Insert(menu.Items.Count - 1, itemXaml);
Cont’dvoid Parse(){
StringReader strreader = new StringReader(txtbox.Text);XmlTextReader xmlreader = new XmlTextReader(strreader);try{
object obj = XamlReader.Load(xmlreader); // 예외 상황 발생 시
txtbox.Foreground = SystemColors.WindowTextBrush;
if (obj is Window){
// Window 객체를 위해서는 F7 키를 눌렀을 때 독립된 창을 띄워줌win = obj as Window;statusParse.Content = "Press F7 to display Window";
}else{
// Frame 컨트롤의 Content 프로퍼티에 설정win = null;frameParent.Content = obj; statusParse.Content = "OK";
}}catch (Exception exc){
// TextBox 의 텍스트 전체를 붉은색으로 표시하고 메시지를 상태표시줄에 표시txtbox.Foreground = Brushes.Red;statusParse.Content = exc.Message;
}}
공백 개수 변경• XamlTabSpaceDialog.xaml
– 대화상자의 배치 정의
• XamlTabSpaceDialog.cs
• XamlCruncher.cs– Tab Space 메뉴 선택 시
위 대화상자 호출
public int TabSpaces{
set { txtbox.Text = value.ToString(); }get { return Int32.Parse(txtbox.Text); }
}void TextBoxOnTextChanged(object sender, TextChangedEventArgs args){
int result; btnOk.IsEnabled = (Int32.TryParse(txtbox.Text, out result) && result > 0 && result < 11);}void OkOnClick(object sender, RoutedEventArgs args){ DialogResult = true;}
TextBox 와 Frame 의 위치 변경• XamlOrientationMenuItem.cs
Star.xaml
• Points 프로퍼티– PointCollection 타입– 연속적인 X 와 Y 좌표를 포인트로 명세– 숫자는 공백이나 콤마로 구분 가능
• Fill 프로퍼티– Brushes 클래스의 정적 멤버 사용– 16 진법으로 RGB 색상 사용 가능– 알파 채널 적용 가능 (128)– 부동소수점으로 scRGB 스킴으로 표현
<Polygon xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Points="144 48, 200 222, 53 114, 235 114, 88 222" Fill="Red" Stroke="Blue" StrokeThickness="5" />
Fill=“FF0000”
Fill=“#80FF0000”
Fill=“sc#0.5,1,0,0”
LinearGradientBrush• 적어도 2 개의 값과 그라디언트 스탑 필요• 객체 엘리먼트 (Polygon) & 프로퍼티 속성 (Fill)• 자식 엘리먼트를 포함하는 문법으로 프로퍼티 명세 가능 ( 프로퍼티 엘리먼트 , 속성요소 )
<Polygon> <Polygon.Fill> Red </Polygon.Fill></Polygon>
<Polygon.Fill> <Brush> Red </Brush></Polygon.Fill>
(Brush 타입의 Fill 프로퍼티 참조 )
<Polygon.Fill> <SolidColorBrush> Red </ SolidColorBrush></Polygon.Fill>
(Brush 는 SolidColorBrush 타입의 객체로 변환가능 )
<Polygon.Fill> <SolidColorBrush Color=“Red”> </ SolidColorBrush></Polygon.Fill>
(SolidColorBrush 는 객체이므로 프로퍼티 가질 수 있음 )
<!-- 잘못된 문법 -><Polygon.Fill Attr=“Whatever”> …</Polygon.Fill>
( 프로퍼티는 프로퍼티 가질 수 없음 )
Cont’d<Polygon xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen-tation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Points="144 48, 200 222, 53 114, 235 114, 88 222" Stroke="Blue" StrokeThickness="5"> <Polygon.Fill> <RadialGradientBrush> <GradientStop Offset="0" Color="Blue" /> <GradientStop Offset="1" Color="Red" /> </RadialGradientBrush> </Polygon.Fill></Polygon>
윈도우 컨텐트 프로퍼티• DockPanel
• Grid
• StackPanel
RoutedEvent• 클래스와 이벤트 이름으로 속성으로 사용함으로써 이벤트 핸들러 설정 가능
<TextBlock.ContextMenu><ContextMenu MenuItem.Click="MenuItemOnClick">
<MenuItem Header="Red" /> <MenuItem Header="Orange" /> <MenuItem Header="Yellow" /> <MenuItem Header="Green" /> <MenuItem Header="Blue" /> <MenuItem Header="Indigo" /> <MenuItem Header="Violet" /> </ContextMenu></TextBlock.ContextMenu>
Thank you• Q&A