更新:フィードバックに基づいて作り直されました。
UIにはCanExecute()がfalseを返す理由が必要なため、次の2つのことが頭に浮かびます。
オプション1:列挙可能なメッセージプロパティをコマンドインターフェイスに追加し、CanExecute()の呼び出し中に必要に応じて入力します。その後、UIは必要に応じてプロパティに問い合わせることができます。このルートを使用する場合は、CanExecute()を呼び出すたびにプロパティの内容をクリアして、状態を見失わないようにしてください。
public interface ICommand
{
IEnumerable<string> Messages { get; }
bool CanExecute();
void Execute();
}
public class SomeCommand : ICommand
{
public IEnumerable<string> Messages { get; private set; }
public bool CanExecute()
{
var messages = new List<string>();
var canExecute = true;
if (SomeCondition)
{
canExecute = false;
messages.Add("Some reason");
}
if (AnotherCondition)
{
canExecute = false;
messages.Add("Another reason");
}
Messages = messages;
return canExecute;
}
public void Execute() { }
}
オプション2: CanExecute()に、boolと列挙可能なmessagesプロパティを含むオブジェクトを返すようにします。これにより、メッセージがCanExecute()のその呼び出しにのみ適用されることが明らかになります。ただし、実装する場所/方法(データバインディングなど)によっては、これにより、探している以上に他のシナリオが複雑になる可能性があります。
public class CanExecuteResult
{
public bool CanExecute { get; set; }
public IEnumerable<string> Messages { get; set; }
}
public interface ICommand
{
CanExecuteResult CanExecute();
void Execute();
}
public class SomeCommand : ICommand
{
public CanExecuteResult CanExecute()
{
var result = new CanExecuteResult { CanExecute = true };
var messages = new List<string>();
if (SomeCondition)
{
result.CanExecute = false;
messages.Add("Some reason");
}
if (AnotherCondition)
{
result.CanExecute = false;
messages.Add("Another reason");
}
result.Messages = messages;
return result;
}
public void Execute() { }
}
明らかに、インターフェースや列挙可能なタイプなどをどのように処理するかについての詳細はあなた次第です。コードはアイデアの単なる表現です。