From 29b00a43fab983940e12cbc154e2ec1a9e3b648a Mon Sep 17 00:00:00 2001 From: avalsa Date: Sun, 18 Feb 2018 20:05:34 +0300 Subject: [PATCH 01/14] add basic grid styling and filtering --- .gitignore | 2 +- GraphLabs.Dal.Ef/GraphLabs.Dal.Ef.csproj | 4 +- .../GraphLabs.DomainModel.csproj | 4 +- .../Filters/IFilterableByName.cs | 17 ++++ GraphLabs.Site.Core/FiltersInfo.cs | 17 ++++ .../GraphLabs.Site.Core.csproj | 9 +- .../GraphLabs.Site.Logic.csproj | 4 +- .../GraphLabs.Site.Models.csproj | 5 +- .../Groups/GroupListModel.cs | 23 ++++- .../Schedule/LabScheduleListModel.cs | 2 +- .../GraphLabs.Site.ServicesConfig.csproj | 4 +- GraphLabs.Site/Controllers/GroupController.cs | 13 ++- GraphLabs.Site/Filters/IFilterableByName.cs | 10 ++ .../Filters/IFilterableByUserRole.cs | 12 +++ GraphLabs.Site/GraphLabs.Site.csproj | 7 +- GraphLabs.Site/Views/Group/Index.cshtml | 27 ++---- GraphLabs.Site/Views/Helpers/GraphLabsForm.cs | 7 ++ .../Views/Helpers/GraphLabsUIFactory.cs | 68 ++++++++++++++ .../Views/Helpers/GraphLabsWebGrid.cs | 93 +++++++++++++++++++ .../GraphLabs.Tests.Site.csproj | 6 ++ GraphLabs.Utils/GraphLabs.Site.Utils.csproj | 4 +- .../GraphLabs.WcfServices.csproj | 4 +- 22 files changed, 295 insertions(+), 47 deletions(-) create mode 100644 GraphLabs.Site.Core/Filters/IFilterableByName.cs create mode 100644 GraphLabs.Site.Core/FiltersInfo.cs create mode 100644 GraphLabs.Site/Filters/IFilterableByName.cs create mode 100644 GraphLabs.Site/Filters/IFilterableByUserRole.cs create mode 100644 GraphLabs.Site/Views/Helpers/GraphLabsForm.cs create mode 100644 GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs create mode 100644 GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs diff --git a/.gitignore b/.gitignore index 8d00f84..cd53f00 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ /[Pp]ackages *.user - +/.idea [Oo]bj [Bb]in /AssemblyVersion.cs diff --git a/GraphLabs.Dal.Ef/GraphLabs.Dal.Ef.csproj b/GraphLabs.Dal.Ef/GraphLabs.Dal.Ef.csproj index 2f4ed58..ab62b0a 100644 --- a/GraphLabs.Dal.Ef/GraphLabs.Dal.Ef.csproj +++ b/GraphLabs.Dal.Ef/GraphLabs.Dal.Ef.csproj @@ -244,8 +244,8 @@ - cd "$(SolutionDir)" -powershell "& ""$(SolutionDir)\generateVersionInfo.ps1""" + + + + + + + + diff --git a/GraphLabs.Site/Views/Group/Index.cshtml b/GraphLabs.Site/Views/Group/Index.cshtml index 7a8c522..048f59a 100644 --- a/GraphLabs.Site/Views/Group/Index.cshtml +++ b/GraphLabs.Site/Views/Group/Index.cshtml @@ -1,4 +1,6 @@ -@model GraphLabs.Site.Models.Groups.GroupListModel +@using System.Web.UI.WebControls +@using Helpers +@model GraphLabs.Site.Models.Groups.GroupListModel @{ ViewBag.Title = "Группы пользователей"; @@ -16,24 +18,11 @@ @{ - var grid = new WebGrid(Model, canPage:true ,canSort:true, rowsPerPage:10); - grid.Pager(WebGridPagerModes.All); - @grid.GetHtml(tableStyle: "webGrid", - headerStyle: "webgrid-header", - footerStyle : "webgrid-footer", - rowStyle: "webgrid-row", - alternatingRowStyle: "webgrid-altrow", - selectedRowStyle : "webgrid-selected-row", - caption: null, - displayHeader: true, - htmlAttributes: new { id = "datatable" }, - - columns: grid.Columns( - grid.Column(header: "#", format: item => item.Id, columnName: "Id", style:"idColumn"), - grid.Column(header: "Название", format: item => item.Name, columnName: "Name", style:"nameColumn"), - grid.Column(header: "Доступность", format: item => item.IsOpen, columnName: "IsOpen", style:"openColumn") - ) - ); + var grid = new GraphLabsWebGrid(Model); + grid.Pager(); + @grid.GetHtml(columns : grid.Columns(grid.Column(header: "#", format: item => item.Id, columnName: "Id", style:"idColumn"), + grid.Column(header: "Название", format: item => item.Name, columnName: "Name", style:"nameColumn"), + grid.Column(header: "Доступность", format: item => item.IsOpen, columnName: "IsOpen", style:"openColumn"))); } @section scripts{ diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsForm.cs b/GraphLabs.Site/Views/Helpers/GraphLabsForm.cs new file mode 100644 index 0000000..310b4c5 --- /dev/null +++ b/GraphLabs.Site/Views/Helpers/GraphLabsForm.cs @@ -0,0 +1,7 @@ +namespace ASP.Helpers +{ + public class GraphLabsForm + { + + } +} \ No newline at end of file diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs b/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs new file mode 100644 index 0000000..adbced8 --- /dev/null +++ b/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs @@ -0,0 +1,68 @@ +using System.Web.UI; +using System.Web.UI.HtmlControls; + + +namespace ASP.Helpers +{ + public static class GraphLabsUIFactory + { + public static HtmlGenericControl createHtmlForm() + { + var form = new HtmlGenericControl("form"); + form.Attributes.Add("class", "graphlabs-form"); + return form; + } + + public static HtmlInputText createHtmlInputText() + { + var text = new HtmlInputText("text"); + text.Attributes.Add("class", "graphlabs-input-text"); + return text; + } + + public static HtmlInputCheckBox createHtmlInputCheckBox() + { + var checkBox = new HtmlInputCheckBox(); + checkBox.Attributes.Add("class", "graphlabs-checkbox"); + return checkBox; + } + + public static HtmlGenericControl createHtmlLabel() + { + var label = new HtmlGenericControl("label"); + label.Attributes.Add("class", "graphlabs-label"); + return label; + } + + public static HtmlInputButton createHtmlSubmitButton() + { + var button = new HtmlInputButton("submit"); + button.Attributes.Add("class", "graphlabs-submit"); + button.Value = "Применить"; + return button; + } + + public static HtmlInputButton createHtmlResetButton() + { + var button = new HtmlInputButton("reset"); + button.Attributes.Add("class", "graphlabs-reset"); + button.Value = "Очистить"; + return button; + } + + public static Control createInputField(string name, string labelText) + { + var input = GraphLabsUIFactory.createHtmlInputText(); + input.Name = name; + input.ID = name; + + var label = GraphLabsUIFactory.createHtmlLabel(); + label.InnerText = labelText; + + var div = new HtmlGenericControl("div"); + div.Controls.Add(label); + label.Controls.Add(input); + return div; + } + } +} \ No newline at end of file diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs new file mode 100644 index 0000000..1f43db4 --- /dev/null +++ b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Web; +using System.Web.Helpers; +using System.Web.Mvc; +using System.Web.Mvc.Html; +using System.Web.UI; +using System.Web.UI.HtmlControls; +using System.Web.UI.WebControls; +using GraphLabs.Site.Core; +using GraphLabs.Site.Core.Filters; +using Microsoft.Practices.Unity; + +namespace ASP.Helpers +{ + public class GraphLabsWebGrid : WebGrid + { + private IEnumerable _source; + + public GraphLabsWebGrid(IEnumerable source) + : base(source, canPage: true, canSort: true, rowsPerPage: 10) + { + _source = source; + } + + public IHtmlString GetHtml(string tableStyle = "webGrid", string headerStyle = "webgrid-header", + string footerStyle = "webgrid-footer", + string rowStyle = "webgrid-row", string alternatingRowStyle = "webgrid-altrow", + string selectedRowStyle = "webgrid-selected-row", + string caption = null, bool displayHeader = true, bool fillEmptyRows = false, + string emptyRowCellValue = null, IEnumerable columns = null, + IEnumerable exclusions = null, + WebGridPagerModes mode = WebGridPagerModes.Numeric | WebGridPagerModes.NextPrevious, + string firstText = null, string previousText = null, string nextText = null, string lastText = null, + int numericLinksCount = 5, object htmlAttributes = null) + { + var buildHtml = new StringBuilder(); + addHtmlFilters(buildHtml); + buildHtml.AppendLine(base.GetHtml(tableStyle, headerStyle, footerStyle, rowStyle, alternatingRowStyle, + selectedRowStyle, caption, displayHeader, fillEmptyRows, emptyRowCellValue, columns, exclusions, mode, + firstText, previousText, nextText, lastText, numericLinksCount, htmlAttributes + ).ToString()); + + return new HtmlString(buildHtml.ToString()); + } + + private void addHtmlFilters(StringBuilder stringBuilder) + { + var types = new FiltersInfo().GetFilters(); + var mainDiv = new HtmlGenericControl("div"); + var form = GraphLabsUIFactory.createHtmlForm(); + mainDiv.Controls.Add(form); + + foreach (var type in types) + { + if (isA(_source, type)) + { + MethodInfo textMethod = null; + foreach (var method in type.GetMethods()) + { + if (method.Name.EndsWith("Text")) + { + textMethod = method; + } + } + var m = _source.GetType().GetMethod(textMethod.Name); + var s = m.Invoke(_source, null); + form.Controls.Add(GraphLabsUIFactory.createInputField(type.Name.Split(new[]{"By", "`"}, StringSplitOptions.None)[1], (string)s)); + } + } + + if (form.Controls.Count == 0) + { + return; + } + + form.Controls.Add(GraphLabsUIFactory.createHtmlResetButton()); + form.Controls.Add(GraphLabsUIFactory.createHtmlSubmitButton()); + mainDiv.RenderControl(new HtmlTextWriter(new StringWriter(stringBuilder))); + } + + private static bool isA(object o, Type t) + { + return (o.GetType().GetInterfaces().Any(x => + x.IsGenericType && + x.GetGenericTypeDefinition() == t)); + } + } +} \ No newline at end of file diff --git a/GraphLabs.Tests.Site/GraphLabs.Tests.Site.csproj b/GraphLabs.Tests.Site/GraphLabs.Tests.Site.csproj index 9c27385..169f9bd 100644 --- a/GraphLabs.Tests.Site/GraphLabs.Tests.Site.csproj +++ b/GraphLabs.Tests.Site/GraphLabs.Tests.Site.csproj @@ -68,6 +68,12 @@ + + + {D62CC3F4-3EA1-44FF-B9E2-492582788B3B} + GraphLabs.Site.Core + + diff --git a/GraphLabs.Utils/GraphLabs.Site.Utils.csproj b/GraphLabs.Utils/GraphLabs.Site.Utils.csproj index 888cec5..0310a51 100644 --- a/GraphLabs.Utils/GraphLabs.Site.Utils.csproj +++ b/GraphLabs.Utils/GraphLabs.Site.Utils.csproj @@ -173,8 +173,8 @@ - cd "$(SolutionDir)" -powershell "& ""$(SolutionDir)\generateVersionInfo.ps1""" + + + From c06914d454dfc0922f2cb79005b41c24fbc26b76 Mon Sep 17 00:00:00 2001 From: avalsa Date: Tue, 20 Feb 2018 00:26:54 +0300 Subject: [PATCH 02/14] web grid 2.0 --- .../Filters/IFilterAttribute.cs | 5 ++++ GraphLabs.Site.Core/Filters/IFilterable.cs | 15 ++++++++++ .../Filters/IFilterableByName.cs | 17 ----------- .../Filters/IFilterableModel.cs | 5 ++++ .../Filters/StringFilterAttribute.cs | 15 ++++++++++ GraphLabs.Site.Core/FiltersInfo.cs | 17 ----------- .../GraphLabs.Site.Core.csproj | 9 ++++-- .../Groups/GroupListModel.cs | 17 ++++------- GraphLabs.Site.Models/Groups/GroupModel.cs | 4 ++- GraphLabs.Site/Controllers/GroupController.cs | 10 +++++-- .../Views/Helpers/GraphLabsWebGrid.cs | 29 ++++++++++--------- 11 files changed, 79 insertions(+), 64 deletions(-) create mode 100644 GraphLabs.Site.Core/Filters/IFilterAttribute.cs create mode 100644 GraphLabs.Site.Core/Filters/IFilterable.cs delete mode 100644 GraphLabs.Site.Core/Filters/IFilterableByName.cs create mode 100644 GraphLabs.Site.Core/Filters/IFilterableModel.cs create mode 100644 GraphLabs.Site.Core/Filters/StringFilterAttribute.cs delete mode 100644 GraphLabs.Site.Core/FiltersInfo.cs diff --git a/GraphLabs.Site.Core/Filters/IFilterAttribute.cs b/GraphLabs.Site.Core/Filters/IFilterAttribute.cs new file mode 100644 index 0000000..36657ef --- /dev/null +++ b/GraphLabs.Site.Core/Filters/IFilterAttribute.cs @@ -0,0 +1,5 @@ +namespace GraphLabs.Site.Core.Filters +{ + public interface IFilterAttribute + {} +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/IFilterable.cs b/GraphLabs.Site.Core/Filters/IFilterable.cs new file mode 100644 index 0000000..9f0dc89 --- /dev/null +++ b/GraphLabs.Site.Core/Filters/IFilterable.cs @@ -0,0 +1,15 @@ +using System; +using System.Linq.Expressions; +using GraphLabs.DomainModel.Infrastructure; +using GraphLabs.Site.Models.Infrastructure; + +namespace GraphLabs.Site.Core.Filters +{ + public interface IFilterable + where TEntity : AbstractEntity + where TModel : IFilterableModel + { + IListModel filter(Expression> filter); + } + +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/IFilterableByName.cs b/GraphLabs.Site.Core/Filters/IFilterableByName.cs deleted file mode 100644 index 64695ce..0000000 --- a/GraphLabs.Site.Core/Filters/IFilterableByName.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using GraphLabs.Site.Models.Infrastructure; - - - -namespace GraphLabs.Site.Core.Filters -{ - - //convention : название должно быть в духе ***By*** - привет Post - public interface IFilterableByName - where TListModel : IListModel - { - TListModel FilterByName(String name); - //convention : ***Text - отображение на форме - воообще любое назвнаие метода, но кончающееся на Text - string FilterableByNameText(); - } -} \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/IFilterableModel.cs b/GraphLabs.Site.Core/Filters/IFilterableModel.cs new file mode 100644 index 0000000..fc3903a --- /dev/null +++ b/GraphLabs.Site.Core/Filters/IFilterableModel.cs @@ -0,0 +1,5 @@ +namespace GraphLabs.Site.Core.Filters +{ + public interface IFilterableModel + {} +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/StringFilterAttribute.cs b/GraphLabs.Site.Core/Filters/StringFilterAttribute.cs new file mode 100644 index 0000000..572e3d6 --- /dev/null +++ b/GraphLabs.Site.Core/Filters/StringFilterAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace GraphLabs.Site.Core.Filters +{ + [System.AttributeUsage(System.AttributeTargets.Property)] + public class StringFilterAttribute : Attribute, IFilterAttribute + { + private string _name; + + public StringFilterAttribute(string name) + { + _name = name; + } + } +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/FiltersInfo.cs b/GraphLabs.Site.Core/FiltersInfo.cs deleted file mode 100644 index fc79895..0000000 --- a/GraphLabs.Site.Core/FiltersInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; - -namespace GraphLabs.Site.Core -{ - public class FiltersInfo - { - public Type[] GetFilters() - { - var q = from t in Assembly.GetExecutingAssembly().GetTypes() - where t.IsInterface && t.Namespace == "GraphLabs.Site.Core.Filters" - select t; - return q.ToArray(); - } - } -} \ No newline at end of file diff --git a/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj b/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj index 03ea091..5ff7203 100644 --- a/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj +++ b/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj @@ -119,6 +119,9 @@ 0 + + ..\GraphLabs.WcfServices\Bin\GraphLabs.DomainModel.dll + ..\GraphLabs.WcfServices\Bin\GraphLabs.Site.Models.dll @@ -138,8 +141,10 @@ Properties\AssemblyVersion.cs - - + + + + diff --git a/GraphLabs.Site.Models/Groups/GroupListModel.cs b/GraphLabs.Site.Models/Groups/GroupListModel.cs index 231ec06..cd61bcb 100644 --- a/GraphLabs.Site.Models/Groups/GroupListModel.cs +++ b/GraphLabs.Site.Models/Groups/GroupListModel.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Linq.Expressions; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using GraphLabs.DomainModel; @@ -10,12 +11,11 @@ namespace GraphLabs.Site.Models.Groups { /// Модель списка групп - public sealed class GroupListModel : ListModelBase, - IFilterableByName + public sealed class GroupListModel : ListModelBase, IFilterable { private readonly IEntityQuery _query; private readonly IEntityBasedModelLoader _modelLoader; - private string _name = ""; + private Expression> _filter = (group => true); /// Модель списка групп public GroupListModel(IEntityQuery query, IEntityBasedModelLoader modelLoader) @@ -28,21 +28,16 @@ public GroupListModel(IEntityQuery query, IEntityBasedModelLoader() - .Where(m => _name == "" || _name.Equals(m.Name)) + .Where(_filter) .ToArray() .Select(_modelLoader.Load) .ToArray(); } - public GroupListModel FilterByName(String name) + public IListModel filter(Expression> filter) { - _name = name ?? ""; + _filter = filter; return this; } - - public string FilterableByNameText() - { - return "Номер группы"; - } } } \ No newline at end of file diff --git a/GraphLabs.Site.Models/Groups/GroupModel.cs b/GraphLabs.Site.Models/Groups/GroupModel.cs index eafbc5a..91d8ac1 100644 --- a/GraphLabs.Site.Models/Groups/GroupModel.cs +++ b/GraphLabs.Site.Models/Groups/GroupModel.cs @@ -1,13 +1,15 @@ using System.Collections.Generic; using GraphLabs.DomainModel; +using GraphLabs.Site.Core.Filters; using GraphLabs.Site.Models.Infrastructure; namespace GraphLabs.Site.Models.Groups { - public class GroupModel : IEntityBasedModel + public class GroupModel : IEntityBasedModel, IFilterableModel { public long Id { get; set; } + [StringFilter("Номер группы")] public string Name { get; set; } public bool IsOpen { get; set; } diff --git a/GraphLabs.Site/Controllers/GroupController.cs b/GraphLabs.Site/Controllers/GroupController.cs index 12f9094..7028aca 100644 --- a/GraphLabs.Site/Controllers/GroupController.cs +++ b/GraphLabs.Site/Controllers/GroupController.cs @@ -30,10 +30,14 @@ public GroupController( public ActionResult Index(string message, string Name) { ViewBag.Message = message; + if (Name == "") + { + Name = null; + } + var model = _listModelLoader.LoadListModel() + .filter(g => Name == null || Name.Equals(g.Name)); - var model = _listModelLoader.LoadListModel().FilterByName(Name); - - return View(model); + return View((GroupListModel) model); } public ActionResult Create() diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs index 1f43db4..7c4afa6 100644 --- a/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs +++ b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs @@ -50,26 +50,24 @@ public IHtmlString GetHtml(string tableStyle = "webGrid", string headerStyle = " private void addHtmlFilters(StringBuilder stringBuilder) { - var types = new FiltersInfo().GetFilters(); var mainDiv = new HtmlGenericControl("div"); var form = GraphLabsUIFactory.createHtmlForm(); mainDiv.Controls.Add(form); - foreach (var type in types) + if (isA(_source, typeof(IFilterable<,>))) { - if (isA(_source, type)) + var e = getType(_source, typeof(IFilterable<,>)); + + var genericArgument = e.GetGenericArguments()[1]; + foreach (var propertyInfo in genericArgument.GetProperties()) { - MethodInfo textMethod = null; - foreach (var method in type.GetMethods()) + foreach (var customAttributeData in propertyInfo.CustomAttributes) { - if (method.Name.EndsWith("Text")) - { - textMethod = method; + if (customAttributeData.AttributeType.GetInterfaces().Contains(typeof(IFilterAttribute))) + { + form.Controls.Add(GraphLabsUIFactory.createInputField(propertyInfo.Name, (string) customAttributeData.ConstructorArguments[0].Value)); } } - var m = _source.GetType().GetMethod(textMethod.Name); - var s = m.Invoke(_source, null); - form.Controls.Add(GraphLabsUIFactory.createInputField(type.Name.Split(new[]{"By", "`"}, StringSplitOptions.None)[1], (string)s)); } } @@ -83,11 +81,16 @@ private void addHtmlFilters(StringBuilder stringBuilder) mainDiv.RenderControl(new HtmlTextWriter(new StringWriter(stringBuilder))); } - private static bool isA(object o, Type t) + private static Type getType(object o, Type t) { - return (o.GetType().GetInterfaces().Any(x => + return (o.GetType().GetInterfaces().FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == t)); } + + private static bool isA(object o, Type t) + { + return getType(o, t) != null; + } } } \ No newline at end of file From f02630452461d020fb69d67930dddbdbb2bc190c Mon Sep 17 00:00:00 2001 From: avalsa Date: Tue, 20 Feb 2018 11:58:21 +0300 Subject: [PATCH 03/14] add bool filtering --- GraphLabs.Site.Models/Groups/GroupModel.cs | 3 +- GraphLabs.Site/Controllers/GroupController.cs | 5 ++-- .../Views/Helpers/GraphLabsUIFactory.cs | 28 +++++++++++++++++++ .../Views/Helpers/GraphLabsWebGrid.cs | 11 ++++++-- 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/GraphLabs.Site.Models/Groups/GroupModel.cs b/GraphLabs.Site.Models/Groups/GroupModel.cs index 91d8ac1..ab94dd8 100644 --- a/GraphLabs.Site.Models/Groups/GroupModel.cs +++ b/GraphLabs.Site.Models/Groups/GroupModel.cs @@ -11,7 +11,8 @@ public class GroupModel : IEntityBasedModel, IFilterableModel [StringFilter("Номер группы")] public string Name { get; set; } - + + [StringFilter("Возможность вступить в группу")] public bool IsOpen { get; set; } public ICollection Students { get; set; } diff --git a/GraphLabs.Site/Controllers/GroupController.cs b/GraphLabs.Site/Controllers/GroupController.cs index 7028aca..1a46e23 100644 --- a/GraphLabs.Site/Controllers/GroupController.cs +++ b/GraphLabs.Site/Controllers/GroupController.cs @@ -27,7 +27,7 @@ public GroupController( _modelLoader = modelLoader; } - public ActionResult Index(string message, string Name) + public ActionResult Index(string message, string Name, bool? isOpen) { ViewBag.Message = message; if (Name == "") @@ -35,7 +35,8 @@ public ActionResult Index(string message, string Name) Name = null; } var model = _listModelLoader.LoadListModel() - .filter(g => Name == null || Name.Equals(g.Name)); + .filter(g => (Name == null || Name.Equals(g.Name)) + && (isOpen == null || g.IsOpen == isOpen)); return View((GroupListModel) model); } diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs b/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs index adbced8..72d6aed 100644 --- a/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs +++ b/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs @@ -24,6 +24,7 @@ public static HtmlInputCheckBox createHtmlInputCheckBox() { var checkBox = new HtmlInputCheckBox(); checkBox.Attributes.Add("class", "graphlabs-checkbox"); + checkBox.Value = ""; return checkBox; } @@ -64,5 +65,32 @@ public static Control createInputField(string name, string labelText) label.Controls.Add(input); return div; } + + public static Control createInputCheckBox(string name, string labelText) + { + var input = GraphLabsUIFactory.createHtmlInputCheckBox(); + input.Name = name; + input.ID = name; + input.Value = "true"; + input.Attributes.Add("onchange", "checkboxChange(this)"); + var hiddenInput = new HtmlGenericControl("input"); + hiddenInput.Attributes.Add("type", "hidden"); + hiddenInput.Attributes.Add("value", ""); + hiddenInput.Attributes.Add("name", name); + hiddenInput.Attributes.Add("id", "h" + name); + + HtmlGenericControl script = new HtmlGenericControl("script"); + script.InnerHtml = "function checkboxChange(chkBox) { document.getElementById(\"h" + name + "\").value = \"false\";} ";//"if (chkBox.checked) { chkBox.value = \"true\";} else { chkBox.value = \"false\"; }}"; + var label = GraphLabsUIFactory.createHtmlLabel(); + label.InnerText = labelText; + + var div = new HtmlGenericControl("div"); + div.Controls.Add(label); + + label.Controls.Add(input); + label.Controls.Add(hiddenInput); + label.Controls.Add(script); + return div; + } } } \ No newline at end of file diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs index 7c4afa6..663bfcb 100644 --- a/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs +++ b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs @@ -64,8 +64,15 @@ private void addHtmlFilters(StringBuilder stringBuilder) foreach (var customAttributeData in propertyInfo.CustomAttributes) { if (customAttributeData.AttributeType.GetInterfaces().Contains(typeof(IFilterAttribute))) - { - form.Controls.Add(GraphLabsUIFactory.createInputField(propertyInfo.Name, (string) customAttributeData.ConstructorArguments[0].Value)); + { + if (propertyInfo.PropertyType == typeof(bool)) + { + form.Controls.Add(GraphLabsUIFactory.createInputCheckBox(propertyInfo.Name, + (string) customAttributeData.ConstructorArguments[0].Value)); + } else { + form.Controls.Add(GraphLabsUIFactory.createInputField(propertyInfo.Name, + (string) customAttributeData.ConstructorArguments[0].Value)); + } } } } From 862e226eb985356574dce0b433c6468d6ea95960 Mon Sep 17 00:00:00 2001 From: avalsa Date: Wed, 21 Feb 2018 19:06:18 +0300 Subject: [PATCH 04/14] small refactor --- .../Views/Helpers/GraphLabsUIFactory.cs | 51 +++++++++---------- .../Views/Helpers/GraphLabsWebGrid.cs | 30 +++++------ 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs b/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs index 72d6aed..9e1d200 100644 --- a/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs +++ b/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs @@ -6,44 +6,44 @@ namespace ASP.Helpers { public static class GraphLabsUIFactory { - public static HtmlGenericControl createHtmlForm() + public static HtmlGenericControl CreateHtmlForm() { var form = new HtmlGenericControl("form"); form.Attributes.Add("class", "graphlabs-form"); return form; } - public static HtmlInputText createHtmlInputText() + public static HtmlInputText CreateHtmlInputText() { var text = new HtmlInputText("text"); text.Attributes.Add("class", "graphlabs-input-text"); return text; } - - public static HtmlInputCheckBox createHtmlInputCheckBox() + + public static HtmlInputCheckBox CreateHtmlInputCheckBox() { var checkBox = new HtmlInputCheckBox(); checkBox.Attributes.Add("class", "graphlabs-checkbox"); checkBox.Value = ""; return checkBox; } - - public static HtmlGenericControl createHtmlLabel() + + public static HtmlGenericControl CreateHtmlLabel() { var label = new HtmlGenericControl("label"); label.Attributes.Add("class", "graphlabs-label"); return label; } - - public static HtmlInputButton createHtmlSubmitButton() + + public static HtmlInputButton CreateHtmlSubmitButton() { var button = new HtmlInputButton("submit"); button.Attributes.Add("class", "graphlabs-submit"); button.Value = "Применить"; return button; } - - public static HtmlInputButton createHtmlResetButton() + + public static HtmlInputButton CreateHtmlResetButton() { var button = new HtmlInputButton("reset"); button.Attributes.Add("class", "graphlabs-reset"); @@ -51,13 +51,13 @@ public static HtmlInputButton createHtmlResetButton() return button; } - public static Control createInputField(string name, string labelText) + public static Control CreateInputField(string name, string labelText) { - var input = GraphLabsUIFactory.createHtmlInputText(); + var input = GraphLabsUIFactory.CreateHtmlInputText(); input.Name = name; input.ID = name; - - var label = GraphLabsUIFactory.createHtmlLabel(); + + var label = GraphLabsUIFactory.CreateHtmlLabel(); label.InnerText = labelText; var div = new HtmlGenericControl("div"); @@ -65,30 +65,25 @@ public static Control createInputField(string name, string labelText) label.Controls.Add(input); return div; } - - public static Control createInputCheckBox(string name, string labelText) + + public static Control CreateInputCheckBox(string name, string labelText) { - var input = GraphLabsUIFactory.createHtmlInputCheckBox(); + var input = GraphLabsUIFactory.CreateHtmlInputCheckBox(); input.Name = name; input.ID = name; input.Value = "true"; input.Attributes.Add("onchange", "checkboxChange(this)"); - var hiddenInput = new HtmlGenericControl("input"); - hiddenInput.Attributes.Add("type", "hidden"); - hiddenInput.Attributes.Add("value", ""); - hiddenInput.Attributes.Add("name", name); - hiddenInput.Attributes.Add("id", "h" + name); - + HtmlGenericControl script = new HtmlGenericControl("script"); - script.InnerHtml = "function checkboxChange(chkBox) { document.getElementById(\"h" + name + "\").value = \"false\";} ";//"if (chkBox.checked) { chkBox.value = \"true\";} else { chkBox.value = \"false\"; }}"; - var label = GraphLabsUIFactory.createHtmlLabel(); + script.InnerHtml = "function checkboxChange(chkBox) { if (chkBox.value==\"true\") {chkBox.value= \"false\"; chkBox.indeterminate = true;} else { chkBox.value= \"true\"; chkBox.checked=true; } }"; + + var label = GraphLabsUIFactory.CreateHtmlLabel(); label.InnerText = labelText; - + var div = new HtmlGenericControl("div"); div.Controls.Add(label); - + label.Controls.Add(input); - label.Controls.Add(hiddenInput); label.Controls.Add(script); return div; } diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs index 663bfcb..d69c2b7 100644 --- a/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs +++ b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs @@ -2,18 +2,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; using System.Text; using System.Web; using System.Web.Helpers; -using System.Web.Mvc; -using System.Web.Mvc.Html; using System.Web.UI; using System.Web.UI.HtmlControls; -using System.Web.UI.WebControls; -using GraphLabs.Site.Core; using GraphLabs.Site.Core.Filters; -using Microsoft.Practices.Unity; namespace ASP.Helpers { @@ -39,7 +33,7 @@ public IHtmlString GetHtml(string tableStyle = "webGrid", string headerStyle = " int numericLinksCount = 5, object htmlAttributes = null) { var buildHtml = new StringBuilder(); - addHtmlFilters(buildHtml); + AddHtmlFilters(buildHtml); buildHtml.AppendLine(base.GetHtml(tableStyle, headerStyle, footerStyle, rowStyle, alternatingRowStyle, selectedRowStyle, caption, displayHeader, fillEmptyRows, emptyRowCellValue, columns, exclusions, mode, firstText, previousText, nextText, lastText, numericLinksCount, htmlAttributes @@ -48,15 +42,15 @@ public IHtmlString GetHtml(string tableStyle = "webGrid", string headerStyle = " return new HtmlString(buildHtml.ToString()); } - private void addHtmlFilters(StringBuilder stringBuilder) + private void AddHtmlFilters(StringBuilder stringBuilder) { var mainDiv = new HtmlGenericControl("div"); - var form = GraphLabsUIFactory.createHtmlForm(); + var form = GraphLabsUIFactory.CreateHtmlForm(); mainDiv.Controls.Add(form); - if (isA(_source, typeof(IFilterable<,>))) + if (IsA(_source, typeof(IFilterable<,>))) { - var e = getType(_source, typeof(IFilterable<,>)); + var e = GetType(_source, typeof(IFilterable<,>)); var genericArgument = e.GetGenericArguments()[1]; foreach (var propertyInfo in genericArgument.GetProperties()) @@ -67,10 +61,10 @@ private void addHtmlFilters(StringBuilder stringBuilder) { if (propertyInfo.PropertyType == typeof(bool)) { - form.Controls.Add(GraphLabsUIFactory.createInputCheckBox(propertyInfo.Name, + form.Controls.Add(GraphLabsUIFactory.CreateInputCheckBox(propertyInfo.Name, (string) customAttributeData.ConstructorArguments[0].Value)); } else { - form.Controls.Add(GraphLabsUIFactory.createInputField(propertyInfo.Name, + form.Controls.Add(GraphLabsUIFactory.CreateInputField(propertyInfo.Name, (string) customAttributeData.ConstructorArguments[0].Value)); } } @@ -83,21 +77,21 @@ private void addHtmlFilters(StringBuilder stringBuilder) return; } - form.Controls.Add(GraphLabsUIFactory.createHtmlResetButton()); - form.Controls.Add(GraphLabsUIFactory.createHtmlSubmitButton()); + form.Controls.Add(GraphLabsUIFactory.CreateHtmlResetButton()); + form.Controls.Add(GraphLabsUIFactory.CreateHtmlSubmitButton()); mainDiv.RenderControl(new HtmlTextWriter(new StringWriter(stringBuilder))); } - private static Type getType(object o, Type t) + private static Type GetType(object o, Type t) { return (o.GetType().GetInterfaces().FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == t)); } - private static bool isA(object o, Type t) + private static bool IsA(object o, Type t) { - return getType(o, t) != null; + return GetType(o, t) != null; } } } \ No newline at end of file From 9bb53dde473d2c5a11cad61a78ff9848d034e5ad Mon Sep 17 00:00:00 2001 From: avalsa Date: Sat, 24 Feb 2018 13:25:19 +0300 Subject: [PATCH 05/14] refactor filtering scheme --- .../Filters/AbstractFilterableModel.cs | 13 ++++++++ GraphLabs.Site.Core/Filters/FilterParams.cs | 33 +++++++++++++++++++ GraphLabs.Site.Core/Filters/IFilterable.cs | 4 +-- .../Filters/IFilterableModel.cs | 5 --- .../GraphLabs.Site.Core.csproj | 3 +- .../Groups/GroupListModel.cs | 5 +-- GraphLabs.Site.Models/Groups/GroupModel.cs | 15 +++++++-- .../GraphLabsFilteringController.cs | 25 ++++++++++++++ GraphLabs.Site/Controllers/GroupController.cs | 21 +++--------- GraphLabs.Site/GraphLabs.Site.csproj | 1 + 10 files changed, 95 insertions(+), 30 deletions(-) create mode 100644 GraphLabs.Site.Core/Filters/AbstractFilterableModel.cs create mode 100644 GraphLabs.Site.Core/Filters/FilterParams.cs delete mode 100644 GraphLabs.Site.Core/Filters/IFilterableModel.cs create mode 100644 GraphLabs.Site/Controllers/GraphLabsFilteringController.cs diff --git a/GraphLabs.Site.Core/Filters/AbstractFilterableModel.cs b/GraphLabs.Site.Core/Filters/AbstractFilterableModel.cs new file mode 100644 index 0000000..1ba6828 --- /dev/null +++ b/GraphLabs.Site.Core/Filters/AbstractFilterableModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Linq.Expressions; + +namespace GraphLabs.Site.Core.Filters +{ + public abstract class AbstractFilterableModel + { + public static Expression> CreateFilter(FilterParams filterParams) + { + return t => true; + } + } +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/FilterParams.cs b/GraphLabs.Site.Core/Filters/FilterParams.cs new file mode 100644 index 0000000..7f12187 --- /dev/null +++ b/GraphLabs.Site.Core/Filters/FilterParams.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Specialized; + +namespace GraphLabs.Site.Core.Filters +{ + public class FilterParams + { + private readonly NameValueCollection _filterParams; + + public FilterParams(NameValueCollection filterParams) + { + _filterParams = filterParams; + } + + private string GetParam(string name) + { + string value = _filterParams.Get(name); + if (value == "") value = null; + return value; + } + + public string GetStringParam(string name) + { + return GetParam(name); + } + + public bool? GetBoolParam(string name) + { + string s = GetParam(name); + return s == null ? (bool?) null : Boolean.Parse(s); + } + } +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/IFilterable.cs b/GraphLabs.Site.Core/Filters/IFilterable.cs index 9f0dc89..334f53d 100644 --- a/GraphLabs.Site.Core/Filters/IFilterable.cs +++ b/GraphLabs.Site.Core/Filters/IFilterable.cs @@ -7,9 +7,9 @@ namespace GraphLabs.Site.Core.Filters { public interface IFilterable where TEntity : AbstractEntity - where TModel : IFilterableModel + where TModel : AbstractFilterableModel { - IListModel filter(Expression> filter); + IListModel Filter(Expression> filter); } } \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/IFilterableModel.cs b/GraphLabs.Site.Core/Filters/IFilterableModel.cs deleted file mode 100644 index fc3903a..0000000 --- a/GraphLabs.Site.Core/Filters/IFilterableModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace GraphLabs.Site.Core.Filters -{ - public interface IFilterableModel - {} -} \ No newline at end of file diff --git a/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj b/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj index 5ff7203..7d5c8d8 100644 --- a/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj +++ b/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj @@ -141,7 +141,8 @@ Properties\AssemblyVersion.cs - + + diff --git a/GraphLabs.Site.Models/Groups/GroupListModel.cs b/GraphLabs.Site.Models/Groups/GroupListModel.cs index cd61bcb..6dac26c 100644 --- a/GraphLabs.Site.Models/Groups/GroupListModel.cs +++ b/GraphLabs.Site.Models/Groups/GroupListModel.cs @@ -1,10 +1,7 @@ using System; using System.Linq; using System.Linq.Expressions; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using GraphLabs.DomainModel; -using GraphLabs.Site.Core; using GraphLabs.Site.Core.Filters; using GraphLabs.Site.Models.Infrastructure; @@ -34,7 +31,7 @@ protected override GroupModel[] LoadItems() .ToArray(); } - public IListModel filter(Expression> filter) + public IListModel Filter(Expression> filter) { _filter = filter; return this; diff --git a/GraphLabs.Site.Models/Groups/GroupModel.cs b/GraphLabs.Site.Models/Groups/GroupModel.cs index ab94dd8..c303705 100644 --- a/GraphLabs.Site.Models/Groups/GroupModel.cs +++ b/GraphLabs.Site.Models/Groups/GroupModel.cs @@ -1,11 +1,13 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; using GraphLabs.DomainModel; using GraphLabs.Site.Core.Filters; using GraphLabs.Site.Models.Infrastructure; namespace GraphLabs.Site.Models.Groups { - public class GroupModel : IEntityBasedModel, IFilterableModel + public class GroupModel : AbstractFilterableModel, IEntityBasedModel { public long Id { get; set; } @@ -20,5 +22,14 @@ public class GroupModel : IEntityBasedModel, IFilterableModel public int FirstYear { get; set; } public int Number { get; set; } + + public static Expression> CreateFilter(FilterParams filterParams) + { + string Name = filterParams.GetStringParam("Name"); + bool? isOpen = filterParams.GetBoolParam("IsOpen"); + + return g => (Name == null || Name.Equals(g.Name)) + && (isOpen == null || g.IsOpen == isOpen); + } } } \ No newline at end of file diff --git a/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs b/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs new file mode 100644 index 0000000..d208a46 --- /dev/null +++ b/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs @@ -0,0 +1,25 @@ +using System; +using System.Linq.Expressions; +using System.Web.Mvc; +using GraphLabs.DomainModel.Infrastructure; +using GraphLabs.Site.Core.Filters; +using GraphLabs.Site.Models.Infrastructure; + +namespace GraphLabs.Site.Controllers +{ + public abstract class GraphLabsFilteringController : GraphLabsController + where TEntity : AbstractEntity + where TModel : AbstractFilterableModel, IEntityBasedModel + { + protected Expression> _fiExpression; + + protected override void OnActionExecuting(ActionExecutingContext filterContext) + { + if (filterContext.ActionDescriptor.ActionName.Equals("Index"))//может быть это ограничение лишнее + { + FilterParams _filterParams = new FilterParams(Request.QueryString); + _fiExpression = (Expression>) typeof(TModel).GetMethod("CreateFilter").Invoke(null, new[] {_filterParams}); + } + } + } +} \ No newline at end of file diff --git a/GraphLabs.Site/Controllers/GroupController.cs b/GraphLabs.Site/Controllers/GroupController.cs index 1a46e23..4fd48ff 100644 --- a/GraphLabs.Site/Controllers/GroupController.cs +++ b/GraphLabs.Site/Controllers/GroupController.cs @@ -1,17 +1,13 @@ -using System; -using System.Linq; -using GraphLabs.Site.Controllers.Attributes; -using System.Web.Mvc; +using System.Web.Mvc; using GraphLabs.DomainModel; -using GraphLabs.Site.Core; +using GraphLabs.Site.Controllers.Attributes; using GraphLabs.Site.Models.Groups; using GraphLabs.Site.Models.Infrastructure; -using WebGrease.Css.Extensions; namespace GraphLabs.Site.Controllers { [GLAuthorize(UserRole.Administrator, UserRole.Teacher)] - public class GroupController : GraphLabsController + public class GroupController : GraphLabsFilteringController { private readonly IListModelLoader _listModelLoader; private readonly IEntityBasedModelSaver _modelSaver; @@ -27,17 +23,10 @@ public GroupController( _modelLoader = modelLoader; } - public ActionResult Index(string message, string Name, bool? isOpen) + public ActionResult Index(string message) { ViewBag.Message = message; - if (Name == "") - { - Name = null; - } - var model = _listModelLoader.LoadListModel() - .filter(g => (Name == null || Name.Equals(g.Name)) - && (isOpen == null || g.IsOpen == isOpen)); - + var model = _listModelLoader.LoadListModel().Filter(_fiExpression); return View((GroupListModel) model); } diff --git a/GraphLabs.Site/GraphLabs.Site.csproj b/GraphLabs.Site/GraphLabs.Site.csproj index 8a1d818..b246f18 100644 --- a/GraphLabs.Site/GraphLabs.Site.csproj +++ b/GraphLabs.Site/GraphLabs.Site.csproj @@ -232,6 +232,7 @@ + From efd14e05e92c4fea817f8a4c41ee5fc061803b99 Mon Sep 17 00:00:00 2001 From: avalsa Date: Fri, 20 Apr 2018 11:57:19 +0300 Subject: [PATCH 06/14] small refactor and simple caching scheme --- GraphLabs.Site.Models/Groups/GroupModel.cs | 6 +++--- .../GraphLabsFilteringController.cs | 20 +++++++++++++++---- GraphLabs.Site/Controllers/GroupController.cs | 4 ++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/GraphLabs.Site.Models/Groups/GroupModel.cs b/GraphLabs.Site.Models/Groups/GroupModel.cs index c303705..4161979 100644 --- a/GraphLabs.Site.Models/Groups/GroupModel.cs +++ b/GraphLabs.Site.Models/Groups/GroupModel.cs @@ -14,7 +14,7 @@ public class GroupModel : AbstractFilterableModel, IEntityBasedModel Students { get; set; } @@ -25,10 +25,10 @@ public class GroupModel : AbstractFilterableModel, IEntityBasedModel> CreateFilter(FilterParams filterParams) { - string Name = filterParams.GetStringParam("Name"); + string name = filterParams.GetStringParam("Name"); bool? isOpen = filterParams.GetBoolParam("IsOpen"); - return g => (Name == null || Name.Equals(g.Name)) + return g => (name == null || name.ToLower().Equals(g.Name.ToLower())) && (isOpen == null || g.IsOpen == isOpen); } } diff --git a/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs b/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs index d208a46..a6bb2d6 100644 --- a/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs +++ b/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Concurrent; using System.Linq.Expressions; +using System.Reflection; using System.Web.Mvc; using GraphLabs.DomainModel.Infrastructure; using GraphLabs.Site.Core.Filters; @@ -11,14 +13,24 @@ public abstract class GraphLabsFilteringController : GraphLabsC where TEntity : AbstractEntity where TModel : AbstractFilterableModel, IEntityBasedModel { - protected Expression> _fiExpression; + private static readonly ConcurrentDictionary _methodInfos = new ConcurrentDictionary(); + + protected Expression> FiExpression { get; private set; } + + public abstract ActionResult Index(string message); protected override void OnActionExecuting(ActionExecutingContext filterContext) { - if (filterContext.ActionDescriptor.ActionName.Equals("Index"))//может быть это ограничение лишнее + if (filterContext.ActionDescriptor.ActionName.Equals(nameof(Index)))//может быть это ограничение лишнее { - FilterParams _filterParams = new FilterParams(Request.QueryString); - _fiExpression = (Expression>) typeof(TModel).GetMethod("CreateFilter").Invoke(null, new[] {_filterParams}); + FilterParams filterParams = new FilterParams(Request.QueryString); + Type type = typeof(TModel); + if (!_methodInfos.ContainsKey(type)) + { + _methodInfos.TryAdd(type, type.GetMethod(nameof(AbstractFilterableModel.CreateFilter))); + } + + FiExpression = (Expression>) _methodInfos[type].Invoke(null, new[] {filterParams}); } } } diff --git a/GraphLabs.Site/Controllers/GroupController.cs b/GraphLabs.Site/Controllers/GroupController.cs index 4fd48ff..00ac0e1 100644 --- a/GraphLabs.Site/Controllers/GroupController.cs +++ b/GraphLabs.Site/Controllers/GroupController.cs @@ -23,10 +23,10 @@ public GroupController( _modelLoader = modelLoader; } - public ActionResult Index(string message) + public override ActionResult Index(string message) { ViewBag.Message = message; - var model = _listModelLoader.LoadListModel().Filter(_fiExpression); + var model = _listModelLoader.LoadListModel().Filter(FiExpression); return View((GroupListModel) model); } From ef9ae78d9314f1d21be457b935011134f92d5e19 Mon Sep 17 00:00:00 2001 From: avalsa Date: Fri, 20 Apr 2018 15:25:36 +0300 Subject: [PATCH 07/14] add bounded filtering attribute --- .../Filters/AbstractFilterableModel.cs | 2 +- .../Filters/BoundedFilterAttribute.cs | 19 +++++++ GraphLabs.Site.Core/Filters/FilterParams.cs | 42 ++++++++++++++- .../GraphLabs.Site.Core.csproj | 4 ++ GraphLabs.Site.Models/Groups/GroupModel.cs | 9 ++-- .../GraphLabsFilteringController.cs | 2 +- .../Views/Helpers/GraphLabsUIFactory.cs | 50 +++++++++++++---- .../Views/Helpers/GraphLabsWebGrid.cs | 54 +++++++++++++------ 8 files changed, 147 insertions(+), 35 deletions(-) create mode 100644 GraphLabs.Site.Core/Filters/BoundedFilterAttribute.cs diff --git a/GraphLabs.Site.Core/Filters/AbstractFilterableModel.cs b/GraphLabs.Site.Core/Filters/AbstractFilterableModel.cs index 1ba6828..20c907b 100644 --- a/GraphLabs.Site.Core/Filters/AbstractFilterableModel.cs +++ b/GraphLabs.Site.Core/Filters/AbstractFilterableModel.cs @@ -5,7 +5,7 @@ namespace GraphLabs.Site.Core.Filters { public abstract class AbstractFilterableModel { - public static Expression> CreateFilter(FilterParams filterParams) + public static Expression> CreateFilter(FilterParams filterParams) { return t => true; } diff --git a/GraphLabs.Site.Core/Filters/BoundedFilterAttribute.cs b/GraphLabs.Site.Core/Filters/BoundedFilterAttribute.cs new file mode 100644 index 0000000..0c8e2d1 --- /dev/null +++ b/GraphLabs.Site.Core/Filters/BoundedFilterAttribute.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace GraphLabs.Site.Core.Filters +{ + [System.AttributeUsage(System.AttributeTargets.Property)] + public class BoundedFilterAttribute : Attribute, IFilterAttribute + { + private String _name; + private Object[] _limiters; + + public BoundedFilterAttribute(string name, Object[] limiters) + { + _name = name; + _limiters = limiters; + } + } +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/FilterParams.cs b/GraphLabs.Site.Core/Filters/FilterParams.cs index 7f12187..59fbf38 100644 --- a/GraphLabs.Site.Core/Filters/FilterParams.cs +++ b/GraphLabs.Site.Core/Filters/FilterParams.cs @@ -1,9 +1,11 @@ using System; +using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.Reflection; namespace GraphLabs.Site.Core.Filters { - public class FilterParams + public class FilterParams { private readonly NameValueCollection _filterParams; @@ -23,7 +25,43 @@ public string GetStringParam(string name) { return GetParam(name); } - + + public object GetBoundedParam(string name) + { + var index = GetIntParam(name); + if (index == null) + { + return null; + } + + var propertyInfo = typeof(T).GetProperty(name); + if (propertyInfo == null) return null; + foreach (var customAttributeData in propertyInfo.CustomAttributes) + { + if (customAttributeData.AttributeType == typeof(BoundedFilterAttribute)) + { + return ((ReadOnlyCollection) customAttributeData + .ConstructorArguments[1].Value)[index.Value].Value; + } + } + + return null; + } + + public int? GetIntParam(string name) + { + try + { + string s = GetParam(name); + return s == null ? (int?) null : Int32.Parse(s); + } + catch (FormatException) + { + return null; + } + } + + public bool? GetBoolParam(string name) { string s = GetParam(name); diff --git a/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj b/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj index 7d5c8d8..c36d7d0 100644 --- a/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj +++ b/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj @@ -125,6 +125,9 @@ ..\GraphLabs.WcfServices\Bin\GraphLabs.Site.Models.dll + + ..\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll + @@ -141,6 +144,7 @@ Properties\AssemblyVersion.cs + diff --git a/GraphLabs.Site.Models/Groups/GroupModel.cs b/GraphLabs.Site.Models/Groups/GroupModel.cs index 4161979..1f8cacf 100644 --- a/GraphLabs.Site.Models/Groups/GroupModel.cs +++ b/GraphLabs.Site.Models/Groups/GroupModel.cs @@ -11,7 +11,8 @@ public class GroupModel : AbstractFilterableModel, IEntityBasedModel, IEntityBasedModel> CreateFilter(FilterParams filterParams) + public static Expression> CreateFilter(FilterParams filterParams) { - string name = filterParams.GetStringParam("Name"); - bool? isOpen = filterParams.GetBoolParam("IsOpen"); + string name = (string) filterParams.GetBoundedParam(nameof(Name)); + bool? isOpen = filterParams.GetBoolParam(nameof(IsOpen)); return g => (name == null || name.ToLower().Equals(g.Name.ToLower())) && (isOpen == null || g.IsOpen == isOpen); diff --git a/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs b/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs index a6bb2d6..0ffe7bd 100644 --- a/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs +++ b/GraphLabs.Site/Controllers/GraphLabsFilteringController.cs @@ -23,7 +23,7 @@ protected override void OnActionExecuting(ActionExecutingContext filterContext) { if (filterContext.ActionDescriptor.ActionName.Equals(nameof(Index)))//может быть это ограничение лишнее { - FilterParams filterParams = new FilterParams(Request.QueryString); + FilterParams filterParams = new FilterParams(Request.QueryString); Type type = typeof(TModel); if (!_methodInfos.ContainsKey(type)) { diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs b/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs index 9e1d200..8996198 100644 --- a/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs +++ b/GraphLabs.Site/Views/Helpers/GraphLabsUIFactory.cs @@ -1,4 +1,5 @@ -using System.Web.UI; +using System.Collections.Generic; +using System.Web.UI; using System.Web.UI.HtmlControls; @@ -28,10 +29,11 @@ public static HtmlInputCheckBox CreateHtmlInputCheckBox() return checkBox; } - public static HtmlGenericControl CreateHtmlLabel() + public static HtmlGenericControl CreateHtmlLabel(string labelText) { var label = new HtmlGenericControl("label"); label.Attributes.Add("class", "graphlabs-label"); + label.InnerText = labelText; return label; } @@ -53,14 +55,13 @@ public static HtmlInputButton CreateHtmlResetButton() public static Control CreateInputField(string name, string labelText) { - var input = GraphLabsUIFactory.CreateHtmlInputText(); + var input = CreateHtmlInputText(); input.Name = name; input.ID = name; - var label = GraphLabsUIFactory.CreateHtmlLabel(); - label.InnerText = labelText; + var label = CreateHtmlLabel(labelText); - var div = new HtmlGenericControl("div"); + var div = CreateDiv(); div.Controls.Add(label); label.Controls.Add(input); return div; @@ -68,7 +69,7 @@ public static Control CreateInputField(string name, string labelText) public static Control CreateInputCheckBox(string name, string labelText) { - var input = GraphLabsUIFactory.CreateHtmlInputCheckBox(); + var input = CreateHtmlInputCheckBox(); input.Name = name; input.ID = name; input.Value = "true"; @@ -77,15 +78,44 @@ public static Control CreateInputCheckBox(string name, string labelText) HtmlGenericControl script = new HtmlGenericControl("script"); script.InnerHtml = "function checkboxChange(chkBox) { if (chkBox.value==\"true\") {chkBox.value= \"false\"; chkBox.indeterminate = true;} else { chkBox.value= \"true\"; chkBox.checked=true; } }"; - var label = GraphLabsUIFactory.CreateHtmlLabel(); - label.InnerText = labelText; + var label = CreateHtmlLabel(labelText); - var div = new HtmlGenericControl("div"); + var div = CreateDiv(); div.Controls.Add(label); label.Controls.Add(input); label.Controls.Add(script); return div; } + + public static Control CreateDiv() + { + return new HtmlGenericControl("div"); + } + + public static Control CreateSelectField(string name, string desc, Dictionary options) + { + var div = CreateDiv(); + var label = CreateHtmlLabel(desc); + + var select = new HtmlGenericControl("select"); + select.Attributes.Add("name", name); + foreach (var option in options) + { + select.Controls.Add(CreateHtmlOption(option.Key, option.Value)); + } + + div.Controls.Add(label); + div.Controls.Add(select); + return div; + } + + private static Control CreateHtmlOption(string value, string desc) + { + var option = new HtmlGenericControl("option"); + option.Attributes.Add("value", value); + option.InnerText = desc; + return option; + } } } \ No newline at end of file diff --git a/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs index d69c2b7..d34609f 100644 --- a/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs +++ b/GraphLabs.Site/Views/Helpers/GraphLabsWebGrid.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Web; using System.Web.Helpers; @@ -38,7 +40,7 @@ public IHtmlString GetHtml(string tableStyle = "webGrid", string headerStyle = " selectedRowStyle, caption, displayHeader, fillEmptyRows, emptyRowCellValue, columns, exclusions, mode, firstText, previousText, nextText, lastText, numericLinksCount, htmlAttributes ).ToString()); - + return new HtmlString(buildHtml.ToString()); } @@ -47,11 +49,11 @@ private void AddHtmlFilters(StringBuilder stringBuilder) var mainDiv = new HtmlGenericControl("div"); var form = GraphLabsUIFactory.CreateHtmlForm(); mainDiv.Controls.Add(form); - + if (IsA(_source, typeof(IFilterable<,>))) { var e = GetType(_source, typeof(IFilterable<,>)); - + var genericArgument = e.GetGenericArguments()[1]; foreach (var propertyInfo in genericArgument.GetProperties()) { @@ -59,27 +61,45 @@ private void AddHtmlFilters(StringBuilder stringBuilder) { if (customAttributeData.AttributeType.GetInterfaces().Contains(typeof(IFilterAttribute))) { - if (propertyInfo.PropertyType == typeof(bool)) + if (customAttributeData.AttributeType == typeof(StringFilterAttribute)) { - form.Controls.Add(GraphLabsUIFactory.CreateInputCheckBox(propertyInfo.Name, - (string) customAttributeData.ConstructorArguments[0].Value)); - } else { - form.Controls.Add(GraphLabsUIFactory.CreateInputField(propertyInfo.Name, - (string) customAttributeData.ConstructorArguments[0].Value)); + //фильтрация по одному полю с подписью + if (propertyInfo.PropertyType == typeof(bool)) + { + form.Controls.Add(GraphLabsUIFactory.CreateInputCheckBox(propertyInfo.Name, + (string) customAttributeData.ConstructorArguments[0].Value)); + } + else + { + form.Controls.Add(GraphLabsUIFactory.CreateInputField(propertyInfo.Name, + (string) customAttributeData.ConstructorArguments[0].Value)); + } + } + else if (customAttributeData.AttributeType == typeof(BoundedFilterAttribute)) + { + //фильтрация с подписанным фильтруемым полем с ограниченным набором значений + var options = + ((ReadOnlyCollection) customAttributeData + .ConstructorArguments[1].Value) + .Select(a => a.Value) + .Select((v, i) => new {Key = i, Value = v}) + .ToDictionary(o => o.Key.ToString(), o => o.Value.ToString()); + form.Controls.Add(GraphLabsUIFactory.CreateSelectField(propertyInfo.Name, + (string) customAttributeData.ConstructorArguments[0].Value, options)); } } } } - } - if (form.Controls.Count == 0) - { - return; - } + if (form.Controls.Count == 0) + { + return; + } - form.Controls.Add(GraphLabsUIFactory.CreateHtmlResetButton()); - form.Controls.Add(GraphLabsUIFactory.CreateHtmlSubmitButton()); - mainDiv.RenderControl(new HtmlTextWriter(new StringWriter(stringBuilder))); + form.Controls.Add(GraphLabsUIFactory.CreateHtmlResetButton()); + form.Controls.Add(GraphLabsUIFactory.CreateHtmlSubmitButton()); + mainDiv.RenderControl(new HtmlTextWriter(new StringWriter(stringBuilder))); + } } private static Type GetType(object o, Type t) From 919f00ca56e340310f5d03bdc4421481f3ae8df4 Mon Sep 17 00:00:00 2001 From: avalsa Date: Sat, 28 Apr 2018 13:21:52 +0300 Subject: [PATCH 08/14] add dynamic bounded filtering attribute --- .../Filters/DynamicBoundFilterAttribute.cs | 17 ++++++++ GraphLabs.Site.Core/Filters/FilterParams.cs | 13 ++++++ .../Filters/GraphLabsValuesHolder.cs | 41 +++++++++++++++++++ .../Filters/IFilterValuesProvider.cs | 9 ++++ .../GraphLabs.Site.Core.csproj | 6 +++ .../GraphLabs.Site.Models.csproj | 1 + GraphLabs.Site.Models/Groups/GroupModel.cs | 3 +- .../Groups/NameFilterProvider.cs | 18 ++++++++ .../Views/Helpers/GraphLabsUIFactory.cs | 9 ++++ .../Views/Helpers/GraphLabsWebGrid.cs | 15 +++++++ 10 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 GraphLabs.Site.Core/Filters/DynamicBoundFilterAttribute.cs create mode 100644 GraphLabs.Site.Core/Filters/GraphLabsValuesHolder.cs create mode 100644 GraphLabs.Site.Core/Filters/IFilterValuesProvider.cs create mode 100644 GraphLabs.Site.Models/Groups/NameFilterProvider.cs diff --git a/GraphLabs.Site.Core/Filters/DynamicBoundFilterAttribute.cs b/GraphLabs.Site.Core/Filters/DynamicBoundFilterAttribute.cs new file mode 100644 index 0000000..98c700e --- /dev/null +++ b/GraphLabs.Site.Core/Filters/DynamicBoundFilterAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace GraphLabs.Site.Core.Filters +{ + [System.AttributeUsage(System.AttributeTargets.Property)] + public class DynamicBoundFilterAttribute : Attribute, IFilterAttribute + { + private String _name; + private Type _typeOfProvider; + + public DynamicBoundFilterAttribute(string name, Type typeOfProvider) + { + _name = name; + _typeOfProvider = typeOfProvider; + } + } +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/FilterParams.cs b/GraphLabs.Site.Core/Filters/FilterParams.cs index 59fbf38..d08b581 100644 --- a/GraphLabs.Site.Core/Filters/FilterParams.cs +++ b/GraphLabs.Site.Core/Filters/FilterParams.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Reflection; @@ -8,6 +9,7 @@ namespace GraphLabs.Site.Core.Filters public class FilterParams { private readonly NameValueCollection _filterParams; + private Dictionary cache = new Dictionary(); public FilterParams(NameValueCollection filterParams) { @@ -42,6 +44,17 @@ public object GetBoundedParam(string name) { return ((ReadOnlyCollection) customAttributeData .ConstructorArguments[1].Value)[index.Value].Value; + } else if (customAttributeData.AttributeType == typeof(DynamicBoundFilterAttribute)) + { + if (cache.ContainsKey(name)) + { + return cache[name]; + } + var key = GetParam(name + "ver"); + var values = (object[]) GraphLabsValuesHolder.getAndRemove(key); + var result = values[index.Value]; + cache[name] = result; + return result; } } diff --git a/GraphLabs.Site.Core/Filters/GraphLabsValuesHolder.cs b/GraphLabs.Site.Core/Filters/GraphLabsValuesHolder.cs new file mode 100644 index 0000000..b72680d --- /dev/null +++ b/GraphLabs.Site.Core/Filters/GraphLabsValuesHolder.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Concurrent; + +namespace GraphLabs.Site.Core.Filters +{ + public class GraphLabsValuesHolder + { + private static readonly Random r = new Random(); + private static readonly ConcurrentDictionary _container = + new ConcurrentDictionary(); + + //return accesssor string to type + public static string registerValue(object value) + { + while (true) + { + var key = r.Next().ToString(); + if (!_container.ContainsKey(key)) + { + lock (_container) + { + if (!_container.ContainsKey(key)) + { + _container[key] = value; + return key; + } + } + } + } + + } + + //gets and remove value + public static object getAndRemove(string key) + { + var o = _container[key]; + _container.TryRemove(key, out o); + return o; + } + } +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/Filters/IFilterValuesProvider.cs b/GraphLabs.Site.Core/Filters/IFilterValuesProvider.cs new file mode 100644 index 0000000..93e0bb7 --- /dev/null +++ b/GraphLabs.Site.Core/Filters/IFilterValuesProvider.cs @@ -0,0 +1,9 @@ +using System; + +namespace GraphLabs.Site.Core.Filters +{ + public interface IFilterValuesProvider + { + Object[] getValues(); + } +} \ No newline at end of file diff --git a/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj b/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj index c36d7d0..bbc7e3e 100644 --- a/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj +++ b/GraphLabs.Site.Core/GraphLabs.Site.Core.csproj @@ -125,6 +125,9 @@ ..\GraphLabs.WcfServices\Bin\GraphLabs.Site.Models.dll + + ..\packages\Unity.3.0.1304.1\lib\Net45\Microsoft.Practices.Unity.dll + ..\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll @@ -145,11 +148,14 @@ Properties\AssemblyVersion.cs + + + diff --git a/GraphLabs.Site.Models/GraphLabs.Site.Models.csproj b/GraphLabs.Site.Models/GraphLabs.Site.Models.csproj index 11702ed..3cf11db 100644 --- a/GraphLabs.Site.Models/GraphLabs.Site.Models.csproj +++ b/GraphLabs.Site.Models/GraphLabs.Site.Models.csproj @@ -158,6 +158,7 @@ + diff --git a/GraphLabs.Site.Models/Groups/GroupModel.cs b/GraphLabs.Site.Models/Groups/GroupModel.cs index 1f8cacf..9810e44 100644 --- a/GraphLabs.Site.Models/Groups/GroupModel.cs +++ b/GraphLabs.Site.Models/Groups/GroupModel.cs @@ -12,7 +12,8 @@ public class GroupModel : AbstractFilterableModel, IEntityBasedModel