7

最初に、以下のサンプルは単純化しすぎていると言いたいです。WPF コントロールをバインドしたとします。

<Window Title="Window1" Height="300" Width="300">
<Grid>
    <StackPanel>
        <TextBox Text="{Binding Name}" Margin="10"/>
        <Button HorizontalAlignment="Center" 
        Content="Click Me" Margin="5" 
        Padding="2" Click="OnButtonClick" />
    </StackPanel>
</Grid>
</Window>

INotifyPropertyChangedウィンドウは、フォームに Name セッターを実装して持つ Person クラスにバインドされます。

    public string Name 
    {
        get { return _name; }
        set 
        {
            _name = "Some Name";
            OnPropertyChanged("Name");
        }
    }

つまり、ユーザーが UI から変更しようとするたびに、_name に「ある名前」が割り当てられます。しかし、このサンプルは機能しません。TextBox の名前をいくつかの値に変更し、タブを押してフォーカスをボタンに移動させ、TextBox の値は変更されませんが、PropertyChanged イベントがトリガーされました。

なぜそれが起こるのか説明していただけますか?私が理解しているように、PropertyChangedイベントによりUIはプロパティから値を再読み取りして表示するように強制されますが、私の例では、データバインドされたテキストボックスの値は更新されません。


また。これがプロパティの不適切な実装であることは理解していますが、これは単純化しすぎていることを繰り返したいと思います。これは単なるサンプルです。とにかく、 PropertyChanged は、プロパティが変更されたため更新する必要があることを通知しますが、更新しません。

4

7 に答える 7

9

PropertyChanged イベントは、イベントのイニシエータであるため、TextBox によって無視されます。

明確化:

TextBox (またはテキスト ボックスのバインディング) は、同じ呼び出しで PropertyChanged イベントを受け取るため、自分がイニシエーターであることを認識します。非同期呼び出しを行うと、テキストボックス (またはバインディング) は自分がイニシエーターであることを知る方法がないため、他の誰かが更新したかのようにイベントを処理します。

UI に 2 番目のテキスト ボックスを追加すると、1 番目のテキスト ボックスを編集すると 2 番目のテキスト ボックスが変化することがわかります。

于 2009-01-26T19:40:23.030 に答える
4

バインディングのUpdateSourceTriggerPropertyChangedの場合、Heinziによって提案されたダミーコンバータの回避策(ここで説明)は機能しません。しかし、これが私たちに必要なものである場合はどうなりますか?

バインディングを非同期にすることでうまくいくようです。例:

SelectedIndex="{Binding SelectedIndex, IsAsync=True}"
于 2010-10-29T09:39:16.610 に答える
2

Bubblewrap が既に指摘したように、これは仕様によるものです。テキストボックスは、バインドされたプロパティを何らかの値に設定すると、セッターが値を変更しないことを前提としています。Microsoft によると、既存のコードが破損するため、この動作は変更されません。

値を変更したい場合(そうするのには十分な理由があります)、たとえばダミーのコンバーターを追加するなどの回避策を使用する必要があります。この手法について詳しく説明しているブログ エントリ(私が書いたものではありません) があります。

于 2009-09-01T14:03:15.363 に答える
0
public string MyField  
{  
    get { return _myField; }  
    set {   
        if (_myField == value)  
            return;  

        _myField = value;   

        OnPropertyChanged("MyField");  
    }  
}  

これは、プロパティの適切な実装です。

プロパティを変更するときは、オブジェクトのまったく同じインスタンスがコントロールにバインドされていることを確認してください。そうしないと、変更が通知されますが、コントロールが適切にバインドされていないため、コントロールはそれを取得しません。

于 2009-01-26T18:14:27.633 に答える
0

セッターインフォームの交換

        set 
        {
            _name = "Some Name";
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.DataBind, 
                (SendOrPostCallback)delegate { OnPropertyChanged("Name"); },
                null);
        }

問題は解決しますが、まだ開いています。プロパティが変更されたことを同期シグナリングする代わりに、非同期呼び出しを行う必要があるのはなぜですか。

于 2009-01-26T18:15:20.800 に答える
0

その理由は、セッターで「ある名前」をハードコーディングしたためです。textBox の値を変更すると、セッターが実際に呼び出され、「Some Name」を propertyValue として再度設定するため、UI で変更されていないように見えます。Put すると_name = value、物事は期待どおりに機能します。

于 2009-01-26T18:09:18.860 に答える
0

私が間違っていなければ、TextBox の Text プロパティの既定のバインド動作は TwoWay であるため、これは機能するはずです。次のように、XAML で強制的に TwoWay にすることができます。

<Window Title="Window1" Height="300" Width="300">
  <Grid>
    <StackPanel>
        <TextBox Text="{Binding Name, Mode=TwoWay}" Margin="10"/>
        <Button HorizontalAlignment="Center" 
        Content="Click Me" Margin="5" 
        Padding="2" Click="OnButtonClick" />
    </StackPanel>
  </Grid>
</Window>

Mode=TwoWayBinding 宣言の に注意してください。

それでもうまくいかない場合は、イベントを発生させたり、プロパティを割り当てたりするコードで例外がスローされていると思われます。それを探す必要があります。


UI スレッドではないスレッドで値を変更する呼び出しを行っている可能性があるようです。この場合、呼び出しをマーシャリングして UI スレッドでプロパティ変更イベントを発生させるか、UI スレッドで値を変更する必要があります。

オブジェクトが UI 要素にバインドされている場合、UI に影響を与える可能性のあるオブジェクトへの変更は、UI スレッドで行う必要があります。

于 2009-01-26T18:09:41.823 に答える