0

私は Silverlight の初心者で、単純な Silverlight バインド サンプルを機能させることができません!

ロード中にリスト内のドキュメントの数を表示するビューモデルを作成する必要があります。

INotifyPropertyChanged を実装する基本クラスを作成しました。

public abstract class BaseViewModel : INotifyPropertyChanged {

    protected BaseViewModel() {}


    #region INotifyPropertyChanged Members

    protected void OnPropertyChanged(string propertyName) {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

「CountDocs」プロパティを持つ子クラスを作成しました。

public class DocumentViewModel : BaseViewModel {

    public DocumentViewModel () {
    ...
    }

...

    public int CountDocs {
        get { return countDocs; }
        set {
            if (countDocs != value) {
                countDocs = value;
                OnPropertyChanged("CountDocs");
            }
        }
    }

    public int countDocs;

}

次の内容の DocumentViewModel.xaml があります。

<UserControl 
...
xmlns:vm="clr-namespace: ... .ViewModels" >
...
<UserControl.Resources>
    <vm:DocumentViewModel  x:Key="viewModel"/>
</UserControl.Resources>
...
<TextBlock x:Name="CounterTextBlock" Text="{Binding Source={StaticResource viewModel}, Path=CountDocs}"></TextBlock>

つまり、子クラスの名前空間について言及し、子クラスのリソースをキー「viewModel」で作成し、テキストブロックのバインディングをこのオブジェクトのプロパティ「CountDocs」に入力しました。

問題は、CountDocs プロパティが TextBlock を一度だけ満たすことです: 読み込み時です。しかし、CountDocs を設定すると、TextBlock がいっぱいになりません。

バインディングの Mode プロパティを使用して DataContext を使用しようとしましたが、まだ機能しません。

バインディングに何か問題がありますか?オブジェクトの CountDocs プロパティが変更されたときに ViewModel を更新するにはどうすればよいですか?

ありがとう

4

3 に答える 3

0

あなたの質問の詳細を理解できれば、バックグラウンド スレッドで UI バインド値を更新している可能性があります (ドキュメントの読み込み時)。

UI スレッドでそれを行う必要があります。そうしないと、変更が表示されません。私たちの WPF アプリの 1 つで、これに気付くまで、ランダムな更新が消えていました。

Silverlight (および WPF) アプリで多くのマルチスレッド化を行っているため、この問題を回避するために、以下のような基本クラスに通知ヘルパーを実装しました (その他のものは削除されています)。メイン UI スレッドですべての通知メッセージをディスパッチします。試してみる:

public class ViewModelBase : INotifyPropertyChanged
{
    protected delegate void OnUiThreadDelegate();

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void SendPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            // Ensure property change is on the UI thread
            this.OnUiThread(() => this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)));
        }
    }

    protected void OnUiThread(OnUiThreadDelegate onUiThreadDelegate)
    {
        // Are we on the Dispatcher thread ?
        if (Deployment.Current.Dispatcher.CheckAccess())
        {
            onUiThreadDelegate();
        }
        else
        {
            // We are not on the UI Dispatcher thread so invoke the call on it.
            Deployment.Current.Dispatcher.BeginInvoke(onUiThreadDelegate);
        }
    }
}
于 2012-08-14T09:18:47.723 に答える
0

質問へのコメントでわかったように、ViewModel を 2 回インスタンス化し、実際にはビューにバインドされていないプロパティ値を変更しました。

それはどうしてですか?ViewModel を View に自動的に接続する MVVM フレームワークを使用しているか、コードのどこかで認識していない場所で発生しています。コンストラクターにブレークポイントを設定し、ヒットしたら、Visual Studio でコール スタックを分析します。

于 2012-08-17T08:40:53.390 に答える
0

XAML で ViewModel インスタンスを作成したので、その ViewModel にアクセスして使用する必要があります。

別のインスタンスがある場合、そのインスタンスはバインディングを更新しません。リソースで作成されたインスタンスのみが使用されます。

CountDocs プロパティを設定したとおっしゃいましたが、そのためのコードはありません。どこでそれを行う場合でも、リソースから ViewModel インスタンスを使用する必要があります。

これが、ビューのコンストラクターでビューモデルをインスタンス化し、それへの参照を保持するのが好きな理由です。また、バインディングに多数のデータ ソースをアタッチする予定がない場合は、LayoutRoot.DataContext を ViewModel インスタンスに設定し、バインディングの Source 属性を削除するだけです。

ViewModelBase _vm = null;
public MyView()
{
_vm = 新しい DocumentViewModel();
this.LayoutRoot.DataContext = _vm;
}

XAML では、 <TextBlock x:Name="CounterTextBlock" Text="{Binding CountDocs}"></TextBlock>

于 2012-08-14T12:11:36.373 に答える