Skip to content

Commit

Permalink
dynamic data: support DynamicColumns virtual column
Browse files Browse the repository at this point in the history
  • Loading branch information
exyi committed Feb 20, 2022
1 parent 0aff84b commit d2a06b1
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 28 deletions.
77 changes: 77 additions & 0 deletions src/DynamicData/DynamicData/DynamicColumns.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Linq;
using DotVVM.Framework.Binding;
using DotVVM.Framework.Binding.Expressions;
using DotVVM.Framework.Compilation.Styles;
using DotVVM.Framework.Controls.DynamicData.Metadata;
using DotVVM.Framework.Hosting;
using DotVVM.Framework.Utils;

namespace DotVVM.Framework.Controls.DynamicData
{
// TODO: replace this with something else
public class DummyColumnThatDoesNothing : GridViewColumn
{
public DummyColumnThatDoesNothing()
{
Visible = false;
}

public override void CreateControls(IDotvvmRequestContext context, DotvvmControl container) { }
public override void CreateEditControls(IDotvvmRequestContext context, DotvvmControl container) { }
}
public class DynamicColumns: GridViewColumn
{
public static DotvvmCapabilityProperty PropsProperty =
DotvvmCapabilityProperty.RegisterCapability<Props, DynamicColumns>();

public static GridViewColumn[] Replace(IStyleMatchContext<DynamicColumns> col)
{
if (col.HasProperty(c => c.EditTemplate))
throw new NotSupportedException("EditTemplate is not supported in DynamicGridColumnGroup.");

var props = col.PropertyValue<Props>(PropsProperty).NotNull();

var context = new DynamicDataContext(col.Control.DataContextTypeStack, col.Configuration.ServiceProvider)
{
ViewName = props.ViewName,
GroupName = props.GroupName
};

var properties = DynamicEntityBase.GetPropertiesToDisplay(context);

var columns = properties.Select(p => CreateColumn(p, context, props)).ToArray();
return columns;
}

protected static DynamicGridColumn CreateColumn(PropertyDisplayMetadata property, DynamicDataContext context, Props props)
{
return
new DynamicGridColumn()
.SetProperty(p => p.Property, context.CreateValueBinding(property));
// .SetProperty("Changed", props.Changed.GetValueOrDefault(property.PropertyInfo.Name))
// .SetProperty("Enabled", props.Enabled.GetValueOrDefault(property.PropertyInfo.Name, true));
}

public override void CreateControls(IDotvvmRequestContext context, DotvvmControl container) => throw new NotImplementedException("DynamicGridColumn must be replaced using server-side styles. It cannot be used at runtime");
public override void CreateEditControls(IDotvvmRequestContext context, DotvvmControl container) => throw new NotImplementedException("DynamicGridColumn must be replaced using server-side styles. It cannot be used at runtime");

[DotvvmControlCapability]
public sealed record Props
{
/// <summary>
/// Gets or sets the view name (e.g. Insert, Edit, ReadOnly). Some fields may have different metadata for each view.
/// </summary>
public string? ViewName { get; init; }


/// <summary>
/// Gets or sets the group of fields that should be rendered. If not set, fields from all groups will be rendered.
/// </summary>
public string? GroupName { get; init; }

public IValueBinding? Property { get; init; }
public ValueOrBinding<bool> IsEditable { get; init; } = new(true);
}
}
}
3 changes: 3 additions & 0 deletions src/DynamicData/DynamicData/DynamicDataExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ private static void AddDynamicDataConfiguration(DotvvmConfiguration config)
private static void RegisterDynamicDataStyles(DotvvmConfiguration config)
{
var s = config.Styles;
s.Register<DynamicColumns>()
.SetDotvvmProperty(Styles.AppendProperty, c => DynamicColumns.Replace(c))
.ReplaceWith(new DummyColumnThatDoesNothing());
s.Register<DynamicGridColumn>()
.ReplaceWith(c => DynamicGridColumn.Replace(c));
}
Expand Down
2 changes: 1 addition & 1 deletion src/DynamicData/DynamicData/DynamicEntityBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ protected DynamicDataContext CreateDynamicDataContext()
/// <summary>
/// Gets the list of properties that should be displayed.
/// </summary>
protected virtual PropertyDisplayMetadata[] GetPropertiesToDisplay(DynamicDataContext context)
internal static PropertyDisplayMetadata[] GetPropertiesToDisplay(DynamicDataContext context)
{
var entityPropertyListProvider = context.Services.GetRequiredService<IEntityPropertyListProvider>();
var viewContext = context.CreateViewContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public static bool HasProperty(this IStyleMatchContext c, DotvvmProperty propert
/// <summary>
/// Determines whether the control has the given <see cref="DotvvmProperty"/>.
/// </summary>
public static bool HasProperty<TControl>(this IStyleMatchContext<TControl> c, Expression<Func<TControl, object>> property)
public static bool HasProperty<TControl>(this IStyleMatchContext<TControl> c, Expression<Func<TControl, object?>> property)
{
var prop = DotvvmPropertyUtils.GetDotvvmPropertyFromExpression(property);
return c.HasProperty(prop);
Expand All @@ -171,7 +171,7 @@ public static bool HasBinding(this IStyleMatchContext c, DotvvmProperty property
/// <summary>
/// Determines whether the control has the given <see cref="DotvvmProperty"/>.
/// </summary>
public static bool HasBinding<TControl>(this IStyleMatchContext<TControl> c, Expression<Func<TControl, object>> property)
public static bool HasBinding<TControl>(this IStyleMatchContext<TControl> c, Expression<Func<TControl, object?>> property)
{
var prop = DotvvmPropertyUtils.GetDotvvmPropertyFromExpression(property);
return c.HasBinding(prop);
Expand Down
5 changes: 5 additions & 0 deletions src/Framework/Framework/Controls/GridViewCheckBoxColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public override void CreateControls(IDotvvmRequestContext context, DotvvmControl

public override void CreateEditControls(IDotvvmRequestContext context, DotvvmControl container)
{
if (EditTemplate is {} editTemplate)
{
editTemplate.BuildContent(context, container);
return;
}
CreateControlsCore(container, enabled: true);
}

Expand Down
15 changes: 14 additions & 1 deletion src/Framework/Framework/Controls/GridViewColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,15 @@ public bool Visible
public static readonly DotvvmProperty EditCellDecoratorsProperty =
DotvvmProperty.Register<List<Decorator>?, GridViewColumn>(c => c.EditCellDecorators);

[MarkupOptions(AllowBinding = false, MappingMode = MappingMode.InnerElement)]
public ITemplate? EditTemplate
{
get { return (ITemplate?)GetValue(EditTemplateProperty); }
set { SetValue(EditTemplateProperty, value); }
}
public static readonly DotvvmProperty EditTemplateProperty
= DotvvmProperty.Register<ITemplate?, GridViewColumn>(c => c.EditTemplate, null);

/// <summary>
/// Gets or sets a list of decorators that will be applied on each header cell.
/// </summary>
Expand All @@ -173,7 +182,11 @@ public bool Visible

public abstract void CreateControls(IDotvvmRequestContext context, DotvvmControl container);

public abstract void CreateEditControls(IDotvvmRequestContext context, DotvvmControl container);
public virtual void CreateEditControls(IDotvvmRequestContext context, DotvvmControl container)
{
if (EditTemplate == null) throw new DotvvmControlException(this, $"{this.GetType().Name}.EditTemplate must be set when editing is allowed in a GridView.");
EditTemplate.BuildContent(context, container);
}

public virtual void CreateHeaderControls(IDotvvmRequestContext context, GridView gridView, Action<string?>? sortCommand, HtmlGenericControl cell, IGridViewDataSet? gridViewDataSet)
{
Expand Down
17 changes: 0 additions & 17 deletions src/Framework/Framework/Controls/GridViewTemplateColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,10 @@ public class GridViewTemplateColumn : GridViewColumn
public static readonly DotvvmProperty ContentTemplateProperty
= DotvvmProperty.Register<ITemplate?, GridViewTemplateColumn>(c => c.ContentTemplate, null);


[MarkupOptions(AllowBinding = false, MappingMode = MappingMode.InnerElement)]
public ITemplate? EditTemplate
{
get { return (ITemplate?)GetValue(EditTemplateProperty); }
set { SetValue(EditTemplateProperty, value); }
}
public static readonly DotvvmProperty EditTemplateProperty
= DotvvmProperty.Register<ITemplate?, GridViewTemplateColumn>(c => c.EditTemplate, null);


public override void CreateControls(IDotvvmRequestContext context, DotvvmControl container)
{
ContentTemplate.NotNull("GridViewTemplateColumn.ContentTemplate must be set")
.BuildContent(context, container);
}

public override void CreateEditControls(IDotvvmRequestContext context, DotvvmControl container)
{
if (EditTemplate == null) throw new DotvvmControlException(this, "EditTemplate must be set when editing is allowed in a GridView.");
EditTemplate.BuildContent(context, container);
}
}
}
6 changes: 6 additions & 0 deletions src/Framework/Framework/Controls/GridViewTextColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ public override void CreateControls(IDotvvmRequestContext context, DotvvmControl

public override void CreateEditControls(IDotvvmRequestContext context, DotvvmControl container)
{
if (EditTemplate is {} editTemplate)
{
editTemplate.BuildContent(context, container);
return;
}

var textBox = new TextBox();
textBox.FormatString = FormatString;

Expand Down
14 changes: 11 additions & 3 deletions src/Tests/ControlTests/DynamicDataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,19 @@ public async Task DynamicEntityWithVisibleEnabledFields(string viewName, string
",
user: new ClaimsPrincipal(user),
fileName: $"{nameof(DynamicEntityWithVisibleEnabledFields)}-{viewName}-{userRoleName}-{isAuthenticated}"
check.CheckString(r.FormattedHtml, $"{viewName}-{userRoleName}-{isAuthenticated}", fileExtension: "html");
}
[TestMethod]
public async Task BasicDynamicGrid()
{
var r = await cth.RunPage(typeof(BasicTestViewModel), @"
<dot:GridView DataSource={value: List}>
<dd:DynamicColumns />
</dot:GridView>
"
);

CollectionAssert.AreEqual(new WrappedHtmlControl2[0], r.View.GetAllDescendants().OfType<WrappedHtmlControl2>().ToArray());

check.CheckString(r.FormattedHtml, $"{viewName}-{userRoleName}-{isAuthenticated}", fileExtension: "html");
check.CheckString(r.FormattedHtml, fileExtension: "html");
}

public class SimpleEntity
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<html>
<head></head>
<body>

<!-- ko if: List()?.length -->
<table data-bind="dotvvm-gridviewdataset: {'mapping':{},'dataSet':List()}">
<thead>
<tr>
<th>
<span></span>
</th>
<th class="">
<span>Id</span>
</th>
<th class="">
<span>Name</span>
</th>
<th class="">
<span>Email</span>
</th>
<th class="">
<span>Sometime</span>
</th>
</tr>
</thead>
<tbody data-bind="foreach: List">
<tr>
<td></td>
<td>
<span data-bind="text: Id"></span>
</td>
<td>
<span data-bind="text: Name"></span>
</td>
<td>
<span data-bind="text: Email"></span>
</td>
<td>
<span data-bind="text: dotvvm.globalize.formatString(&quot;&quot;, Sometime)"></span>
</td>
</tr>
</tbody>
</table>
<!-- /ko -->
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,10 @@
"type": "System.Collections.Generic.List`1[[DotVVM.Framework.Controls.Decorator, DotVVM.Framework, Version=***, Culture=neutral, PublicKeyToken=23f3607db32275da]]",
"mappingMode": "InnerElement"
},
"EditTemplate": {
"type": "DotVVM.Framework.Controls.ITemplate, DotVVM.Framework",
"mappingMode": "InnerElement"
},
"FilterTemplate": {
"type": "DotVVM.Framework.Controls.ITemplate, DotVVM.Framework",
"dataContextManipulation": {
Expand Down Expand Up @@ -584,10 +588,6 @@
"type": "DotVVM.Framework.Controls.ITemplate, DotVVM.Framework",
"mappingMode": "InnerElement",
"required": true
},
"EditTemplate": {
"type": "DotVVM.Framework.Controls.ITemplate, DotVVM.Framework",
"mappingMode": "InnerElement"
}
},
"DotVVM.Framework.Controls.GridViewTextColumn": {
Expand Down

0 comments on commit d2a06b1

Please sign in to comment.