Skip to content

Commit 45580b6

Browse files
authored
DataBinder MVP Implementation #85 (#95)
* Completed initial implementation of Eval and DataBinder (#85) * Added DataBinder doc
1 parent 4bb7df5 commit 45580b6

File tree

19 files changed

+463
-105
lines changed

19 files changed

+463
-105
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
*.ncrunchproject
1212
*.ncrunchsolution
1313

14+
# Project XML documentation
15+
BlazorWebFormsComponents.xml
16+
1417
# User-specific files (MonoDevelop/Xamarin Studio)
1518
*.userprefs
1619
.ionide/

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ There are a significant number of controls in ASP.NET Web Forms, and we will foc
5050

5151
We will NOT be converting any DataSource objects, Wizard components, skins or themes. Once this first collection of 23 controls is written, we can consider additional features like modern tag formatting.
5252

53+
## Utility Features
54+
55+
There are a handful of features that augment the ASP<span></span>.NET development experience that are made available as part of this project in order to support migration efforts. These features include:
56+
57+
- [DataBinder](docs/Databinder.md)
58+
5359
## Compiling the project
5460

5561
There are three different types of .NET projects in this repository: .NET Framework, .NET Core, and .NET Standard. The sample projects are in the `/samples` folder, while the unit test project is next to the component library in the `/src` folder. From the root of the repository, you should be able to execute:

docs/Databinder.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# DataBinder
2+
3+
In Web Forms applications, there is a somewhat standard approach of formatting and placing data in controls by using the DataBinder object. The DataBinder would be used in ItemTemplate, AlternatingItemTemplate, and other control templates to indicate where data would be formatted and placed. [Microsoft's original documentation about the DataBinder](https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.databinder?view=netframework-4.8) are available.
4+
5+
## ASP<span></span>.NET Syntax, Support and Migration
6+
7+
There are several common techniques that the DataBinder was used and various levels of support are provided:
8+
9+
| Web Forms Syntax | Description | Blazor Support |
10+
| --- | --- | --- |
11+
| `DataBinder.Eval(Container.DataItem, "PropertyName")` | Output the `PropertyName` of the current item | *Fully Supported for Container.DataItem* |
12+
| `Eval("PropertyName")` | Output the `PropertyName` of the current item | *Fully Supported when using static* |
13+
| `DataBinder.Eval(Container.DataItem, "PropertyName", "FormatString")` | Output the formatted value of `PropertyName` of the current item with the `FormatString` | *Fully Supported for Container.DataItem* |
14+
| `Eval("PropertyName", "FormatString")` | Output the formatted value of `PropertyName` of the current item with the `FormatString` | *Fully Supported when using static* |
15+
| `DataBinder.GetDataItem` | Output the item currently operated on | Not supported: Replace with calls to `@context` |
16+
| `DataBinder.GetPropertyValue(Container.DataItem, "PropertyName")` | Get the property requested as an object for further handling | Only supported when passing in `@context` for the first argument. **Recommendation**: replace with `@context.PropertyName` to directly access the property in a strongly-typed manner |
17+
18+
[Back to top](#DataBinder)
19+
20+
## Support and Migration
21+
22+
The DataBinder is not recommended by Microsoft in Web Forms for use in high-performance applications due to the amount of reflection used to output and format content. Similarly, we do not recommend long-term use of the DataBinder and have marked it with an `Obsolete` flag indicating that there are methods to easily migrate syntax to be more Razor-performance-friendly.
23+
24+
[Back to top](#DataBinder)
25+
26+
### Usage
27+
28+
To migrate your Web Forms control that is referencing the DataBinder to Blazor, start with syntax similar to the following:
29+
30+
```html
31+
<ItemTemplate>
32+
<li><%#: DataBinder.Eval(Container.DataItem, "Price", "{0:C}") %></li>
33+
</ItemTemplate>
34+
```
35+
36+
All of the databound components in this library support DataBinder syntax and can easily be converted by replacing the angle brackets with razor notation like the following:
37+
38+
```html
39+
<ItemTemplate>
40+
<li>@DataBinder.Eval(Container.DataItem, "Price", "{0:C}")</li>
41+
</ItemTemplate>
42+
```
43+
44+
That's a VERY simple conversion and its clear how we can continue to deliver the same feature and formatting using Blazor. You can even shorten the syntax to use the simple `Eval` keyword and get the same effect. Just include a `@using static` keyword near the top of your Blazor page with this syntax and you can using the shortened format of `Eval`.
45+
46+
```html
47+
@using static BlazorWebFormsComponents.DataBinder
48+
...
49+
<ItemTemplate>
50+
<li>@Eval("Price", "{0:C}")</li>
51+
</ItemTemplate>
52+
```
53+
54+
*Note:* Your Blazor application will emit compiler warnings while you continue to use the DataBinder.
55+
56+
[Back to top](#DataBinder)
57+
58+
### Moving On
59+
60+
Moving on from the DataBinder to a more performant and simple Razor syntax is quite easy using an `ItemContext` and referencing the iterated item directly. This approach has the additional benefit of providing type-safety and compiler checking on the content of your Blazor pages.
61+
62+
Our `Eval("Price")` statement above is further simplified into:
63+
64+
```html
65+
<Repeater Context="Item">
66+
...
67+
<ItemTemplate>
68+
<li>@Item.Price.ToString("C")</li>
69+
</ItemTemplate>
70+
...
71+
</Repeater>
72+
```
73+
74+
[Back to top](#DataBinder)

docs/Migration/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Namespaces and tag-prefixes are gone. You can do a Find and Replace on asp: and
3838

3939
- A simple initial site migration
4040
- Intertwined code
41+
- [DataBinder](Databinder.md)
4142
- Model-Binding
4243
- .NET Standard to the rescue!
4344
- Other considerations

samples/AfterBlazorServerSide/Pages/ControlSamples/ListView/Index.razor

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
@page "/ControlSamples/ListView"
2+
@using static BlazorWebFormsComponents.DataBinder
3+
@using SharedSampleObjects.Models
24

35
<h2>ListView Component homepage</h2>
46

@@ -24,9 +26,9 @@
2426
<AlternatingItemTemplate>
2527
<tr class="table-dark">
2628
<td>@Item.Id</td>
27-
<td>@Item.Name</td>
28-
<td>@Item.Price.ToString("c")</td>
29-
<td>@Item.LastUpdate.ToString("d")</td>
29+
<td>@Eval("Name")</td>
30+
<td>@Eval("Price", "{0:C}")</td>
31+
<td>@Eval("LastUpdate", "{0:d}")</td>
3032
</tr>
3133
</AlternatingItemTemplate>
3234
<ItemTemplate>

samples/BeforeWebForms/ControlSamples/ListView/Default.aspx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
</LayoutTemplate>
3232
<AlternatingItemTemplate>
3333
<tr class="table-dark">
34-
<td><%# Item.Id %></td>
34+
<td><%# DataBinder.Eval(Container.DataItem, "Id", "{0:C}") %></td>
3535
<td><%# Item.Name %></td>
3636
<td><%# Item.Price.ToString("c") %></td>
3737
<td><%# Item.LastUpdate.ToString("d") %></td>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
@inherits TestComponentBase
2+
@using static BlazorWebFormsComponents.Enums.RepeatLayout
3+
@using static BlazorWebFormsComponents.Enums.DataListEnum
4+
5+
6+
<Fixture Test="FirstTest">
7+
<ComponentUnderTest>
8+
<DataList Items="Widget.SimpleWidgetList"
9+
ItemType="Widget"
10+
RepeatLayout="Flow">
11+
<HeaderTemplate>My Widget List</HeaderTemplate>
12+
<ItemTemplate>@DataBinder.Eval("Name")</ItemTemplate>
13+
</DataList>
14+
</ComponentUnderTest>
15+
</Fixture>
16+
17+
18+
@code {
19+
20+
void FirstTest()
21+
{
22+
23+
var cut = GetComponentUnderTest();
24+
25+
cut.FindAll("span").Count().ShouldBe(5);
26+
cut.FindAll("span").Skip(1).First().TextContent.ShouldBe("My Widget List");
27+
28+
cut.Find("span").HasAttribute("title").ShouldBeFalse();
29+
30+
}
31+
32+
33+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@inherits TestComponentBase
2+
@using static BlazorWebFormsComponents.DataBinder
3+
4+
<Fixture Test="FirstTest">
5+
<ComponentUnderTest>
6+
<ListView Items="Widget.SimpleWidgetList"
7+
ItemType="Widget">
8+
<ItemTemplate><span>@Eval("Name")</span><span>@Eval("Price", "{0:C}")</span></ItemTemplate>
9+
</ListView>
10+
</ComponentUnderTest>
11+
</Fixture>
12+
13+
14+
@code {
15+
16+
void FirstTest()
17+
{
18+
19+
var cut = GetComponentUnderTest();
20+
Console.WriteLine(cut.Markup);
21+
22+
var spans = cut.FindAll("span");
23+
24+
var theWidget = Widget.SimpleWidgetList[0];
25+
26+
spans[0].TextContent.ShouldBe(theWidget.Name);
27+
spans[1].TextContent.ShouldBe(theWidget.Price.ToString("C"));
28+
29+
}
30+
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@inherits TestComponentBase
2+
3+
<Fixture Test="FirstTest">
4+
<ComponentUnderTest>
5+
<Repeater Items="Widget.SimpleWidgetList"
6+
ItemType="Widget">
7+
<ItemTemplate><span>@DataBinder.Eval("Name")</span></ItemTemplate>
8+
<SeparatorTemplate><hr/></SeparatorTemplate>
9+
</Repeater>
10+
</ComponentUnderTest>
11+
</Fixture>
12+
13+
14+
@code {
15+
16+
void FirstTest()
17+
{
18+
19+
var cut = GetComponentUnderTest();
20+
21+
cut.FindAll("span").Count().ShouldBe(3);
22+
cut.FindAll("hr").Count().ShouldBe(3);
23+
24+
}
25+
26+
27+
}

src/BlazorWebFormsComponents/BaseDataBindingComponent.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public abstract class BaseDataBindingComponent : BaseWebFormsComponent
1919

2020
#endregion
2121

22-
2322
}
2423

2524
}

0 commit comments

Comments
 (0)