INotifyPropertyChanged
ユーザーコントロールの依存プロパティであるデータ構造があります。データ構造のプロパティの 1 つが、コントロールの要素の 1 つにバインドされています。
MyData.cs (MVVM Light を使用して実装INotifyPropertyChanged
):
public class MyData : ObservableObject
{
private string _text;
public string Text
{
get { return _text; }
set { Set(() => Text, ref _text, value); }
}
public override string ToString()
{
return Text;
}
}
TextControl.xaml:
<UserControl x:Class="UITester.TextControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Name="This"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox Text="{Binding ElementName=This, Path=Data.Text, Mode=TwoWay}"></TextBox>
</Grid>
</UserControl>
TextControl.xaml.cs:
public partial class TextControl : UserControl
{
public static MyData DefaultData = new MyData {Text = "Default"};
public MyData Data
{
get { return (MyData)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(MyData), typeof(TextControl), new PropertyMetadata(DefaultData));
public TextControl()
{
InitializeComponent();
}
}
DataProperty
ここで私が望むのは、内部プロパティの 1 つが変更されるたびに、依存関係プロパティが更新される (つまり、変更されたことに関心のある人に通知される) ことです。
これを 2 つの方法でテストします。
依存関係プロパティ
Data
をLabel
そして、依存関係プロパティを作成し
MyControlText
、コントロールと aMainWindow
の両方をそれにバインドします。Data
Label
MainWindow.xaml:
<Window x:Class="UITester.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:uiTester="clr-namespace:UITester"
Title="MainWindow" Height="350" Width="525"
x:Name="me">
<StackPanel DataContext="{Binding ElementName=me}">
<uiTester:TextControl x:Name="MyControl" Data="{Binding ElementName=me, Path=MyControlText}"></uiTester:TextControl>
<Label Content="{Binding ElementName=MyControl, Path=Data}"></Label>
<Label Content="{Binding ElementName=me, Path=MyControlText}"></Label>
<Button Click="SetButtonClick">Set</Button>
<Button Click="ResetButtonClick">Reset</Button>
</StackPanel>
</Window>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
private readonly Dictionary<int, int> _selected = new Dictionary<int, int>();
public MainWindow()
{
InitializeComponent();
//list.ItemsSource = _selected.Values;
}
private void SetButtonClick(object sender, RoutedEventArgs e)
{
MyControlText = new MyData{Text = "new"};
}
private void ResetButtonClick(object sender, RoutedEventArgs e)
{
MyControlText = null;
}
public MyData MyControlText
{
get { return (MyData)GetValue(MyControlTextProperty); }
set { SetValue(MyControlTextProperty, value); }
}
// Using a DependencyProperty as the backing store for MyControlText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyControlTextProperty =
DependencyProperty.Register("MyControlText", typeof(MyData), typeof(MainWindow), new PropertyMetadata(new MyData{ Text = ""}));
}
TextBox
コントロールの内部を変更すると、依存関係プロパティData
が更新され、その結果、両方のLabel
s が更新されます。
これはうまくいかなかったので、プロパティを明示的に変更するために登録しようとしました:
public partial class TextControl : UserControl
{
public static MyData DefaultData = new MyData {Text = "Default"};
public MyData Data
{
get { return (MyData)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(MyData), typeof(TextControl), new PropertyMetadata(DefaultData) { PropertyChangedCallback = TextPropertyChanged });
private static void TextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var c = (TextControl) d;
if (e.NewValue != null)
{
((MyData) e.NewValue).PropertyChanged += (s, ea) =>
{
c.GetBindingExpression(DataProperty).UpdateSource();
};
}
}
public TextControl()
{
InitializeComponent();
}
}
このように、新しい依存関係プロパティを設定するたびに、そのプロパティのいずれかが変更されたイベントに登録されると考えました。ハンドラーでは、依存関係プロパティにバインドされているすべての要素を更新したいと考えていました。しかし、これもうまくいきませんでした...
コードにブレークポイントを配置すると実際に壊れるため、コントロール内のバインディングが機能することはわかっていUpdateSource
ますが、依存関係プロパティ全体を更新する方法がわかりません(それにバインドされているラベルとともに)。
更新:「d.InvalidateProperty(DataProperty);」も呼び出そうとしました。「c.GetBindingExpression(DataProperty).UpdateSource();」の代わりに しかし、それもうまくいきませんでした...