For a given report, the user will want to have multiple filtering options. This isn't bad when the options are enumerations, and other 'static' data types, however things can get silly fast when you need a select list that is populated by fields stored in a table in the backend.
对于给定的报告,用户将希望具有多个过滤选项。当选项是枚举和其他“静态”数据类型时,这也不错,但是当您需要一个由存储在后端表中的字段填充的选择列表时,事情会变得非常快。
How do you handle this scenario? I find myself constantly reshaping the View data to accommodate the additional filter fields, but it really is starting to be a bit much tracking not only the selected options, but also the options themselves...
你如何处理这种情况?我发现自己不断地重塑View数据以适应额外的过滤器字段,但它确实开始有点跟踪选定的选项,还有选项本身......
is there not a better way?
有没有更好的方法?
3 个解决方案
#1
I’m currently building out a new reporting section for one of our products at work and am dealing with this same issue. The solution I’ve come up with so far, though it hasn’t been implemented yet so this is still a work in progress, is along the lines of this.
我目前正在为我们的一个产品在工作中构建一个新的报告部分,并且正在处理同样的问题。我到目前为止提出的解决方案,虽然尚未实施,所以这仍然是一项正在进行的工作,与此类似。
There will be a class that will represent a report filter which will contain some basic info such as the label text and a list of option values.
将有一个类代表一个报告过滤器,它将包含一些基本信息,例如标签文本和选项值列表。
public enum DisplayStyle
{
DropDown,
ListBox,
RadioList,
CheckList,
TextBox
}
public class FilterOption
{
public string Name { get; set; }
public string Value { get; set; }
public bool Selected { get; set; }
}
public class ReportFilter
{
public string Title { get; set; }
public DisplayStyle Style { get; set; }
public List<FilterOption> Options { get; set; }
}
And then my model will contain a list of these option classes that will be generated based on each report’s needs. I also have a base report class that each report will inherit from so that way I can handle building out the option lists on a per report basis and use one view to handle them all.
然后我的模型将包含这些选项类的列表,这些类将根据每个报表的需要生成。我还有一个基本报告类,每个报告都将继承,这样我就可以处理基于每个报告构建选项列表并使用一个视图来处理它们。
public class ReportModel
{
public string Name { get; set; }
public List<ReportFilter> Filters { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
Then inside my view(s) I’ll have some helper methods that will take in those option classes and build out the actual controls for me.
然后在我的视图中,我将有一些辅助方法,它们将接受这些选项类并为我构建实际的控件。
public static string ReportFilter(this HtmlHelper htmlHelper, DisplayStyle displayStyle, FilterOption filterOption)
{
switch (displayStyle)
{
case DisplayStyle.TextBox:
return string.Format("<input type=\"text\"{0}>", filterOption.Selected ? (" value=\"" + filterOption.Value + "\"") : string.Empty);
break;
...
}
}
My route would look like this
我的路线看起来像这样
Reports/{reportID}/start/{startDate}/end/{endDate}/{*pathInfo}
All reports have a start and end date and then optional filters. The catchall parameter will have lists of filter values in the form of “Customer/1,4,7/Program/45,783”. So it’ll be like a key/value pair in list form. Then when the controller loads it’ll parse out those values into something more meaningful.
所有报告都有一个开始和结束日期,然后是可选的过滤器。 catchall参数将具有“Customer / 1,4,7 / Program / 45,783”形式的过滤器值列表。所以它就像列表形式的键/值对。然后,当控制器加载它时,它会将这些值解析为更有意义的值。
public static Dictionary<string, string> RouteParams(string pathInfo)
{
if (string.IsNullOrEmpty(pathInfo))
{
return new Dictionary<string, string>();
}
var values = new Dictionary<string, string>();
// split out params and add to the dictionary object
return values;
}
Then it will pass them off to the report class and validate them to make sure they’re correct for that report. Then when the options are loaded for that report anything that’s been set in the URL will be set to Selected in the ReportOption class so their state can be maintained. Then the filter list and other report data will be added to the model.
然后它会将它们传递给报告类并验证它们以确保它们对于该报告是正确的。然后,当为该报告加载选项时,在URL中设置的任何内容都将在ReportOption类中设置为Selected,以便可以维护它们的状态。然后,过滤器列表和其他报告数据将添加到模型中。
For my setup some filters will change when another filters selection changes so there will be some AJAX in here to post the data and get the updated filter options. The drilldown will work sort of like the search options at amazon or newegg when you narrow your search criteria.
对于我的设置,当另一个过滤器选择发生变化时,一些过滤器会发生变化,因此这里会有一些AJAX发布数据并获得更新的过滤器选项。当您缩小搜索条件时,向下钻取将类似于亚马逊或新网的搜索选项。
I hope that all makes sense to someone beside me. And if anyone has some input on improving it I’d be happy to hear it.
我希望对我身边的人都有意义。如果有人对改进它有一些意见,我会很高兴听到它。
#2
You could go and retrieve the data asynchronously on the screen using jQuery and JsonResults from your MVC application, this is how we populate all of our lists and searches in our applications. I have an example of how it is done here.
您可以使用来自MVC应用程序的jQuery和JsonResults在屏幕上异步检索数据,这就是我们在应用程序中填充所有列表和搜索的方式。我有一个如何在这里完成的例子。
This way the view data is loaded on demand, if they don't use the extra filters then they don't have to get the view data and if one selection relates to another then it's clear which set of data you need to retrieve.
这样,视图数据按需加载,如果它们不使用额外的过滤器,那么它们不必获取视图数据,如果一个选择与另一个选择相关,则清楚需要检索哪组数据。
Another option, though I don't like this one as much but jQuery solution may not suit you, is to have your model object for your view contain all the view data so that all you need to do is set the single model object and all the lists are loaded directly and strongly typed. This will simplify the view and the back end code because it will be more clear that for this view the only thing you need is a complete version of this model object.
另一种选择,虽然我不喜欢这个,但jQuery解决方案可能不适合你,是让你的视图的模型对象包含所有视图数据,这样你需要做的就是设置单个模型对象和所有列表直接加载并强类型化。这将简化视图和后端代码,因为更清楚的是,对于此视图,您唯一需要的是此模型对象的完整版本。
For example if you had two lists for combo boxes then your model might look like:
例如,如果您有两个组合框列表,那么您的模型可能如下所示:
public class MyViewMode
{
public int MyProperty { get; set; }
public string SomeString { get; set; }
List<string> ComboListA { get; set; }
List<string> ComboListB { get; set; }
}
Hope that makes sense, if not please comment and I'll expand on it.
希望有意义,如果没有请评论,我会扩展它。
#3
Ad-hoc filtering on reports is indeed a tricky issue especially when you want to show a custom user interface control based on the data type, do validation, make some filters to be dependent on one another and others not, etc.
对报告进行特别过滤确实是一个棘手的问题,尤其是当您想要根据数据类型显示自定义用户界面控件,进行验证,使某些过滤器彼此依赖而其他过滤器不依赖,等等。
One thing I think that is worth considering is the old "build vs buy" issue here. There are specialized tools out there for ad-hoc reporting that do provide a UI for ad-hoc filters help with this such as the usual suspects Crystal Reports, Microsoft's Reporting Services, or our product ActiveReports Server. In ActiveReports Server we support cascading prompts (where available values in prompts depend on one another) and make it easy for anyone, even non-technical business users to modify the prompts (assuming they have permissions obviously). More information about using prompts in ActiveReports Server is here. ActiveReports Server is also, all managed .NET code, and provides ASP.NET controls and web services that allows you to integrate it into your web apps.
我认为值得考虑的一件事就是旧的“构建与购买”问题。有专门的工具用于临时报告,它们为临时过滤器提供了一个UI帮助,例如通常的疑问Crystal Reports,Microsoft的Reporting Services或我们的产品ActiveReports Server。在ActiveReports Server中,我们支持级联提示(提示中的可用值彼此依赖),并使任何人,甚至非技术业务用户都可以轻松修改提示(假设他们显然具有权限)。有关在ActiveReports Server中使用提示的详细信息,请单击此处。 ActiveReports Server也是所有托管的.NET代码,并提供ASP.NET控件和Web服务,允许您将其集成到Web应用程序中。
Scott Willeke
Product Manager - ActiveReports Server
GrapeCity inc.
#1
I’m currently building out a new reporting section for one of our products at work and am dealing with this same issue. The solution I’ve come up with so far, though it hasn’t been implemented yet so this is still a work in progress, is along the lines of this.
我目前正在为我们的一个产品在工作中构建一个新的报告部分,并且正在处理同样的问题。我到目前为止提出的解决方案,虽然尚未实施,所以这仍然是一项正在进行的工作,与此类似。
There will be a class that will represent a report filter which will contain some basic info such as the label text and a list of option values.
将有一个类代表一个报告过滤器,它将包含一些基本信息,例如标签文本和选项值列表。
public enum DisplayStyle
{
DropDown,
ListBox,
RadioList,
CheckList,
TextBox
}
public class FilterOption
{
public string Name { get; set; }
public string Value { get; set; }
public bool Selected { get; set; }
}
public class ReportFilter
{
public string Title { get; set; }
public DisplayStyle Style { get; set; }
public List<FilterOption> Options { get; set; }
}
And then my model will contain a list of these option classes that will be generated based on each report’s needs. I also have a base report class that each report will inherit from so that way I can handle building out the option lists on a per report basis and use one view to handle them all.
然后我的模型将包含这些选项类的列表,这些类将根据每个报表的需要生成。我还有一个基本报告类,每个报告都将继承,这样我就可以处理基于每个报告构建选项列表并使用一个视图来处理它们。
public class ReportModel
{
public string Name { get; set; }
public List<ReportFilter> Filters { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
Then inside my view(s) I’ll have some helper methods that will take in those option classes and build out the actual controls for me.
然后在我的视图中,我将有一些辅助方法,它们将接受这些选项类并为我构建实际的控件。
public static string ReportFilter(this HtmlHelper htmlHelper, DisplayStyle displayStyle, FilterOption filterOption)
{
switch (displayStyle)
{
case DisplayStyle.TextBox:
return string.Format("<input type=\"text\"{0}>", filterOption.Selected ? (" value=\"" + filterOption.Value + "\"") : string.Empty);
break;
...
}
}
My route would look like this
我的路线看起来像这样
Reports/{reportID}/start/{startDate}/end/{endDate}/{*pathInfo}
All reports have a start and end date and then optional filters. The catchall parameter will have lists of filter values in the form of “Customer/1,4,7/Program/45,783”. So it’ll be like a key/value pair in list form. Then when the controller loads it’ll parse out those values into something more meaningful.
所有报告都有一个开始和结束日期,然后是可选的过滤器。 catchall参数将具有“Customer / 1,4,7 / Program / 45,783”形式的过滤器值列表。所以它就像列表形式的键/值对。然后,当控制器加载它时,它会将这些值解析为更有意义的值。
public static Dictionary<string, string> RouteParams(string pathInfo)
{
if (string.IsNullOrEmpty(pathInfo))
{
return new Dictionary<string, string>();
}
var values = new Dictionary<string, string>();
// split out params and add to the dictionary object
return values;
}
Then it will pass them off to the report class and validate them to make sure they’re correct for that report. Then when the options are loaded for that report anything that’s been set in the URL will be set to Selected in the ReportOption class so their state can be maintained. Then the filter list and other report data will be added to the model.
然后它会将它们传递给报告类并验证它们以确保它们对于该报告是正确的。然后,当为该报告加载选项时,在URL中设置的任何内容都将在ReportOption类中设置为Selected,以便可以维护它们的状态。然后,过滤器列表和其他报告数据将添加到模型中。
For my setup some filters will change when another filters selection changes so there will be some AJAX in here to post the data and get the updated filter options. The drilldown will work sort of like the search options at amazon or newegg when you narrow your search criteria.
对于我的设置,当另一个过滤器选择发生变化时,一些过滤器会发生变化,因此这里会有一些AJAX发布数据并获得更新的过滤器选项。当您缩小搜索条件时,向下钻取将类似于亚马逊或新网的搜索选项。
I hope that all makes sense to someone beside me. And if anyone has some input on improving it I’d be happy to hear it.
我希望对我身边的人都有意义。如果有人对改进它有一些意见,我会很高兴听到它。
#2
You could go and retrieve the data asynchronously on the screen using jQuery and JsonResults from your MVC application, this is how we populate all of our lists and searches in our applications. I have an example of how it is done here.
您可以使用来自MVC应用程序的jQuery和JsonResults在屏幕上异步检索数据,这就是我们在应用程序中填充所有列表和搜索的方式。我有一个如何在这里完成的例子。
This way the view data is loaded on demand, if they don't use the extra filters then they don't have to get the view data and if one selection relates to another then it's clear which set of data you need to retrieve.
这样,视图数据按需加载,如果它们不使用额外的过滤器,那么它们不必获取视图数据,如果一个选择与另一个选择相关,则清楚需要检索哪组数据。
Another option, though I don't like this one as much but jQuery solution may not suit you, is to have your model object for your view contain all the view data so that all you need to do is set the single model object and all the lists are loaded directly and strongly typed. This will simplify the view and the back end code because it will be more clear that for this view the only thing you need is a complete version of this model object.
另一种选择,虽然我不喜欢这个,但jQuery解决方案可能不适合你,是让你的视图的模型对象包含所有视图数据,这样你需要做的就是设置单个模型对象和所有列表直接加载并强类型化。这将简化视图和后端代码,因为更清楚的是,对于此视图,您唯一需要的是此模型对象的完整版本。
For example if you had two lists for combo boxes then your model might look like:
例如,如果您有两个组合框列表,那么您的模型可能如下所示:
public class MyViewMode
{
public int MyProperty { get; set; }
public string SomeString { get; set; }
List<string> ComboListA { get; set; }
List<string> ComboListB { get; set; }
}
Hope that makes sense, if not please comment and I'll expand on it.
希望有意义,如果没有请评论,我会扩展它。
#3
Ad-hoc filtering on reports is indeed a tricky issue especially when you want to show a custom user interface control based on the data type, do validation, make some filters to be dependent on one another and others not, etc.
对报告进行特别过滤确实是一个棘手的问题,尤其是当您想要根据数据类型显示自定义用户界面控件,进行验证,使某些过滤器彼此依赖而其他过滤器不依赖,等等。
One thing I think that is worth considering is the old "build vs buy" issue here. There are specialized tools out there for ad-hoc reporting that do provide a UI for ad-hoc filters help with this such as the usual suspects Crystal Reports, Microsoft's Reporting Services, or our product ActiveReports Server. In ActiveReports Server we support cascading prompts (where available values in prompts depend on one another) and make it easy for anyone, even non-technical business users to modify the prompts (assuming they have permissions obviously). More information about using prompts in ActiveReports Server is here. ActiveReports Server is also, all managed .NET code, and provides ASP.NET controls and web services that allows you to integrate it into your web apps.
我认为值得考虑的一件事就是旧的“构建与购买”问题。有专门的工具用于临时报告,它们为临时过滤器提供了一个UI帮助,例如通常的疑问Crystal Reports,Microsoft的Reporting Services或我们的产品ActiveReports Server。在ActiveReports Server中,我们支持级联提示(提示中的可用值彼此依赖),并使任何人,甚至非技术业务用户都可以轻松修改提示(假设他们显然具有权限)。有关在ActiveReports Server中使用提示的详细信息,请单击此处。 ActiveReports Server也是所有托管的.NET代码,并提供ASP.NET控件和Web服务,允许您将其集成到Web应用程序中。
Scott Willeke
Product Manager - ActiveReports Server
GrapeCity inc.