UI要素を更新しないコードで定義されたWPFデータバインディングの問題
-
03-07-2019 - |
質問
実行時に実装されるため、新しいUI要素とデータバインディングをコードで定義する必要があります。これが私がやろうとしていることの簡略版です。
データモデル:
public class AddressBook : INotifyPropertyChanged
{
private int _houseNumber;
public int HouseNumber
{
get { return _houseNumber; }
set { _houseNumber = value; NotifyPropertyChanged("HouseNumber"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string sProp)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(sProp));
}
}
}
コードでのバインド:
AddressBook book = new AddressBook();
book.HouseNumber = 123;
TextBlock tb = new TextBlock();
Binding bind = new Binding("HouseNumber");
bind.Source = book;
bind.Mode = BindingMode.OneWay;
tb.SetBinding(TextBlock.TextProperty, bind); // Text block displays "123"
myGrid.Children.Add(tb);
book.HouseNumber = 456; // Text block displays "123" but PropertyChanged event fires
データが最初にバインドされると、テキストブロックは正しいハウス番号で更新されます。その後、後でコードで家番号を変更すると、ブックのPropertyChangedイベントが発生しますが、テキストブロックは更新されません。誰にもその理由を教えてもらえますか?
ありがとう、 ベン
解決
その根本は、PropertyChangedEventArgsに渡した文字列がプロパティの名前と完全に一致しなかったことです。次のようなものがありました:
public int HouseNumber
{
get { return _houseNumber; }
set { _houseNumber = value; NotifyPropertyChanged("HouseNum"); }
}
これが必要な場所:
public int HouseNumber
{
get { return _houseNumber; }
set { _houseNumber = value; NotifyPropertyChanged("HouseNumber"); }
}
いいね!正しい方向に押してくれてありがとう。
他のヒント
他の AddressBook
参照ではなく、バインディングで使用された AddressBook
参照を更新していることを確認してください。
指定したAddressBookコードを操作するために次のものを入手しました。
<StackPanel>
<Button Click="Button_Click">Random</Button>
<Grid x:Name="myGrid">
</Grid>
</StackPanel>
コードビハインド:
public partial class Window1 : Window
{
private AddressBook book;
public Window1()
{
InitializeComponent();
book = new AddressBook();
book.HouseNumber = 13;
TextBlock tb = new TextBlock();
Binding bind = new Binding("HouseNumber");
bind.Source = book;
tb.SetBinding(TextBlock.TextProperty, bind);
myGrid.Children.Add(tb);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Random rnd = new Random();
book.HouseNumber = rnd.Next();
}
}
更新コードで同じ参照が使用されていることに注意してください。
バインディングモードをプログラムで設定する必要がありますか?デフォルトはOneTimeです。
コードをカットアンドペーストしました(そして少し追加しました)。
public Window1()
{
InitializeComponent();
AddressBook book = new AddressBook();
book.HouseNumber = 123;
TextBlock tb = new TextBlock();
Binding bind = new Binding("HouseNumber");
bind.Source = book;
bind.Mode = BindingMode.OneWay;
tb.SetBinding(TextBlock.TextProperty, bind); // Text block displays "123"
myGrid.Children.Add(tb);
book.HouseNumber = 456;
}
private void TestButton_Click(object sender, RoutedEventArgs e)
{
AddressBook book =
(AddressBook(TextBlock)
myGrid.Children[0])
.GetBindingExpression(TextBlock.TextProperty)
.DataItem;
book.HouseNumber++;
}
起動時に456を表示し、ボタンをクリックすると、TextBlockの数値が正常にインクリメントされます。
おそらく、あなたは間違った場所で問題の原因を探しているのでしょうか?
バインディングで使用したのと同じオブジェクトを更新しますか?一見何も問題がないように見えるので、簡単なことを確認してください。 :)
フィールド( _houseNumber
)を直接設定して、コードがプロパティをバイパスしますか?