diff --git a/src/Framework/Framework/Controls/DataPager.cs b/src/Framework/Framework/Controls/DataPager.cs index 7292dcd86b..8a300df463 100644 --- a/src/Framework/Framework/Controls/DataPager.cs +++ b/src/Framework/Framework/Controls/DataPager.cs @@ -23,7 +23,7 @@ public class DataPager : HtmlGenericControl private readonly GridViewDataSetBindingProvider gridViewDataSetBindingProvider; private readonly BindingCompilationService bindingCompilationService; - private DataPagerCommands? pagerCommands; + private DataPagerBindings? pagerBindings; public DataPager(GridViewDataSetBindingProvider gridViewDataSetBindingProvider, BindingCompilationService bindingCompilationService) @@ -137,7 +137,7 @@ public ICommandBinding? LoadData protected HtmlGenericControl? ContentWrapper { get; set; } protected HtmlGenericControl? GoToFirstPageButton { get; set; } protected HtmlGenericControl? GoToPreviousPageButton { get; set; } - protected PlaceHolder? NumberButtonsPlaceHolder { get; set; } + protected Repeater? NumberButtonsRepeater { get; set; } protected HtmlGenericControl? GoToNextPageButton { get; set; } protected HtmlGenericControl? GoToLastPageButton { get; set; } protected virtual string ActiveItemCssClass => "active"; @@ -160,75 +160,70 @@ protected virtual void DataBind(Hosting.IDotvvmRequestContext context) Children.Clear(); var dataSetBinding = GetValueBinding(DataSetProperty)!; - var dataContextType = DataContextStack.Create(dataSetBinding.ResultType, this.GetDataContextType()); - ContentWrapper = CreateWrapperList(dataContextType); + var dataSetType = dataSetBinding.ResultType; + ContentWrapper = CreateWrapperList(); Children.Add(ContentWrapper); var commandType = LoadData is {} ? GridViewDataSetCommandType.StaticCommand : GridViewDataSetCommandType.Command; - pagerCommands = gridViewDataSetBindingProvider.GetDataPagerCommands(dataContextType, commandType); - object enabledValue = GetValueRaw(EnabledProperty)!; + pagerBindings = gridViewDataSetBindingProvider.GetDataPagerCommands(this.GetDataContextType().NotNull(), dataSetBinding, commandType); + + + var enabled = GetValueOrBinding(EnabledProperty)!; - if (typeof(IPageableGridViewDataSet).IsAssignableFrom(dataContextType.DataContextType)) + if (typeof(IPageableGridViewDataSet).IsAssignableFrom(dataSetType)) { - GoToFirstPageButton = CreateNavigationButton("««", FirstPageTemplate, enabledValue, pagerCommands.GoToFirstPage!, context); + GoToFirstPageButton = CreateNavigationButton("««", FirstPageTemplate, enabled, pagerBindings.GoToFirstPage!, context); + GoToFirstPageButton.CssClasses.Add(DisabledItemCssClass, new ValueOrBinding(pagerBindings.IsFirstPage.NotNull())); ContentWrapper.Children.Add(GoToFirstPageButton); } - if (typeof(IPageableGridViewDataSet).IsAssignableFrom(dataContextType.DataContextType)) + if (typeof(IPageableGridViewDataSet).IsAssignableFrom(dataSetType)) { - GoToPreviousPageButton = CreateNavigationButton("«", PreviousPageTemplate, enabledValue, pagerCommands.GoToPreviousPage!, context); + GoToPreviousPageButton = CreateNavigationButton("«", PreviousPageTemplate, enabled, pagerBindings.GoToPreviousPage!, context); + GoToPreviousPageButton.CssClasses.Add(DisabledItemCssClass, new ValueOrBinding(pagerBindings.IsFirstPage.NotNull())); ContentWrapper.Children.Add(GoToPreviousPageButton); } - if (typeof(IPageableGridViewDataSet).IsAssignableFrom(dataContextType.DataContextType)) + if (pagerBindings.PageNumbers is {}) { // number fields - NumberButtonsPlaceHolder = new PlaceHolder(); - ContentWrapper.Children.Add(NumberButtonsPlaceHolder); - - if (DataSet is IPageableGridViewDataSet dataSet) - { - var currentPageTextContext = DataContextStack.Create(typeof(int), dataContextType); - var i = 0; - foreach (var number in dataSet.PagingOptions.NearPageIndexes) - { - var li = new HtmlGenericControl("li"); - li.SetDataContextType(currentPageTextContext); - li.SetBinding(DataContextProperty, GetNearIndexesBinding(context, i, dataContextType)); - if (number == dataSet.PagingOptions.PageIndex) - { - li.Attributes.Set("class", ActiveItemCssClass); - } - var link = new LinkButton() { Text = (number + 1).ToString() }; - link.SetBinding(ButtonBase.ClickProperty, pagerCommands.GoToPage!); - if (!true.Equals(enabledValue)) link.SetValue(LinkButton.EnabledProperty, enabledValue); - li.Children.Add(link); - NumberButtonsPlaceHolder.Children.Add(li); - - i++; - } - } + var liTemplate = new HtmlGenericControl("li"); + // li.SetDataContextType(currentPageTextContext); + // li.SetBinding(DataContextProperty, GetNearIndexesBinding(context, i, dataContextType)); + liTemplate.CssClasses.Add(ActiveItemCssClass, new ValueOrBinding(pagerBindings.IsActivePage.NotNull())); + var link = new LinkButton(); + link.SetBinding(ButtonBase.ClickProperty, pagerBindings.GoToPage!); + link.SetBinding(ButtonBase.TextProperty, pagerBindings.PageNumberText); + if (!true.Equals(enabled)) link.SetValue(LinkButton.EnabledProperty, enabled); + liTemplate.Children.Add(link); + NumberButtonsRepeater = new Repeater() { + DataSource = pagerBindings.PageNumbers, + RenderWrapperTag = false, + RenderAsNamedTemplate = false, + ItemTemplate = new CloneTemplate(liTemplate) + }; + ContentWrapper.Children.Add(NumberButtonsRepeater); } - if (typeof(IPageableGridViewDataSet).IsAssignableFrom(dataContextType.DataContextType)) + if (typeof(IPageableGridViewDataSet).IsAssignableFrom(dataSetType)) { - GoToNextPageButton = CreateNavigationButton("»", NextPageTemplate, enabledValue, pagerCommands.GoToNextPage!, context); + GoToNextPageButton = CreateNavigationButton("»", NextPageTemplate, enabled, pagerBindings.GoToNextPage!, context); + GoToNextPageButton.CssClasses.Add(DisabledItemCssClass, new ValueOrBinding(pagerBindings.IsLastPage.NotNull())); ContentWrapper.Children.Add(GoToNextPageButton); } - if (typeof(IPageableGridViewDataSet).IsAssignableFrom(dataContextType.DataContextType)) + if (typeof(IPageableGridViewDataSet).IsAssignableFrom(dataSetType)) { - GoToLastPageButton = CreateNavigationButton("»»", LastPageTemplate, enabledValue, pagerCommands.GoToLastPage!, context); + GoToLastPageButton = CreateNavigationButton("»»", LastPageTemplate, enabled, pagerBindings.GoToLastPage!, context); + GoToLastPageButton.CssClasses.Add(DisabledItemCssClass, new ValueOrBinding(pagerBindings.IsLastPage.NotNull())); ContentWrapper.Children.Add(GoToLastPageButton); } } - protected virtual HtmlGenericControl CreateWrapperList(DataContextStack dataContext) + protected virtual HtmlGenericControl CreateWrapperList() { var list = new HtmlGenericControl("ul"); - list.SetDataContextType(dataContext); - list.SetBinding(DataContextProperty, GetDataSetBinding()); return list; } @@ -256,20 +251,6 @@ protected virtual void SetButtonContent(Hosting.IDotvvmRequestContext context, L } } - private ConditionalWeakTable> _nearIndexesBindingCache - = new ConditionalWeakTable>(); - - private ValueBindingExpression GetNearIndexesBinding(IDotvvmRequestContext context, int i, DataContextStack? dataContext = null) - { - return - _nearIndexesBindingCache.GetOrCreateValue(context.Configuration) - .GetOrAdd(i, _ => - ValueBindingExpression.CreateBinding( - bindingCompilationService.WithoutInitialization(), - h => ((IPageableGridViewDataSet)h[0]!).PagingOptions.NearPageIndexes[i], - dataContext)); - } - protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { if (RenderOnServer) @@ -285,7 +266,7 @@ protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequest var loadDataExpression = KnockoutHelper.GenerateClientPostbackLambda("LoadData", loadData, this, new PostbackScriptOptions(elementAccessor: "$element", koContext: CodeParameterAssignment.FromIdentifier("$context"))); helperBinding.Add("loadDataSet", loadDataExpression); } - writer.WriteKnockoutDataBindComment("dotvvm-gridviewdataset", helperBinding.ToString()); + writer.AddKnockoutDataBind("dotvvm-gridviewdataset", helperBinding.ToString()); // If Visible property was set to something, it will be overwritten by this. TODO: is it how it should behave? if (HideWhenOnlyOnePage) @@ -295,9 +276,6 @@ protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequest writer.AddKnockoutDataBind("visible", $"({dataSetBinding}).PagingOptions().PagesCount() > 1"); } - writer.AddKnockoutDataBind("with", this, DataSetProperty, renderEvenInServerRenderingMode: true); - - if (GetValueBinding(EnabledProperty) is IValueBinding enabledBinding) { var disabledBinding = enabledBinding.GetProperty().Binding.CastTo(); @@ -311,105 +289,25 @@ protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequest base.AddAttributesToRender(writer, context); } - protected virtual void AddItemCssClass(IHtmlWriter writer, IDotvvmRequestContext context) - { - } - protected virtual void AddKnockoutDisabledCssDataBind(IHtmlWriter writer, IDotvvmRequestContext context, string expression) { writer.AddKnockoutDataBind("css", $"{{ '{DisabledItemCssClass}': {expression} }}"); } - protected virtual void AddKnockoutActiveCssDataBind(IHtmlWriter writer, IDotvvmRequestContext context, string expression) - { - writer.AddKnockoutDataBind("css", $"{{ '{ActiveItemCssClass}': {expression} }}"); - } - - private static ParametrizedCode currentPageTextJs = new JsBinaryExpression(new JsBinaryExpression(new JsLiteral(1), BinaryOperatorType.Plus, new JsSymbolicParameter(JavascriptTranslator.KnockoutViewModelParameter)), BinaryOperatorType.Plus, new JsLiteral("")).FormatParametrizedScript(); - protected override void RenderContents(IHtmlWriter writer, IDotvvmRequestContext context) { - AddItemCssClass(writer, context); - AddKnockoutDisabledCssDataBind(writer, context, "PagingOptions().IsFirstPage()"); - GoToFirstPageButton!.Render(writer, context); - - AddItemCssClass(writer, context); - AddKnockoutDisabledCssDataBind(writer, context, "PagingOptions().IsFirstPage()"); - GoToPreviousPageButton!.Render(writer, context); - - // render template - writer.WriteKnockoutForeachComment("PagingOptions().NearPageIndexes"); - - // render page number - NumberButtonsPlaceHolder!.Children.Clear(); - RenderPageNumberButton(writer, context); - - writer.WriteKnockoutDataBindEndComment(); - - AddItemCssClass(writer, context); - AddKnockoutDisabledCssDataBind(writer, context, "PagingOptions().IsLastPage()"); - GoToNextPageButton!.Render(writer, context); - - AddItemCssClass(writer, context); - AddKnockoutDisabledCssDataBind(writer, context, "PagingOptions().IsLastPage()"); - GoToLastPageButton!.Render(writer, context); + base.RenderContents(writer, context); } - protected virtual void RenderPageNumberButton(IHtmlWriter writer, IDotvvmRequestContext context) + protected override void RenderBeginTag(IHtmlWriter writer, IDotvvmRequestContext context) { - HtmlGenericControl li = new HtmlGenericControl("li"); - var currentPageTextContext = DataContextStack.Create(typeof(int), NumberButtonsPlaceHolder!.GetDataContextType()); - li.SetDataContextType(currentPageTextContext); - li.DataContext = null; - var currentPageTextBinding = ValueBindingExpression.CreateBinding(bindingCompilationService.WithoutInitialization(), - vm => ((int) vm[0]! + 1).ToString(), - currentPageTextJs, - currentPageTextContext); - - if (!RenderLinkForCurrentPage) - { - writer.AddKnockoutDataBind("visible", "$data == $parent.PagingOptions().PageIndex()"); - AddItemCssClass(writer, context); - writer.AddAttribute("class", ActiveItemCssClass, true); - var literal = new Literal(); - literal.DataContext = 0; - literal.SetBinding(Literal.TextProperty, currentPageTextBinding); - li.Children.Add(literal); - NumberButtonsPlaceHolder!.Children.Add(li); - - li.Render(writer, context); - - writer.AddKnockoutDataBind("visible", "$data != $parent.PagingOptions().PageIndex()"); - } - - li = new HtmlGenericControl("li"); - li.SetDataContextType(currentPageTextContext); - li.DataContext = null; - - NumberButtonsPlaceHolder!.Children.Add(li); - AddItemCssClass(writer, context); - - if (RenderLinkForCurrentPage) - AddKnockoutActiveCssDataBind(writer, context, "$data == $parent.PagingOptions().PageIndex()"); - - li.SetValue(Internal.PathFragmentProperty, "$parent.PagingOptions.NearPageIndexes[$index]"); - var link = new LinkButton(); - li.Children.Add(link); - link.SetDataContextType(currentPageTextContext); - link.SetBinding(ButtonBase.TextProperty, currentPageTextBinding); - link.SetBinding(ButtonBase.ClickProperty, pagerCommands.GoToPage!); - object enabledValue = GetValueRaw(EnabledProperty)!; - if (!true.Equals(enabledValue)) link.SetValue(LinkButton.EnabledProperty, enabledValue); - - li.Render(writer, context); + // don't, delegated to the ContentWrapper html element } - protected override void RenderEndTag(IHtmlWriter writer, IDotvvmRequestContext context) { - base.RenderEndTag(writer, context); - writer.WriteKnockoutDataBindEndComment(); } + private IValueBinding GetDataSetBinding() => GetValueBinding(DataSetProperty) ?? throw new DotvvmControlException(this, "The DataSet property of the dot:DataPager control must be set!"); } diff --git a/src/Framework/Framework/Controls/DataPagerCommands.cs b/src/Framework/Framework/Controls/DataPagerCommands.cs index 9833261de0..7d6045f3cb 100644 --- a/src/Framework/Framework/Controls/DataPagerCommands.cs +++ b/src/Framework/Framework/Controls/DataPagerCommands.cs @@ -1,13 +1,21 @@ +using System.Collections; +using System.Collections.Generic; using DotVVM.Framework.Binding.Expressions; namespace DotVVM.Framework.Controls { - public class DataPagerCommands + public class DataPagerBindings { public ICommandBinding? GoToFirstPage { get; init; } public ICommandBinding? GoToPreviousPage { get; init; } public ICommandBinding? GoToNextPage { get; init; } public ICommandBinding? GoToLastPage { get; init; } public ICommandBinding? GoToPage { get; init; } + + public IStaticValueBinding? IsFirstPage { get; init; } + public IStaticValueBinding? IsLastPage { get; init; } + public IStaticValueBinding>? PageNumbers { get; init; } + public IStaticValueBinding? IsActivePage { get; init; } + public IStaticValueBinding? PageNumberText { get; init; } } -} \ No newline at end of file +} diff --git a/src/Framework/Framework/Controls/GridViewDataSetBindingProvider.cs b/src/Framework/Framework/Controls/GridViewDataSetBindingProvider.cs index c9af459673..4f9125c784 100644 --- a/src/Framework/Framework/Controls/GridViewDataSetBindingProvider.cs +++ b/src/Framework/Framework/Controls/GridViewDataSetBindingProvider.cs @@ -10,6 +10,7 @@ using DotVVM.Framework.Binding.Properties; using DotVVM.Framework.Compilation; using DotVVM.Framework.Compilation.ControlTree; +using DotVVM.Framework.Compilation.ControlTree.Resolved; namespace DotVVM.Framework.Controls; @@ -17,7 +18,7 @@ public class GridViewDataSetBindingProvider { private readonly BindingCompilationService service; - private readonly ConcurrentDictionary<(DataContextStack, GridViewDataSetCommandType), DataPagerCommands> dataPagerCommands = new(); + private readonly ConcurrentDictionary<(DataContextStack dataContextStack, IValueBinding dataSetBinding, GridViewDataSetCommandType commandType), DataPagerBindings> dataPagerCommands = new(); private readonly ConcurrentDictionary<(DataContextStack, GridViewDataSetCommandType), GridViewCommands> gridViewCommands = new(); public GridViewDataSetBindingProvider(BindingCompilationService service) @@ -25,9 +26,9 @@ public GridViewDataSetBindingProvider(BindingCompilationService service) this.service = service; } - public DataPagerCommands GetDataPagerCommands(DataContextStack dataContextStack, GridViewDataSetCommandType commandType) + public DataPagerBindings GetDataPagerCommands(DataContextStack dataContextStack, IValueBinding dataSetBinding, GridViewDataSetCommandType commandType) { - return dataPagerCommands.GetOrAdd((dataContextStack, commandType), _ => GetDataPagerCommandsCore(dataContextStack, commandType)); + return dataPagerCommands.GetOrAdd((dataContextStack, dataSetBinding, commandType), x => GetDataPagerCommandsCore(x.dataContextStack, x.dataSetBinding, x.commandType)); } public GridViewCommands GetGridViewCommands(DataContextStack dataContextStack, GridViewDataSetCommandType commandType) @@ -35,46 +36,84 @@ public GridViewCommands GetGridViewCommands(DataContextStack dataContextStack, G return gridViewCommands.GetOrAdd((dataContextStack, commandType), _ => GetGridViewCommandsCore(dataContextStack, commandType)); } - private DataPagerCommands GetDataPagerCommandsCore(DataContextStack dataContextStack, GridViewDataSetCommandType commandType) + private DataPagerBindings GetDataPagerCommandsCore(DataContextStack dataContextStack, IValueBinding dataSetBinding, GridViewDataSetCommandType commandType) { - ICommandBinding? GetCommandOrNull(ParameterExpression dataSetParam, DataContextStack dataContextStack, string methodName, params Expression[] arguments) + var dataSetExpr = dataSetBinding.GetProperty().Expression; + ICommandBinding? GetCommandOrNull(DataContextStack dataContextStack, string methodName, params Expression[] arguments) { - return typeof(T).IsAssignableFrom(dataSetParam.Type) - ? CreateCommandBinding(commandType, dataSetParam, dataContextStack, methodName, arguments) + return typeof(T).IsAssignableFrom(dataSetExpr.Type) + ? CreateCommandBinding(commandType, dataSetExpr, dataContextStack, methodName, arguments) : null; } + + IStaticValueBinding? GetValueBindingOrNull(Expression> expression) + { + if (typeof(T).IsAssignableFrom(dataSetExpr.Type)) + { + return (IStaticValueBinding)ValueOrBindingExtensions.SelectImpl(dataSetBinding, expression); + } + else + { + return null; + } + } + ParameterExpression CreateParameter(DataContextStack dataContextStack, string name = "_this") { return Expression.Parameter(dataContextStack.DataContextType, name).AddParameterAnnotation(new BindingParameterAnnotation(dataContextStack)); } - return new DataPagerCommands() + var pageIndexDataContext = DataContextStack.CreateCollectionElement( + typeof(int), dataContextStack + ); + + return new DataPagerBindings() { GoToFirstPage = GetCommandOrNull>( - CreateParameter(dataContextStack), dataContextStack, nameof(IPagingFirstPageCapability.GoToFirstPage)), GoToPreviousPage = GetCommandOrNull>( - CreateParameter(dataContextStack), dataContextStack, nameof(IPagingPreviousPageCapability.GoToPreviousPage)), GoToNextPage = GetCommandOrNull>( - CreateParameter(dataContextStack), dataContextStack, nameof(IPagingNextPageCapability.GoToNextPage)), GoToLastPage = GetCommandOrNull>( - CreateParameter(dataContextStack), dataContextStack, nameof(IPagingLastPageCapability.GoToLastPage)), GoToPage = GetCommandOrNull>( - CreateParameter(dataContextStack, "_parent"), - DataContextStack.Create(typeof(int), dataContextStack), + pageIndexDataContext, nameof(IPagingPageIndexCapability.GoToPage), - CreateParameter(DataContextStack.Create(typeof(int), dataContextStack), "_thisIndex")) + CreateParameter(pageIndexDataContext, "_thisIndex")), + + IsFirstPage = + GetValueBindingOrNull, bool>(d => d.PagingOptions.IsFirstPage) ?? + GetValueBindingOrNull, bool>(d => d.PagingOptions.IsFirstPage), + + IsLastPage = + GetValueBindingOrNull, bool>(d => d.PagingOptions.IsLastPage) ?? + GetValueBindingOrNull, bool>(d => d.PagingOptions.IsLastPage), + + PageNumbers = + GetValueBindingOrNull, IEnumerable>(d => d.PagingOptions.NearPageIndexes), + + IsActivePage = // _this == _parent.DataSet.PagingOptions.PageIndex + typeof(IPageableGridViewDataSet).IsAssignableFrom(dataSetExpr.Type) + ? new ValueBindingExpression(service, new object[] { + pageIndexDataContext, + new ParsedExpressionBindingProperty(Expression.Equal( + CreateParameter(pageIndexDataContext, "_thisIndex"), + Expression.Property(Expression.Property(dataSetExpr, "PagingOptions"), "PageIndex") + )), + }) + : null, + + PageNumberText = + service.Cache.CreateValueBinding("_this + 1", pageIndexDataContext) }; } @@ -103,16 +142,16 @@ ParameterExpression CreateParameter(DataContextStack dataContextStack) }; } - private ICommandBinding CreateCommandBinding(GridViewDataSetCommandType commandType, ParameterExpression dataSetParam, DataContextStack dataContextStack, string methodName, Expression[] arguments, Func? transformExpression = null) + private ICommandBinding CreateCommandBinding(GridViewDataSetCommandType commandType, Expression dataSet, DataContextStack dataContextStack, string methodName, Expression[] arguments, Func? transformExpression = null) { var body = new List(); // get concrete type from implementation of IXXXableGridViewDataSet - var optionsConcreteType = GetOptionsConcreteType(dataSetParam.Type, out var optionsProperty); + var optionsConcreteType = GetOptionsConcreteType(dataSet.Type, out var optionsProperty); // call dataSet.XXXOptions.Method(...); var callMethodOnOptions = Expression.Call( - Expression.Convert(Expression.Property(dataSetParam, optionsProperty), optionsConcreteType), + Expression.Convert(Expression.Property(dataSet, optionsProperty), optionsConcreteType), optionsConcreteType.GetMethod(methodName)!, arguments); body.Add(callMethodOnOptions); @@ -120,10 +159,10 @@ private ICommandBinding CreateCommandBinding(GridViewDataSetC if (commandType == GridViewDataSetCommandType.Command) { // if we are on a server, call the dataSet.RequestRefresh if supported - if (typeof(IRefreshableGridViewDataSet).IsAssignableFrom(dataSetParam.Type)) + if (typeof(IRefreshableGridViewDataSet).IsAssignableFrom(dataSet.Type)) { var callRequestRefresh = Expression.Call( - Expression.Convert(dataSetParam, typeof(IRefreshableGridViewDataSet)), + Expression.Convert(dataSet, typeof(IRefreshableGridViewDataSet)), typeof(IRefreshableGridViewDataSet).GetMethod(nameof(IRefreshableGridViewDataSet.RequestRefresh))! ); body.Add(callRequestRefresh); @@ -146,7 +185,7 @@ private ICommandBinding CreateCommandBinding(GridViewDataSetC else if (commandType == GridViewDataSetCommandType.StaticCommand) { // on the client, wrap the call into client-side loading procedure - body.Add(CallClientSideLoad(dataSetParam)); + body.Add(CallClientSideLoad(dataSet)); Expression expression = Expression.Block(body); if (transformExpression != null) { diff --git a/src/Tests/ControlTests/DataPagerTests.cs b/src/Tests/ControlTests/DataPagerTests.cs index 5b89945e0f..f1be5bff24 100644 --- a/src/Tests/ControlTests/DataPagerTests.cs +++ b/src/Tests/ControlTests/DataPagerTests.cs @@ -38,7 +38,7 @@ public async Task CommandDataPager() .Select(c => (c.control, c.command, str: c.command.GetProperty().Expression.ToCSharpString().Trim().TrimEnd(';'))) .OrderBy(c => c.str) .ToArray(); - check.CheckLines(commandExpressions.Select(c => c.str), checkName: "command-bindings", fileExtension: "txt"); + check.CheckLines(commandExpressions.DistinctBy(c => c.command).Select(c => c.str), checkName: "command-bindings", fileExtension: "txt"); check.CheckString(r.FormattedHtml, fileExtension: "html"); diff --git a/src/Tests/ControlTests/testoutputs/DataPagerTests.CommandDataPager-command-bindings.txt b/src/Tests/ControlTests/testoutputs/DataPagerTests.CommandDataPager-command-bindings.txt index 716306d083..dd845c50d5 100644 --- a/src/Tests/ControlTests/testoutputs/DataPagerTests.CommandDataPager-command-bindings.txt +++ b/src/Tests/ControlTests/testoutputs/DataPagerTests.CommandDataPager-command-bindings.txt @@ -1,10 +1,10 @@ -((PagingOptions)_parent.PagingOptions).GoToPage(_thisIndex); -((IRefreshableGridViewDataSet)_parent).RequestRefresh() -((PagingOptions)_this.PagingOptions).GoToFirstPage(); -((IRefreshableGridViewDataSet)_this).RequestRefresh() -((PagingOptions)_this.PagingOptions).GoToLastPage(); -((IRefreshableGridViewDataSet)_this).RequestRefresh() -((PagingOptions)_this.PagingOptions).GoToNextPage(); -((IRefreshableGridViewDataSet)_this).RequestRefresh() -((PagingOptions)_this.PagingOptions).GoToPreviousPage(); -((IRefreshableGridViewDataSet)_this).RequestRefresh() +((PagingOptions)_this.Customers.PagingOptions).GoToFirstPage(); +((IRefreshableGridViewDataSet)_this.Customers).RequestRefresh() +((PagingOptions)_this.Customers.PagingOptions).GoToLastPage(); +((IRefreshableGridViewDataSet)_this.Customers).RequestRefresh() +((PagingOptions)_this.Customers.PagingOptions).GoToNextPage(); +((IRefreshableGridViewDataSet)_this.Customers).RequestRefresh() +((PagingOptions)_this.Customers.PagingOptions).GoToPage(_thisIndex); +((IRefreshableGridViewDataSet)_this.Customers).RequestRefresh() +((PagingOptions)_this.Customers.PagingOptions).GoToPreviousPage(); +((IRefreshableGridViewDataSet)_this.Customers).RequestRefresh() diff --git a/src/Tests/ControlTests/testoutputs/DataPagerTests.CommandDataPager.html b/src/Tests/ControlTests/testoutputs/DataPagerTests.CommandDataPager.html index 865a9386c5..83586b2722 100644 --- a/src/Tests/ControlTests/testoutputs/DataPagerTests.CommandDataPager.html +++ b/src/Tests/ControlTests/testoutputs/DataPagerTests.CommandDataPager.html @@ -1,26 +1,23 @@ -
    -
  • - «« + diff --git a/src/Tests/Runtime/config-tests/ConfigurationSerializationTests.SerializeDefaultConfig.json b/src/Tests/Runtime/config-tests/ConfigurationSerializationTests.SerializeDefaultConfig.json index 31d5da1fae..042ab8074d 100644 --- a/src/Tests/Runtime/config-tests/ConfigurationSerializationTests.SerializeDefaultConfig.json +++ b/src/Tests/Runtime/config-tests/ConfigurationSerializationTests.SerializeDefaultConfig.json @@ -526,6 +526,10 @@ "mappingMode": "InnerElement", "onlyHardcoded": true }, + "LoadData": { + "type": "DotVVM.Framework.Binding.Expressions.ICommandBinding, DotVVM.Framework", + "onlyBindings": true + }, "NextPageTemplate": { "type": "DotVVM.Framework.Controls.ITemplate, DotVVM.Framework", "mappingMode": "InnerElement", @@ -1641,23 +1645,6 @@ "isActive": true, "isAttached": true } - }, - "DotvvmMarkupControl-33jwRoNrnlbAOVpOnCErXw==": { - "ShowDescription": { - "type": "System.Boolean", - "defaultValue": false - } - }, - "DotvvmMarkupControl-koCHqjx2oIk1rVwG1PzLJQ==": { - "Click": { - "type": "DotVVM.Framework.Binding.Expressions.Command, DotVVM.Framework", - "isCommand": true - } - }, - "DotvvmMarkupControl-YYPITyOzVEL518wclEMJZw==": { - "SomeProperty": { - "type": "System.String" - } } }, "capabilities": { diff --git a/src/Tests/ViewModel/GridViewDataSetTests.cs b/src/Tests/ViewModel/GridViewDataSetTests.cs index 9f10233881..169e42fbb4 100644 --- a/src/Tests/ViewModel/GridViewDataSetTests.cs +++ b/src/Tests/ViewModel/GridViewDataSetTests.cs @@ -18,14 +18,16 @@ namespace DotVVM.Framework.Tests.ViewModel [TestClass] public class GridViewDataSetTests { + private readonly BindingCompilationService bindingService; private readonly GridViewDataSetBindingProvider commandProvider; private readonly GridViewDataSet vm; private readonly DataContextStack dataContextStack; private readonly DotvvmControl control; + private readonly ValueBindingExpression> dataSetBinding; public GridViewDataSetTests() { - var bindingService = DotvvmTestHelper.DefaultConfig.ServiceProvider.GetRequiredService(); + bindingService = DotvvmTestHelper.DefaultConfig.ServiceProvider.GetRequiredService(); commandProvider = new GridViewDataSetBindingProvider(bindingService); // build viewmodel @@ -42,6 +44,7 @@ public GridViewDataSetTests() // create page dataContextStack = DataContextStack.Create(vm.GetType()); control = new DotvvmView() { DataContext = vm }; + dataSetBinding = ValueBindingExpression.CreateThisBinding>(bindingService, dataContextStack); } [TestMethod] @@ -49,13 +52,13 @@ public void GridViewDataSet_DataPagerCommands_Command() { // create control with page index data context var pageIndexControl = new PlaceHolder(); - var pageIndexDataContextStack = DataContextStack.Create(typeof(int), dataContextStack); + var pageIndexDataContextStack = DataContextStack.CreateCollectionElement(typeof(int), dataContextStack); pageIndexControl.SetDataContextType(pageIndexDataContextStack); pageIndexControl.SetProperty(p => p.DataContext, ValueOrBinding.FromBoxedValue(1)); control.Children.Add(pageIndexControl); // get pager commands - var commands = commandProvider.GetDataPagerCommands(dataContextStack, GridViewDataSetCommandType.Command); + var commands = commandProvider.GetDataPagerCommands(dataContextStack, dataSetBinding, GridViewDataSetCommandType.Command); // test evaluation of commands Assert.IsNotNull(commands.GoToLastPage); @@ -121,7 +124,7 @@ public void GridViewDataSet_GridViewCommands_Command() public void GridViewDataSet_DataPagerCommands_StaticCommand() { // get pager commands - var commands = commandProvider.GetDataPagerCommands(dataContextStack, GridViewDataSetCommandType.StaticCommand); + var commands = commandProvider.GetDataPagerCommands(dataContextStack, dataSetBinding, GridViewDataSetCommandType.StaticCommand); var goToFirstPage = CompileBinding(commands.GoToFirstPage); Console.WriteLine(goToFirstPage);