UWP(Universal Windows Platform) 소개 — 빠른 시작
Categories:
- 1. Xaml
- 2. MVVM
- 3. ViewModel과 Model의 상호작용
- 4. View와 ViewModel의 상호작용
- 5. (View와 ViewModel) 알림 구현 – INotifyPropertyChanged
- 6. (View와 ViewModel) ListView를 알림 가능한 소스에 바인딩 – ObservableCollection
- 7. (View) ListView의 Item 템플릿(DataTemplate | UserControl)
- 8. (ViewModel과 Model) 데이터 변환 – IValueConverter
- 9. (View) Control 스타일 수정
- 10. Panel 사용
- 11. (View) 적응형 UI (Adaptive UI)
- 12. 레이아웃 원칙
- 13. 지역화(Localization)
- 14. 명명 규칙
- 15. 주의사항
1. Xaml
1.1. XAML 소개
- XAML 개요
- 주로 시각적 UI 요소 생성에 사용됨.
- Xaml 기본 문법은 XML 기반.
- 네임스페이스 별칭 선언:
xmlns:controls="using:Common.Controls"
- 네임스페이스에 선언된 클래스 사용:
<controls:MyControl />
재사용 가능한 리소스(Resource),
x:Key
<Style x:Key="TextBlock_Style" />
- 컨트롤 요소 이름,
x:Name
Xaml:
<MyControl x:Name="myControl" />
C#:
private MyControl myControl;
지역화
x:Uid
<TextBlock x:Uid="sampleText" />
1.2. 가장 기본적인 컨트롤(Control) – TextBlock, Button
<Page x:Class="MyPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBlock Text="UWP 소개" />
<Button Content="UWP 소개" Click="Button_Click" />
</StackPanel>
</Page>
2. MVVM

- View는 가능한 UI 표시 내용만 포함, View는 대부분 Xaml 언어로 작성;
- ViewModel은 비즈니스 처리 로직을 포함하지 않고 Model의 함수를 호출하여 작업 수행;
- Model은 가능한 모든 비즈니스 데이터와 로직을 포함하며 View 및 ViewModel에 의존하지 않도록 함;
3. ViewModel과 Model의 상호작용
3.1. ViewModel이 Model 데이터 조작
ViewModel:
public class ViewModel
{
private Model model;
private ChangeA()
{
this.model.A = "A";
}
}
Model:
public class Model
{
public string A { get; set; }
public string B { get; set; }
}
3.2. Model이 ViewModel에 알림 – event
ViewModel:
public class ViewModel
{
private Model model;
private ChangeA()
{
r.BEventArgs += this.Handler;
}
private void Handler(object sender, EventArgs e)
{
AnyActions();
}
}
Model:
public delegate void BChangedHandler(object sender, EventArgs e);
public class Model
{
public string A { get; set; }
private string _B;
public string B
{
get { return this._B; }
set
{
this._B = value;
if (BEventArgs != null)
{
BEventArgs(this, new EventArgs());
}
}
}
public event BChangedHandler BEventArgs;
}
4. View와 ViewModel의 상호작용
4.1. 데이터 바인딩
- 데이터 바인딩 개요
- DependencyProperty만 바인딩 가능
- Public Property에 바인딩
- 리팩토링 시 주의
4.1.1. ViewModel에 바인딩
View:
<TextBlock Text={Binding SampleText} />
ViewModel:
public string SampleText { get; set; }
4.1.2. 다른 Control에 바인딩
View:
<TextBlock x:Name="TextBlock1" Text="SampleText" />
<Button Content="{Binding ElementName=TextBlock1, Path= Text}" />
4.1.3. DataContext 지정
public ViewModelClass ViewModel { get; set; }
...
SpecifiedControl.DataContext = ViewModel;
...
5. (View와 ViewModel) 알림 구현 – INotifyPropertyChanged
SampleText가 변경될 때, 이 property에 바인딩된 DependencyProperty에 알림
public class MyControlViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void Notify(string propName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
private string _sampleText;
public string SampleText
{
get
{
return _sampleText;
}
set
{
_sampleText = value;
Notify(nameof(SampleText));
}
}
}
또는 ViewModelBase 상속
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void Notify(string propName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
6. (View와 ViewModel) ListView를 알림 가능한 소스에 바인딩 – ObservableCollection

ListView에서 알림 가능한 ItemSource에 바인딩 구현
View:
<ListView ItemsSource="{Binding Items}">
ViewModel:
public ObservableCollection<Recording> Items { get; set; }
- ObservableCollection은 Item 추가/제거, 전체 목록 새로고침 시에만 알림 발생;
- item Recording의 내용 변경 시 UI에 알리려면 Recording이 INotifyPropertyChanged를 구현해야 함.
7. (View) ListView의 Item 템플릿(DataTemplate | UserControl)
7.1. DataTemplate
View:
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate DataType="local:Recording">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding A}" />
<TextBlock Text="{Binding B}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ViewModel:
public ObservableCollection<RecordingViewModel> Items { get; set; }
public class RecordingViewModel : INotifyPropertyChanged
{
...
INotifyPropertyChanged 구현
...
private Recording _recording;
public string A
{
get
{
return this._recording.A;
}
set
{
this._recording.A = value;
Notify(nameof(A));
}
}
public string B { get; set; } = this._recording.B;
public RecordingViewModel (Recording recording)
{
this._recording = recording;
}
}
Model:
public class Recording
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
... ...
}
비교:

7.2. UserControl
7.2.1. DependencyProperty
- Dependency Properties 개요
- DependencyProperty만 다른 property에 바인딩 가능, 바인딩만 View에 알림 구현 가능
- 우선순위 가짐
View:
<control:MyControl Text="앱이 검색 중입니다" IsSearching="{Binding ViewModel.IsSearching}" />
ViewModel:
public class MyControl
{
...
public static readonly DependencyProperty IsSearchingProperty =
DependencyProperty.Register
(
"IsSearching", typeof(Boolean),
typeof(MyControl), null
);
public bool IsSearching
{
get { return (bool)GetValue(IsSearchingProperty); }
set { SetValue(IsSearchingProperty, value); }
}
...
}
8. (ViewModel과 Model) 데이터 변환 – IValueConverter
IValueConverter를 사용하여 ViewModel과 Model 간 데이터 변환 가능.
public class ShowAllButtonVisibilityConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is IList)
{
int count = (value as IList).Count;
if (count > 3)
{
return Windows.UI.Xaml.Visibility.Visible;
}
}
return Windows.UI.Xaml.Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value is IList)
{
int count = (value as IList).Count;
if (count > 3)
{
return Windows.UI.Xaml.Visibility.Visible;
}
}
return Windows.UI.Xaml.Visibility.Collapsed;
}
9. (View) Control 스타일 수정
9.1. Control 내에서 스타일 커스터마이징
View:
<TextBlock Foreground="Red" Text="샘플 텍스트" />
9.2. 통합 스타일 사용 – ResourceDictionary
View:
<Window.Resources>
<ResourceDictionary>
<Style TargetType="TextBlock" x:Key="ImportantText">
<Setter Property="Foreground" Value="Red" />
</Style>
</ResourceDictionary>
</Window.Resources>
...
<TextBlock Text="샘플 텍스트" Style={StaticResource ImportantText} />
9.3. ThemeResource 사용
View:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<Style TargetType="TextBlock" x:Key="ImportantText">
<Setter Property="Foreground" Value="Red" />
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<Style TargetType="TextBlock" x:Key="ImportantText">
<Setter Property="Foreground" Value="Yellow" />
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<Style TargetType="TextBlock" x:Key="ImportantText">
<Setter Property="Foreground" Value="Black" />
</Style>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Window.Resources>
...
<TextBlock Text="샘플 텍스트" Style={ThemeResource ImportantText} />
10. Panel 사용
10.1. Grid
특징:
- 기본 Height/Width는 부모 요소와 동일;
권장:
- Grid 내에서 자식 요소의 레이아웃 크기 정의;
- 비율로 표시;
10.2. StackPanel
특징:
- 부모 요소 경계를 초과할 수 있음;
- Height 또는 Width가 Panel 내 요소에 따라 변경;
권장:
- Padding과 비율 유연하게 사용;
- 부모 요소에서 StackPanel의 Width 또는 Height에 값을 지정하여 Control이 경계를 벗어나지 않도록 방지;
11. (View) 적응형 UI (Adaptive UI)
- VisualStateManager.VisualStateGroup 사용
<VisualStateGroup>
<VisualState x:Name="WideLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger x:Name="WideLayoutTrigger" MinWindowWidth="1280" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="SystemUpdateSideGrid.Width" Value="800" />
<Setter Target="SystemUpdateSideGrid.Grid.Row" Value="0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="MidLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger x:Name="MidLayoutTrigger" MinWindowWidth="700" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="SystemUpdateSideGrid.Width" Value="400" />
<Setter Target="SystemUpdateSideGrid.Grid.Row" Value="1" />
</VisualState.Setters>
</VisualState>
...
</VisualStateGroup>
12. 레이아웃 원칙
- 요소 크기를 명시적으로 설정하지 않음;
- 화면 좌표로 요소 위치 지정하지 않음;
- 컨테이너 내 자식 요소는 사용 가능한 공간 공유;
- 중첩 가능한 레이아웃 컨테이너;
13. 지역화(Localization)
- x:Uid 사용, 요소의 고유 식별자
<TextBlock x:Uid="S_TextBlock1" />
- 리소스 파일 사용
<data name="S_TextBlock1.Text" xml:space="preserve">
<value>샘플 텍스트</value>
</data>
14. 명명 규칙
대문자 카멜 케이스 big camel-case: firstName
소문자 카멜 케이스 little camel-case: FirstName
- Class: 대문자 카멜 케이스
- Property: 대문자 카멜 케이스
- Field: 소문자 카멜 케이스 + “_” 접두사
- Xaml의 Control: 소문자 카멜 케이스
15. 주의사항
- ViewModel의 Property 이름 변경 시 주의, Xaml의 Binding 이름은 리팩토링을 따라가지 않음;