私はC#の新機能で、カスタムIEnumerable列挙型を作成するためにyield returnを使用する方法を発見しました。ウィザードを作成するためにMVVMを使用しようとしていますが、あるページから次のページへのフローを制御する方法がわかりませんでした。場合によっては、特定のステップを表示したい場合がありますが、それ以外の場合は適用されません。IEnumerable/yieldを使用したウィザードのナビゲーション
私の問題は、IEnumerableを使用して後続の各ページを返すことです。実際にはうまくいきますが、おそらく言語で不適切な/意図しないことをしていることがわかります。子クラスは、抽象のステップにIEnumerableをアクセサをオーバーライドすることがあります。
public class HPLDTWizardViewModel : WizardBase
{
protected override IEnumerable<WizardStep> Steps
{
get
{
WizardStep currentStep;
// 1.a start with assay selection
currentStep = new AssaySelectionViewModel();
yield return currentStep;
// 1.b return the selected assay.
SigaDataSet.Assay assay = ((AssaySelectionViewModel)currentStep).SelectedAssay;
sigaDataSet = (SigaDataSet)assay.Table.DataSet;
// 2.a get the number of plates
currentStep = new NumPlatesViewModel(sigaDataSet);
yield return currentStep;
...
}
}
}
親クラスがステップを使用したナビゲーション・ロジックが含まれている列挙子を属性:
public abstract class WizardBase : ViewModelBase
{
private ICommand _moveNextCommand;
private ICommand _cancelCommand;
private IEnumerator<WizardStep> _currentStepEnumerator;
#region Events
/// <summary>
/// Raised when the wizard window should be closed.
/// </summary>
public event EventHandler RequestClose;
#endregion // Events
#region Public Properties
/// <summary>
/// Gets the steps.
/// </summary>
/// <value>The steps.</value>
protected abstract IEnumerable<WizardStep> Steps { get;}
/// <summary>
/// Gets the current step.
/// </summary>
/// <value>The current step.</value>
public WizardStep CurrentStep
{
get
{
if (_currentStepEnumerator == null)
{
_currentStepEnumerator = Steps.GetEnumerator();
_currentStepEnumerator.MoveNext();
}
return _currentStepEnumerator.Current;
}
}
#endregion //Public Properties
#region Commands
public ICommand MoveNextCommand
{
get
{
if (_moveNextCommand == null)
_moveNextCommand = new RelayCommand(
() => this.MoveToNextPage(),
() => this.CanMoveToNextPage());
return _moveNextCommand;
}
}
public ICommand CancelCommand
{
get
{
if (_cancelCommand == null)
_cancelCommand = new RelayCommand(() => OnRequestClose());
return _cancelCommand;
}
}
#endregion //Commands
#region Private Helpers
/// <summary>
/// Determines whether this instance [can move to next page].
/// </summary>
/// <returns>
/// <c>true</c> if this instance [can move to next page]; otherwise, <c>false</c>.
/// </returns>
bool CanMoveToNextPage()
{
if (CurrentStep == null)
return false;
else
return CurrentStep.IsValid();
}
/// <summary>
/// Moves to next page.
/// </summary>
void MoveToNextPage()
{
_currentStepEnumerator.MoveNext();
if (_currentStepEnumerator.Current == null)
OnRequestClose();
else
OnPropertyChanged("CurrentStep");
}
/// <summary>
/// Called when [request close].
/// </summary>
void OnRequestClose()
{
EventHandler handler = this.RequestClose;
if (handler != null)
handler(this, EventArgs.Empty);
}
#endregion //Private Helpers
}
そして、ここではWizardStep抽象クラスは、それぞれがありますウィザードのページの実装:
public abstract class WizardStep : ViewModelBase
{
public abstract string DisplayName { get; }
public abstract bool IsValid();
public abstract List<string> GetValidationErrors();
}
私が言ったように、私は列挙子でリストをナビゲートするので、これはすばらしく機能します。ナビゲーションロジックは抽象親クラスにあり、すべての子が行う必要があるのはSteps属性をオーバーライドすることです。 WizardSteps自体にはロジックが含まれているため、有効期限がわかっており、ユーザーは続行できます。 MVVMを使用しているので、次のボタンは、コマンドを使用してCanMoveToNextPage()およびMoveToNextPage()関数にバインドされています。
私の質問は:この場合、列挙モデルを悪用するのはいかがですか?より良い方法がありますか?私は実際に何らかの形でコントロールフローを定義する必要があります。そして、それは歩留まりリターン能力と実際によく似ていますので、フローロジックをステップアクセサーに戻して次のページを取得させることができます。
このブログ記事をご覧くださいhttp://blogs.msdn.com/b/shawnhar/archive/2010/10/01/iterator-state-machines.aspx – asawyer
'_currentStepEnumerator'とは何ですか?まあ、それは 'IEnumerator'だと思いますが、宣言方法を明確にしてください。それは静的なメンバーですか?最後に、あなたのコードには何も悪いことはありません。アプリケーションロジックを単純化すれば、私はあなたがそれを使うことができると確信しています。とにかく素敵な質問:) –
完全なWizardBaseクラスで更新されました。あなたの有益なコメントありがとう! – millejos