我是一个新手,刚刚发现了如何使用yield return创建自定义的IEnumerable枚举。我正在尝试使用MVVM创建向导,但我遇到了一个问题,即如何控制从一页到下一页的流程。在某些情况下,我可能希望出现某个特定步骤,而在其他情况下,则不适用。
无论如何,我的问题是我正在使用IEnumerable来返回每个后续页面,这非常好用,但我知道我可能在使用语言方面做了一些不正确/意外的事情。子类只需要重写抽象的Steps IEnumerable访问器:
父类包含使用步骤属性的枚举器的导航逻辑:
正如我所说的那样,这种方法非常有效,因为我使用枚举器来导航列表。导航逻辑在一个抽象的父类中,所有子类只需覆盖Steps属性即可。WizardSteps本身包含逻辑,以便它们知道何时有效,并且用户可以继续。我正在使用MVVM,因此下一步按钮通过命令绑定到CanMoveToNextPage()和MoveToNextPage()函数。
我的问题是:在这种情况下滥用枚举模型有多糟糕?是否有更好的方法?我确实需要以某种方式定义控制流程,并且它非常适合使用yield return能力,以便我可以将流程逻辑返回到Steps访问器以获取下一页。
无论如何,我的问题是我正在使用IEnumerable来返回每个后续页面,这非常好用,但我知道我可能在使用语言方面做了一些不正确/意外的事情。子类只需要重写抽象的Steps 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()函数。
我的问题是:在这种情况下滥用枚举模型有多糟糕?是否有更好的方法?我确实需要以某种方式定义控制流程,并且它非常适合使用yield return能力,以便我可以将流程逻辑返回到Steps访问器以获取下一页。
_currentStepEnumerator
是什么?我想它是一个IEnumerator
,但您能否澄清它是如何声明的?它是静态成员吗?最后,我没有看到您代码中有任何问题:如果它简化了您的应用程序逻辑,我相信您可以使用它。无论如何,这是个好问题 :) - as-cii