4. 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!”
5. Stand Alone XAML 두 문서에 같은 엘리먼트 이름을서로 다른 목적으로 사용하는 경우 WPF 프로그래머의 XAML 문서 & 셔츠 버튼 제조업자의 XML 문서 xmlns: XML 네임스페이스 속성 엘리먼트와 자식 엘리먼트에게 적용 유일하고 영속적,URL을 사용하는 것이 일반적 예제XamlStackPanel.xaml PresentationHost.exe 인터넷 익스플로러에 의해 호스팅될 수 있는 Page타입의 객체를 생성 로드된XAML을 실제 StackPanel, Button등객체로 변환한 후 이 객체를 Page의 컨텐트 프로퍼티에 저장 <Button Foreground=“Yellow” FontSize=“24pt”> Hello, XAML! </Button> http://schemas.microsoft.com/winfx/2006/xaml/presentation
6. 페이지 속성 변경 예제 XamlPage.xaml Page를 루트 엘리먼트로 생성하고 WindowTitle프로퍼티에 원하는 텍스트를 설정 StackPanel을 Page의 자식으로 생성 Window를 루트 엘리먼트로 한 스탠드얼론XAML은 불가능 PresentationHost.exe는 스탠드얼론 XAML 파일의 루트 엘리먼트를 어떤 것의 자식으로 만듦 Window객체는 그 어떤 것의 자식도 될 수 없음 루트 엘리먼트는Window를 제외하고 FrameworkElement를 상속받는 것이면 어떤 것도 가능
8. XAML을 리소스로 사용하기 LoadXamlResource.xml Button객체에 Name속성 포함 LoadXamlResource.cs Stream 객체가 XamlReader.Load의 인자가 되어 반환되는 객체(StackPanel)를 Window의Content프로퍼티에 할당 일단 객체가 XAML로부터 변환되어 창의 비주얼트리의 일부가 되면 FindName메소드를 사용해서 엘리먼트트리상에서 특정한 이름으로 찾는 것이 가능 실행 시에 로드한XAML에게 이벤트 핸들러를 연결할 수 있는 가장 간단한 방법 <Button Name="MyButton" HorizontalAlignment="Center" Margin="24"> Hello, XAML! </Button> Uri uri = new Uri("pack://application:,,,/LoadXamlResource.xml"); Stream stream = Application.GetResourceStream(uri).Stream; FrameworkElement el = XamlReader.Load(stream) as FrameworkElement; Content = el; Button btn = el.FindName("MyButton") as Button; if (btn != null) btn.Click += ButtonOnClick;
9. 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/presentation" 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);
10. XAML을 C#에서 로드하기 파일명은 XmlTextReader생성자로 바로 전달 객체가 Window이면 모달리스 대화상자처럼 보임 XmlTextReaderxmlreader = new XmlTextReader(dlg.FileName); object obj = XamlReader.Load(xmlreader); if (obj is Window) { Window win = obj as Window; win.Owner = this; win.Show(); } Else frame.Content = obj;
11. 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
12. Class속성 Class 속성 XAML 파일의 루트 엘리먼트 XAML이 프로젝트 일부로 컴파일될 때만 사용 가능 CompileXamlWindow.xaml XAML 과 비하인드 코드는 하나의 클래스 x:Class="MyNamespace.MyClasName" <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="Petzold.CompileXamlWindow.CompileXamlWindow"> namespace Petzold.CompileXamlWindow { public partial class CompileXamlWindow : Window { … } }
13. BAML (바멜) XAML의 바이너리 형태 CompileXamlWindow.g.cs XAML로부터 산출된 코드 Lstbox와 elips가 선언 InitializeComponent() XAML을 코드와 함께 컴파일했을 때만 가능 public CompileXamlWindow() { InitializeComponent(); // XAML 엘리먼트 속성 설정, 이벤트 핸들러 연결 … } void ButtonOnClick(object sender, RoutedEventArgsargs) { Button btn = sender as Button; // 생략가능 … }
14. 자신의 클래스를 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, SelectionChangedEventArgsargs) { ColorGridBoxclrbox = args.Source as ColorGridBox; … }
15. XAML에서 사용자 정의 클래스 정의 CenteredButton.xaml UseCustomXamlClass.xaml <Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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/presentation" 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>
16. Cont’d UseCustomXamlClass.cs public UseCustomXamlClass() { InitializeComponent(); for (inti = 0; i < 5; i++) { CenteredButtonbtn = new CenteredButton(); btn.Content = "Button No. " + (i + 1); stack.Children.Add(btn); } }
17. 명확한 Main이 사라지는 현상 MyApplication.xaml ApplicationDefinition으로 빌드 작업 설정 StartupUri는 Main 함수에서 호출되는 Run 메소드를 대체, 초기 Window 객체 띄움 MyApplication.cs MyApplication.g.cs파일에서는 Main 메소드 있음 삭제가능 <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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 { } }
18. 코드가 없는 프로젝트 XAML 속에 데이터 바인딩을 가지고 있는 경우 XAML 애니메이션을 사용하는 경우 XamlOnlyApp.xaml 컴파일 시 클래스 자동 생성 XamlOnlyWindow.xaml BAML 실제 구조는 코드를 가진 프로젝트와 유사 <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" StartupUri="XamlOnlyWindow.xaml" /> <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Title="Compile XAML Only" SizeToContent="WidthAndHeight" ResizeMode="CanMinimize"> <StackPanel> … </StackPanel> </Window>
19. XAML 파일 속에 C# 코드 넣기 앞의 CompileXamlOnly프로젝트와 유사 EmbeddedCodeWindow.xaml 필드 정의는 불가능 using등의 문제 해결 위해 System.Reflection네임스페이스의 클래스 숙지 <Window> <StackPanel> … <x:Code> <![CDATA[ … void ListBoxOnSelection(object sender, SelectionChangedEventArgsargs) { 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>
22. 동적 XAML Reader XamlCruncher프로젝트 XamlCruncherAssemblyInfo.cs 프로그램 정보 XamlCruncherSettings.cs public Dock Orientation = Dock.Left; // TextBox와 Frame 위치제어 public intTabSpaces = 4; // 탭키를누를때 삽입할공백개수 public string StartupDocument = // 처음나오는 XAML을설정 "<Button xmlns=quot;http://schemas.microsoft.com/winfx" + "/2006/xaml/presentationquot;" + " xmlns:x=quot;http://schemas.microsoft.com/winfx" + "/2006/xamlquot;>" + " Hello, XAML!" + "</Button>"; // 생성자. 폰트지정 public XamlCruncherSettings() { FontFamily = "Lucida Console"; FontSize = 10 / 0.75; }
23. XamlCruncher.cs XamlCruncher.cs Window의 컨텐트가 될 Grid를 생성 Xaml이라는 최상위 메뉴와 하위 메뉴 생성 // DockPanel을 찾은 후 그것에서 TextBox를 제거 DockPaneldock = txtbox.Parentas DockPanel; dock.Children.Remove(txtbox); // Grid 생성, 3개의 열과 행 Grid grid=new Grid(); dock.Children.Add(grid); // Xaml을 최상위 메뉴로 삽입 MenuItemitemXaml = new MenuItem(); itemXaml.Header = "_Xaml"; menu.Items.Insert(menu.Items.Count - 1, itemXaml);
24. Cont’d void Parse() { StringReaderstrreader = new StringReader(txtbox.Text); XmlTextReaderxmlreader = new XmlTextReader(strreader); try { object obj = XamlReader.Load(xmlreader); // 예외 상황 발생 시 txtbox.Foreground = SystemColors.WindowTextBrush; if (obj is Window) { // Window 객체를 위해서는 F7키를 눌렀을 때 독립된 창을 띄워줌 win = objas 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; } }
25. 공백 개수 변경 XamlTabSpaceDialog.xaml 대화상자의 배치 정의 XamlTabSpaceDialog.cs XamlCruncher.cs Tab Space 메뉴 선택 시 위 대화상자 호출 public intTabSpaces { set { txtbox.Text = value.ToString(); } get { return Int32.Parse(txtbox.Text);} } void TextBoxOnTextChanged(object sender,TextChangedEventArgsargs) { intresult; btnOk.IsEnabled = (Int32.TryParse(txtbox.Text, out result) && result > 0 && result < 11); } void OkOnClick(object sender, RoutedEventArgsargs) { DialogResult = true; }
27. 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”
28. 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.FillAttr=“Whatever”> … </Polygon.Fill> (프로퍼티는프로퍼티 가질 수 없음)