1

ViewModel がPingerViewModel着信 WCFPing()メッセージを処理する MVVM アプリがあります。このようなメッセージの処理は、Scheduler.Defaultのスレッド プールのスレッドで行われます。意味的には、着信 WCF メッセージはバインドされたプロパティCanPingを変更し、そのプロパティの PropertyChanged イベントを発生させます。

しかし、 UI イベント (ウィンドウのフォーカス/クリックなど) を受信するまでUI は更新されません。
イベントが発生するとすぐに更新するにはどうすればよいですか?

PropertyChanged イベントを発生させようとしました...

  • アプリケーションのディスパッチャーで、
  • SynchronizationContext の使用

運がなければ。

また、バインドされたプロパティが実際に適切な値に設定されていること、および PropertyChanged イベントを消費するリスナーが実際に存在することも確認しました。

ここにいくつかのコードがあります (完全なコードは github にあります):
私のビューの MainWindow.xaml の一部:
バウンドCommandは実際には着信 WCF メッセージの生成に関与しないことに注意してください。

<Button Content="Ping" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="PingBtn" VerticalAlignment="Top" Width="75" AutomationProperties.AutomationId="Ping" 
            IsEnabled="{Binding CanPing}" 
            Command="{Binding PingCommand}" />

ビューの一部 MainWindow.xaml.cs

public MainWindow()
{
    DataContext = new PingerViewModel();
    InitializeComponent();
}

私のViewModelの一部

public class PingerViewModel : INotifyPropertyChanged
    public PingerViewModel()
    {
        Pinger = new Pinger(true);
        PingCommand = new PingerPingCommand(this);
        //...
    }

    public bool CanPing
    {
        get
        {
            if (Pinger == null) return false;
            return Pinger.CanPing;
        }
    }

    public void Ping()
    {
        _pingClient.Channel.Ping();
        Pinger.CanPing = false;
        OnPropertyChanged("CanPing");
    }

    protected virtual void OnPong(PongEventArgs e)
    {
        Pinger.CanPing = true;
        OnPropertyChanged("CanPing");
    }

    public Pinger Pinger { get; private set; }

    public ICommand PingCommand { get; private set; }
    //...
}
4

3 に答える 3

3

ボタンからIsEnabled="{Binding CanPing}"を削除する必要があると思います。

ICommand オブジェクトにはCanExecuteCanExecuteChangedイベント ハンドラーが含まれているため、コマンドへのバインドで十分です。

Command クラス内に CanExecute ブール値を作成し、このクラスにも INotifyPropertyChanged を実装します。このようなもの:

public class PingCommand : ICommand, INotifyPropertyChanged
{
    private bool _canExecute;

    public bool CanExecute1
    {
        get { return _canExecute; }
        set
        {
            if (value.Equals(_canExecute)) return;
            _canExecute = value;
            CanExecuteChanged.Invoke(null, null);
            OnPropertyChanged("CanExecute1");
        }
    }

    public void Execute(object parameter)
    {
        //whatever
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute;
    }

    public event EventHandler CanExecuteChanged;
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

次に、ViewModel 内の Ping/Pong メソッドで、コマンド内のこのプロパティを更新します。

public void Ping()
{
    _pingClient.Channel.Ping();
    Pinger.CanPing = false;
    PingCommand.CanExecute1 = false;
    OnPropertyChanged("CanPing");
}

protected virtual void OnPong(PongEventArgs e)
{
    Pinger.CanPing = true;
    PingCommand.CanExecute1 = true;
    OnPropertyChanged("CanPing");
}
于 2013-08-08T12:38:20.750 に答える
0

上記のプロパティのメソッドを使用RaiseCanExecuteChanged()して更新できます。
例えば:

this.PingCommand.RaiseCanExecuteChanged();

これを試してみてください。問題が解決することを願っています。

于 2013-08-08T12:39:01.427 に答える