読者です 読者をやめる 読者になる 読者になる

しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Xamarin.Forms が Prism の DelegateCommand.CanExecuteChanged を検知しない

C# Prism Windows ランタイムアプリ Xamarin

Xamarin.Forms の Button に Command をバインドして、アクティブ/非アクティブを制御する場合、次のようなコードになると思います

#region RemoveCommand

/// <summary>
/// 削除コマンド
/// </summary>
private ICommand removeCommand;

/// <summary>
/// 削除コマンド の取得
/// </summary>
public ICommand RemoveCommand
{
    get { return this.removeCommand ?? (this.removeCommand = new DelegateCommand(this.Remove, this.CanRemove)); }
}

/// <summary>
/// アイテムの削除
/// </summary>
private void Remove()
{
    this.Items.RemoveAt(this.items.Count - 1);

    ((DelegateCommand)this.addCommand).RaiseCanExecuteChanged();
    ((DelegateCommand)this.removeCommand).RaiseCanExecuteChanged();
}

/// <summary>
/// アイテムの追加可能状態
/// </summary>
/// <returns>可能な場合<code>true</code>、それ以外は<code>false</code></returns>
private bool CanRemove()
{
    return this.items.Count > 0;
}

#endregion //RemoveCommand

でも上記のコードだと Xamarin.Forms に RaiseCanExecuteChanged によるアクティブ・非アクティブの変更通知が反映されませんでした・・・

おそらく Prism の Command が内部で弱参照*1によるイベントハンドラ保持をしていることが関係しているとは思いますが;

Xamarin のガベージコレクションはまだ不安定のようですし

#region RemoveCommand

/// <summary>
/// 削除コマンド
/// </summary>
private ICommand removeCommand;

/// <summary>
/// 削除コマンド の取得
/// </summary>
public ICommand RemoveCommand
{
    get { return this.removeCommand ?? (this.removeCommand = new Command(this.Remove, this.CanRemove)); }
}

/// <summary>
/// アイテムの削除
/// </summary>
private void Remove()
{
    this.Items.RemoveAt(this.items.Count - 1);

    // Xamarin.Forms では Xamarin.Forms.Command の ChangeCanExecute しか反応してくれないらしい;
    ((Command)this.addCommand).ChangeCanExecute();
    ((Command)this.removeCommand).ChangeCanExecute();
}

/// <summary>
/// アイテムの追加可能状態
/// </summary>
/// <returns>可能な場合<code>true</code>、それ以外は<code>false</code></returns>
private bool CanRemove()
{
    return this.items.Count > 0;
}

#endregion //RemoveCommand

とりあえず動かしたいというのであれば Xamarin.Forms の Command を上記のように利用すれば問題ないですが、弱参照でうまくいかないことは気になりますね

*1:他のオブジェクトから参照されながらガベージコレクションにより解放対象となりうる状態

参考:WeakReference クラス (System), C# のメモリ管理 (C# によるプログラミング入門)