gpt4 book ai didi

c# - 在 ASP.NET 应用程序中创建具有复杂规则的向导式导航系统的有效且可维护的方法是什么?

转载 作者:太空宇宙 更新时间:2023-11-03 11:25:34 26 4
gpt4 key购买 nike

我在团队中工作,用 C# 更新一个商业网络应用程序。我们正在使用 Telerik 的 RadControls。该应用程序以类似向导的方式引导用户完成一组任务,但也允许用户跳回之前的步骤并进行修改。此外,某些步骤具有复杂的验证方法。例如,一旦您完成了第 5 步的任务,就可以执行第 7、8 和 9 步。此外,如果您在第 2 步更改任何设置,则必须重新执行该点之后的所有操作,因此必须禁用第 3 步之后的所有步骤。

  • 屏幕左侧有一个导航栏(一个 TelerikRadPanel) 按顺序列出所有步骤。取决于关于你在这个过程中所处的位置,一些步骤可用于用户,有些被禁用。
  • 页面顶部有一个下拉框(TelerikRadToolBar 上的 SplitButton)也包含所有步骤
  • 有前进和后退按钮,让你移动到下一个或流程中的前一步。

每个“步骤”都有自己的页面,因此单击“步骤 1”的链接将带您转到 step1.aspx

导航代码遍布整个母版页。有一些方法可以处理步骤启用逻辑,这些逻辑基本上是导航面板选定索引上的大量 switch 语句。我想重新编写所有这些功能并将其放入一个“NavigationManager”类中,该类引用了所有必要的控件(尽管我愿意接受有关建议)。我正在寻找一种解决方案:

  • 了解用户在流程中所处的位置,以及允许用户前往的位置,以便在每次加载页面时启用和禁用导航项。每个步骤都应该有一种验证过程,使其能够决定将用户发送到哪里。
  • 了解如何为每个控件启用和禁用导航项。我如何将其链接起来?每个导航控件的按钮索引都出乎意料地不同。
  • 了解这些步骤之间的关系,以便用户可以单击“下一步”按钮并转到下一个顺序步骤。
  • 易于维护 - 当前的系统非常复杂,修复一个错误会导致其他错误。
  • 高效 - 每次加载页面时处理时间不应该太长

我想我真正遇到困难的是如何在某处定义所有这些步骤一次,以便系统可以使用它们。我考虑过在 enum 中定义所有步骤,但我预见到有很多 switch 语句用于启用导航控件上的步骤按钮。

我用 Google 搜索了所有我能想到的相关关键字,但找不到任何有用的东西。我知道这不是一个独特的问题。我看到很多具有类似导航系统的 Web 应用程序示例,例如 TurboTax。

所以,我的问题是:

  • 如何在一个地方定义我的所有步骤,以便整个程序知道如何处理它们?
  • 我如何使用这些定义来确定用户可以访问哪些步骤,然后启用适当的导航项?

最佳答案

看来您需要了解系统中的几件事。

  • 首先,您需要一个步骤列表以及每个步骤的任务。
  • 其次,您需要了解每个步骤的每个任务的状态。这可以是简单的,例如位标志,也可以是具有更复杂状态的枚举,例如未开始、未完成和完成。每个任务都应该知道自己的状态以及确定该状态的标准。完成一个步骤中的所有任务后,该步骤将自动视为已完成。您可以选择将页面 URL 与每个步骤相关联,甚至可以将控件 ID 与每个任务相关联。
  • 最后,您需要一个全局上下文,它了解页面加载时所有任务的状态,并保留您提到的复杂规则。一种方法是定义一个任务和/或步骤列表,这些任务和/或步骤必须完成并用于基于此 List.All(x x=> true) 设置属性 CanBeVisible;这可以在数据库、XML 中完成,只要将映射加载到具有每个任务的更新状态信息的上下文中即可。然后,任何导航控件都可以利用这个全局上下文并确切知道要呈现哪些选项可见。

想法是将可见性依赖项的映射封装到中央位置的每个任务的状态,然后任何其他 UI 元素(例如导航面板)都可以使用此信息来仅呈现满足任何可见性标准的那些控件给定的步骤和任务集。

来自CKirb250的回复:抱歉,不得不在这里发表我的评论,因为评论框中的格式很糟糕。

  • 是的,我确实需要一个步骤列表。我应该把它们放在哪里?它们应该是一个简单的 enum 吗?它们是否应该以 XML 格式布置在某处,以便我可以使用键值引用它们、应向用户显示它们的名称,以及与该步骤对应的 aspx 页面?

  • 这在数据库中进行了跟踪。为了了解每个步骤的状态,查询数据库。

  • 如何定义复杂的规则?我在想象一个巨大的 switch 语句,上面写着 if (currentStep == steps.Step1) { if (page.IsFilledOut) { enableSteps(1, 2, 3, 4, 5); } .

这是一种在 XML 中进行设置的方法 - 每个元素都应定义为一个类,如果在数据库中进行跟踪(如推荐的那样),那么您将有一些表(至少是 Step、Task、VisibilityDependency。)您可以从 DB 生成 XML(或者直接从 DB 填充类)。我使用 XML 作为一个简单的例子来形象化我的想法:

<WizardSchema>
<Steps>
<Step>
<StepID>1</StepID>
<StepOrder>1</StepOrder>
<StepTitle>First Step</StepTitle>
<StepUrl>~/step1.aspx</StepUrl>
<Tasks>
<Task>
<TaskID>1</TaskID>
<TaskOrder>1</TaskOrder>
<TaskPrompt>Enter your first name:</TaskPrompt>
<TaskControlID>FirstNameTextBox</TaskControlID>
<VisibilityDependencyList></VisibilityDependencyList>
<IsCompleted>True</IsCompleted>
</Task>
<Task>
<TaskID>2</TaskID>
<TaskOrder>2</TaskOrder>
<TaskPrompt>Enter your last name:</TaskPrompt>
<TaskControlID>LastNameTextBox</TaskControlID>
<VisibilityDependencyList>
<VisibilityDependency StepID="1" TaskID="1" />
</VisibilityDependencyList>
<IsCompleted>False</IsCompleted>
</Task>
</Tasks>
</Step>
<Step>
<StepID>2</StepID>
<StepOrder>2</StepOrder>
<StepTitle>Second Step</StepTitle>
<StepUrl>~/step2.aspx</StepUrl>
<Tasks>
<Task>
<TaskID>3</TaskID>
<TaskOrder>1</TaskOrder>
<TaskPrompt>Enter your phone number type:</TaskPrompt>
<TaskControlID>PhoneNumberTypeDropDown</TaskControlID>
<VisibilityDependencyList>
<VisibilityDependency StepID="1" />
<!-- Not setting a TaskID attribute here means ALL tasks should be complete in Step 1 for this dependency to return true -->
</VisibilityDependencyList>
<IsCompleted>False</IsCompleted>
</Task>
<Task>
<TaskID>4</TaskID>
<TaskOrder>2</TaskOrder>
<TaskPrompt>Enter your phone number:</TaskPrompt>
<TaskControlID>PhoneNumberTextBox</TaskControlID>
<VisibilityDependencyList>
<VisibilityDependency StepID="1" />
<VisibilityDependency StepID="2" TaskID="1" />
</VisibilityDependencyList>
<IsCompleted>False</IsCompleted>
</Task>
</Tasks>
</Step>
</Steps>
</WizardSchema>

现在我想的是您的导航控件会轮询您的全局上下文,现在为此编写一些代码只是为了让您了解我将如何执行此操作。

下面是一些代码来表示这个模式和一个方法来返回可以在页面上显示的所有任务;没有 switch 语句!

using System;
using System.Linq;
using System.Collections.Generic;

namespace Stackoverflow.Answers.WizardSchema
{

// Classes to represent your schema
public class VisibilityDependency
{
public int StepID { get; set; }
public int? TaskID { get; set; } // nullable to denote lack of presense
}

public class Task
{
public int TaskID { get; set; }
public int TaskOrder { get; set; }
public string TaskControlID { get; set; }
public bool IsComplete { get; set; }
public List<VisibilityDependency> VisibilityDependencyList { get; set; }
}

public class Step
{
// properties in XML

public int StepID { get; set; }
public string StepTitle { get; set; }
public List<Task> Tasks { get; set; }
}

// Class to act as a global context
public class WizardSchemaProvider
{
/// <summary>
/// Global variable to keep state of all steps (which contani all tasks)
/// </summary>
public List<Step> Steps { get; set; }

/// <summary>
/// Current step, determined by URL or some other means
/// </summary>
public Step CurrentStep { get { return null; /* add some logic to determine current step from URL */ } }

/// <summary>
/// Default Constructor; can get data here to populate Steps property
/// </summary>
public WizardSchemaProvider()
{
// Init; get your data from DB
}

/// <summary>
/// Utility method - returns all tasks that match visibility dependency for the current page;
/// Designed to be called from a navigation control;
/// </summary>
/// <param name="step"></param>
/// <returns></returns>
private IEnumerable<Task> GetAllTasksToDisplay(Step step)
{

// Let's break down the visibility dependency for each one by encapsulating into a delegate;
Func<VisibilityDependency, bool> isVisibilityDependencyMet = v =>
{
// Get the step in the visibility dependency
var stepToCheck = Steps.First(s => s.StepID == v.StepID);

if (null == v.TaskID)
{
// If the task is null, we want all tasks for the step to be completed
return stepToCheck
.Tasks // Look at the List<Task> for the step in question
.All(t => t.IsComplete); // make sure all steps are complete

// if the above is all true, then the current task being checked can be displayed
}

// If the task ID is not null, we only want the specific task (not the whole step)
return stepToCheck
.Tasks
.First(t => t.TaskID == v.TaskID) // get the task to check
.IsComplete;
};

// This Func just runs throgh the list of dependencies for each task to return whether they are met or not; all must be met
var tasksThatCanBeVisible = step
.Tasks
.Where(t => t.VisibilityDependencyList
.All(v => isVisibilityDependencyMet(v)
));

return tasksThatCanBeVisible;
}

public List<string> GetControlIDListForTasksToDisplay(Step step)
{
return this.GetAllTasksToDisplay(this.CurrentStep).Select(t => t.TaskControlID).ToList();
}

}

}

让我知道这是否足以激发您自己的想法,以一种干净的方式重构您的代码。我开发了许多向导式系统并在其中工作,并且亲眼目睹了您所描述的内容;也就是说,如果从一开始就没有很好地架构,它很快就会变得一团糟。祝你好运!

关于c# - 在 ASP.NET 应用程序中创建具有复杂规则的向导式导航系统的有效且可维护的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9456536/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com