수색…
통사론
<TextBlock Text="{Binding Title}"/><TextBlock Text="{Binding Path=Title}"/><TextBlock> <TextBlock.Text> <Binding Path="Title"/> </TextBlock.Text> </TextBlock>
비고
이러한 모든 태그는 동일한 결과를 생성합니다.
문자열을 Text 속성에 바인딩
런타임에 UI 내용을 변경하려면 Binding 을 사용할 수 있습니다. 바인딩 된 속성이 코드에서 변경되면 UI에 표시됩니다.
<TextBlock Text="{Binding Title}"/>
UI에 변경 사항을 알리려면 속성이 INotifyPropertyChanged 인터페이스에서 PropertyChanged 이벤트를 발생 시키거나 Dependency Property 사용해야합니다.
"제목"속성이 xaml.cs 파일 또는 XAML 의 Datacontext 클래스에 있으면 바인딩이 작동합니다.
Datacontext는 XAML에서 직접 설정할 수 있습니다.
<Window x:Class="Application.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Application">
<Window.DataContext>
<local:DataContextClass/>
</Window.DataContext>
문자열 바인딩 서식 지정
예를 들어 날짜와 같은 무언가의 바인딩을 만들 때 특정 형식으로 코드에 숨기지 않고 표시 할 수 있습니다.
이렇게하려면 StringFormat 속성을 사용할 수 있습니다.
여기 예시들이 있습니다 :
Text="{Binding Path=ReleaseDate, StringFormat=dddd dd MMMM yyyy}"
내 날짜 형식은 다음과 같습니다.
2016 년 8 월 16 일 화요일
다음은 온도의 또 다른 예입니다.
Text="{Binding Path=Temp, StringFormat={}{0}°C}"
이 형식은 다음과 같습니다.
25 ° C
INotifyPropertyChanged의 기본 사항
정적 객체 만 표시하고 상호 관련 객체의 변경 사항에 UI가 응답하도록하려면 INotifyPropertyChanged 인터페이스의 기본 사항을 이해해야합니다.
MainWindow 다음과 같이 정의했다고 가정합니다.
<Window x:Class="Application.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:Application.ViewModels>
<Window.DataContext>
<vm:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<TextBlock Text={Binding Path=ApplicationStateText}" />
</Grid>
</Window>
우리의 Viewmodel-Class MainWindowViewModel 다음과 같이 정의했다.
namespace Application.ViewModels
{
public class MainWindowViewModel
{
private string _applicationStateText;
public string ApplicationStateText
{
get { return _applicationStateText; }
set { _applicationStateText = value; }
}
public MainWindowViewModel()
{
ApplicationStateText = "Hello World!";
}
}
}
응용 프로그램의 TextBlock은 바인딩으로 인해 텍스트 Hello World를 표시합니다. 런타임 동안 ApplicationStateText가 변경되면 UI에 이러한 변경 사항이 통지되지 않습니다.
이것을 구현하기 위해 우리의 DataSource는이 경우 MainWindowViewModel 인터페이스 INotifyPropertyChanged 를 구현해야합니다. 이것에 의해, Bindings 가 PropertyChangedEvent 에 등록 할 수있게됩니다.
ApplicationStateText 속성을 다음과 같이 변경할 때마다 PropertyChangedEventHandler 를 호출하면됩니다.
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Application.ViewModels
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged( [CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _applicationStateText;
public string ApplicationStateText
{
get { return _applicationStateText; }
set
{
if (_applicationStateText != value)
{
_applicationStateText = value;
NotifyPropertyChanged();
}
}
}
public MainWindowViewModel()
{
ApplicationStateText = "Hello World!";
}
}
}
TextBlock.Text 의 Binding 이 실제로 PropertyChangedEvent 수신하는지 확인하십시오.
<Window x:Class="Application.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:Application.ViewModels">
<Window.DataContext>
<vm:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<TextBlock Text={Binding Path=ApplicationStateText, UpdateSourceTrigger=PropertyChanged }" />
</Grid>
</Window>
INotifyPropertyChanged 및 INotifyCollectionChanged를 사용하여 개체 컬렉션에 바인딩
User 객체의 Properties가 프로그램 적으로 업데이트 될 수있는 ViewModel 의 Users 속성 아래에 나열된 모든 User 객체를 표시하기로되어있는 ListView 가 있다고 가정합니다.
<ListView ItemsSource="{Binding Path=Users}" >
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type models:User}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,3,15,3"
Text="{Binding Id, Mode=OneWay}" />
<TextBox Width="200"
Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Delay=450}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
User 객체에 대해 올바르게 구현 된 INotifyPropertyChanged Beeing에도 불구하고
public class User : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _id;
private string _name;
public int Id
{
get { return _id; }
private set
{
if (_id == value) return;
_id = value;
NotifyPropertyChanged();
}
}
public string Name
{
get { return _name; }
set
{
if (_name == value) return;
_name = value;
NotifyPropertyChanged();
}
}
public User(int id, string name)
{
Id = id;
Name = name;
}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
ViewModel 객체의 경우
public sealed class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private List<User> _users;
public List<User> Users
{
get { return _users; }
set
{
if (_users == value) return;
_users = value;
NotifyPropertyChanged();
}
}
public MainWindowViewModel()
{
Users = new List<User> {new User(1, "John Doe"), new User(2, "Jane Doe"), new User(3, "Foo Bar")};
}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
사용자에 대한 변경이 프로그래밍 방식으로 이루어진 경우 UI가 업데이트되지 않습니다.
이는 List 인스턴스 자체에 INotifyPropertyChanged 만 설정했기 때문입니다. Element의 한 속성이 변경되면 List가 완전히 다시 인스턴스화 된 경우에만 UI가 업데이트됩니다.// DO NOT DO THIS
User[] userCache = Users.ToArray();
Users = new List<User>(userCache);
그러나 이것은 매우 귀찮고 믿을 수 없을만큼 성능이 나쁘다.
사용자의 ID와 이름을 모두 보여주는 100,000 개의 요소 목록이있는 경우 각 요소를 다시 작성해야하는 200,000 개의 데이터 바인딩이 있습니다. 이로 인해 변경 사항이있을 때마다 사용자에게 지연 될 수 있습니다.
List<T> 대신 System.ComponentModel.ObservableCollection<T> 사용할 수 있습니다. private ObservableCollection<User> _users;
public ObservableCollection<User> Users
{
get { return _users; }
set
{
if (_users == value) return;
_users = value;
NotifyPropertyChanged();
}
}
ObservableCollection 은 CollectionChanged 이벤트를 제공하고 INotifyPropertyChanged 자체를 구현합니다. MSDN 에 따르면 이벤트는 "[..] 항목이 추가 , 제거 , 변경 , 이동 되거나 전체 목록이 새로 고쳐질 때"상승합니다.
.NET 4.5.2 이전 버전에서는 ObservableCollection 이 Collection ObservableCollection Event를 발생시키지 않을 것 입니다.
TrulyObservableCollection<T> 포함하지 않는 INotifyPropertyChanged 대한 제약 T 우리가 필요로하는 모든 것을 갖고 어떠했는지를 노출 T 구현 INotifyPropertyChanged 여부 : /*
* Original Class by Simon @StackOverflow http://stackoverflow.com/a/5256827/3766034
* Removal of the INPC-Constraint by Jirajha @StackOverflow
* according to to suggestion of nikeee @StackOverflow http://stackoverflow.com/a/10718451/3766034
*/
public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
{
private readonly bool _inpcHookup;
public bool NotifyPropertyChangedHookup => _inpcHookup;
public TrulyObservableCollection()
{
CollectionChanged += TrulyObservableCollectionChanged;
_inpcHookup = typeof(INotifyPropertyChanged).GetTypeInfo().IsAssignableFrom(typeof(T));
}
public TrulyObservableCollection(IEnumerable<T> items) : this()
{
foreach (var item in items)
{
this.Add(item);
}
}
private void TrulyObservableCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (NotifyPropertyChangedHookup && e.NewItems != null && e.NewItems.Count > 0)
{
foreach (INotifyPropertyChanged item in e.NewItems)
{
item.PropertyChanged += ItemPropertyChanged;
}
}
if (NotifyPropertyChangedHookup && e.OldItems != null && e.OldItems.Count > 0)
{
foreach (INotifyPropertyChanged item in e.OldItems)
{
item.PropertyChanged -= ItemPropertyChanged;
}
}
}
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
OnCollectionChanged(args);
}
}
우리의 ViewModel에서 Property Users 를 TrulyObservableCollection<User> 로 정의하십시오
private TrulyObservableCollection<string> _users;
public TrulyObservableCollection<string> Users
{
get { return _users; }
set
{
if (_users == value) return;
_users = value;
NotifyPropertyChanged();
}
}
이제 모든 단일 Binding 을 다시 만들 필요없이 컬렉션 내의 요소에 대한 INPC-Property가 변경되면 UI에 알림이 표시됩니다.