Transcript DataBind
강남 DataBinding 스타일
Windows 8 앱개발자라면 꼭 알아야할
개발자가 알아야할 Binding
Non-DataBinding vs. DataBinding
<Grid>
<TextBlock x:Name=“TitleText”/>
<TextBlock x:Name=“SubTitleText”/>
</Grid>
<Grid>
<TextBlock Text=“{Binding Title}”/>
<TextBlock Text=“{Binding SubTitle}”/>
</Grid>
TitleText.Text = item.Title;
SubTitleText.Text = item.SubTitle;
this.DataContext = item;
버튼 누가 지웠어!
Non-DataBinding vs. DataBinding
<Grid>
<HyperlinkButton />
<Grid>
</Grid>
</Grid>
TitleText.Text = item.Title;
SubTitleText.Text = item.SubTitle;
this.DataContext = item;
컴파일 에러 발생!!!
컴파일 에러 없음
UI와 코드의 분리
개발자와 디자이너 업무영역의 분리
PEACE!
<HyperlinkButton Content=“{Binding Title}”/>
이번 앨범 타이틀 곡이 뭐야?
문맥
문맥
문맥 = Context
DataContext
FrameworkElement.DataContext
거의 모든 UI는 FrameworkElement
가정
class Chart
+ Album FirstAlbum
+ List<Album> Albums
class Album
+ string CoverArt
+ string Name
+ Artist Artist
class Artist
+ string ProfilerImage
+ string Name
자식에게 상속하는 DataContext
Visual Tree
Grid(LayoutRoot)
Image
TextBlock
Grid
Image
TextBlock
<Grid x:Name=“LayoutRoot”
DataContext=“{Binding TopAlbum}”>
<Image Source=“{Binding CoverArt}”/>
<TextBlock Text=“{Binding Title}”/>
<StackPanel DataContext=“{Binding Artist}”>
<Image Source=“{Binding ProfileImage}”/>
<TextBlock Text=“{Binding Name}”/>
</StackPanel>
</Grid>
자식에게 상속하는 DataContext
Visual Tree
Grid(LayoutRoot)
Image
TextBlock
Grid
Image
TextBlock
<Grid x:Name=“LayoutRoot”
DataContext=“{Binding TopAlbum}”>
<Image Source=“{Binding CoverArt}”/>
<TextBlock Text=“{Binding Title}”/>
<StackPanel>
<Image Source=“{Binding Artist.ProfileImage}”/>
<TextBlock Text=“{Binding Artist.Name}”/>
</StackPanel>
</Grid>
DataContext 주입법
In C#
var chart = GetKPopChart();
this.DataContext = chart;
In XAML
<Page>
<Page.Resources>
<models:KPopChart x:Key=“Chart” />
</Page.Resources>
<Grid DataContext=“{StaticResource Chart}”>
…..
</Grid>
</Page>
<Page>
<Page.DataContext>
<models:KPopChart />
</Page.DataContext>
<Grid >
…..
</Grid>
</Page>
Binding
문법
•
Binding
–
•
Path (생략가능)
–
•
Text=“{Binding Name, Source={StaticResource MyViewModel}}”
Converter
–
•
Text=“{Binding Path=Title}”
Source
–
•
Text="{Binding Title}"
Text=“{Binding PublishDate, Converter={StaticResource FamiliarDateString}}”
ConverterParameter
–
Text=“{Binding Price, Converter={StaticResource CurrencyConverter},
ConverterParameter=\{0:C2\}}”
{Binding }
•
DataContext 자기 자신!
<TextBlock Text=“{Binding }” />
ItemsControl
ItemsControl 가족
•
•
•
•
•
ListView
GridView
FlipView
ListBox
ComboBox
Control
ItemsControl
.ItemsSource 프로퍼티가 여기 정의
Selector
ListViewBase
ListView
GridView
FlipView
ListBox
ComboBox
ItemsControl에서 DataContext 분배
CS에서
var artists = new List<Artist>()
{
new Artist() { Name = “싸이”, CoverArt=“…”},
new Artist() { Name = “아이유”, CoverArt=“…”},
new Artist() { Name = “싸이”, CoverArt=“…”},
new Artist() { Name = “아이유”, CoverArt=“…”},
}
this.Artists = artist;
….
XAML에서
<ListView ItemsSource=“{Binding Artists}” />
싸이
아이유
싸이
아이유
ItemTemplate과 DataContext
new Artist()
{
Name = “싸이”,
CoverArt=“…”,
}
ItemsSource의 인스턴스 하나가
ListViewItem 하나의 DataContext가
된다.
싸이
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel>
<Image Source=“{Binding CoverArt}” />
<TextBlock Text=“{Binding Name}” />
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
In the hood
ItemsControl의 virtual PrepareContainerForItemOverride(…) 에서
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var contentControl = element as ContentControl;
contentControl.ContentTemplate = this.ItemTemplate;
contentControl.DataContext = item;
}
INotifyPropertyChanged
INotifyCollectionChanged
약속
컨트롤은 INotifyPropertyChanged.PropertyChanged를 구독합니다.
컨트롤은 INotifyCollectionChanged.CollectionChanged를 구독합니다.
Common/BindableBase.cs 에서
public abstract class BindableBase : INotifyPropertyChanged
System.Collections.ObjectModel
public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged
이미 구현되어 있는 것
DataModel/SampleDataSource.cs에서
public abstract class SampleDataCommon : App4.Common.BindableBase
프로퍼티 예 : Title
private string _title = string.Empty;
public string Title
{
get { return this._title; }
set { this.SetProperty(ref this._title, value); }
}
In the Hood
protected bool SetProperty<T>(ref T storage, T value,
[CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
}
storage = value;
this.OnPropertyChanged(propertyName);
return true;
List<Artist> vs. ObservableCollection<Artist>
this.Artist.Add(new Artist());
this.Artist.Add(new Artist());
싸이
싸이
아이유
아이유
싸이
싸이
아이유
Converter
어떤 필요, 어떤 니즈?
public List<string> Artists { get; set; }
…
Artists = new List<string>()
{
“싸이”,
“아이유”,
};
너랑 나랑 강남스타일
싸이, 아이유
샘플 ArtistConverter
namespace MyApp
{
public class ArtistConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
// null 체크, value가 Ienumerable 타입이 아닐 때 예외처리 (생략)
var list = value as IEnumerable;
StringBuilder sb = new StringBuilder();
foreach (var item in list)
{
if (sb.Length > 0)
sb.Append(“, “);
sb.Append((string)item);
}
return sb.ToString();
}
}
}
사용법
인스턴스 생성 (어딘가에) -> 바인딩 식에서 잘 사용
In MyView.xaml (or App.xaml)
<Page>
<Page.Resources>
<conv:ArtistConverter x:Key=“ArtistConverter”/>
</Page.Resources>
<Grid x:Name=“LayoutRoot”>
…
<TextBlock Text=“{Binding Artists,
Converter={StaticResource ArtistConverter}”/>
</Grid>
</Page>
너랑 나랑 강남스타일
싸이, 아이유
Blend 도와줘!
Sample Project
Code Review
GridApp 샘플 프로젝트에서
GroupedItemsPage.xaml.cs에서
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var sampleDataGroups = SampleDataSource.GetGroups((String)navigationParameter);
this.DefaultViewModel["Groups"] = sampleDataGroups;
}
GroupedItemsPage.xaml에서
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="App4.GroupedItemsPage"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}“
…
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
FIN
즐거운 해커쏜(θ) 되세요!