サーチ…


構文

  • <TextBlock Text="{Binding Title}"/>

  • <TextBlock Text="{Binding Path=Title}"/>

  • <TextBlock> <TextBlock.Text> <Binding Path="Title"/> </TextBlock.Text> </TextBlock>

備考

これらのタグはすべて同じ結果を生成します。

テキストプロパティに文字列をバインドする

実行時にUIコンテンツを変更するには、 Bindingを使用できます。バインドされたプロパティがコードから変更されると、UIに表示されます。

<TextBlock Text="{Binding Title}"/>

変更をUIに通知するには、プロパティがPropertyChangedイベントをINotifyPropertyChangedインターフェイスからINotifyPropertyChangedか、 Dependency Propertyを使用する必要があります。

プロパティ "Title"が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℃

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クラスで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を実装する必要があります。これにより、 BindingsPropertyChangedEventに登録できるようになります。
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オブジェクトのプロパティをプログラムで更新できる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を設定しているためです。エレメントの1つのプロパティーが変更された場合にのみ、リストを完全に再インスタンス化した場合のみ、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();
    }
}

ObservableCollectionCollectionChangedイベントを提供し、 INotifyPropertyChanged自体を実装します。 MSDNによると、イベントは "[..]アイテムが追加削除変更移動 、またはリスト全体が更新さ れたときに上昇します"。
ただし、 ここで説明したように、コレクションの要素のプロパティが変更され場合、.NET 4.5.2以前ではObservableCollectionはCollectionChangedイベントを発生させません。

続いて、このソリューション我々は単に私たち自身を実装することができます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);
    }
}

プロパティ・UsersをViewModelのTrulyObservableCollection<User>として定義します

private TrulyObservableCollection<string> _users;
public TrulyObservableCollection<string> Users
{
    get { return _users; }
    set
    {
        if (_users == value) return;
        _users = value;
        NotifyPropertyChanged();
    }
}

私たちのUIは、Collection内の要素のINPC-Propertyが変更されるたびに通知され、すべての単一のBindingを再作成する必要はありません。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow