| Comments

I was finally getting around to updating a little internal app I had that showed some various data that some groups use to triage bugs.  As you can imagine it is a classic “table of stuff” type dataset with various titles, numbers, IDs, etc. as visible columns.  I had built it using Blazor server and wanted to update it a bit.  In doing some of the updates I came across a preferred visual I liked for the grid view and applied the CASE methodology to implement that.  Oh you don’t know what CASE methodology is?  Copy Always, Steal Everything.  In this case the culprit was Immo on my team.  I know right? I couldn’t believe it either that he had something I wanted to take from a UI standpoint.  I digress…

In the end I wanted to provide a rendered table UI quickly and provide a global filter:

Picture of a filtered data table

Styling the table

I copied what I needed and realized I could be using the Bootstrap styles/tables in my use case.  Immo was using just <divs> but I own this t-shirt, so I went with <table> and plus, I like that Bootsrap had a nice example for me.  Off I went and changed my iteration loop. to a nice beautiful striped table.  Here’s what it looked like in the styling initially:

<table class="table table-striped">
    <thead class="thead-light">
        <tr>
            <th scope="col">Date</th>
            <th scope="col">Temp. (C)</th>
            <th scope="col">Temp. (F)</th>
            <th scope="col">Summary</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var forecast in forecasts)
        {
            <tr>
                <td>@forecast.Date.ToShortDateString()</td>
                <td>@forecast.TemperatureC</td>
                <td>@forecast.TemperatureF</td>
                <td>@forecast.Summary</td>
            </tr>
        }
    </tbody>
</table>

Adding a filter

Now I wanted to add some filtering capabilities more globally.  Awesome “boostrap filtering” searching I went and landed on this simple tutorial.  Wow! a few lines of JavaScript, sweet, done.  Or so I thought.  As someone who hasn’t done a lot of SPA web app development I was quickly hit with the reality that once you choose a SPA framework (like Angular, React, Vue, Blazor) that you are essentially buying in to the whole philosophy and that for the most part jQuery-style DOM manipulations will no longer be at your fingertips as easily.  Sigh, off to some teammates I went to complain and look for their sympathy.  Narrator: they had no sympathy.

After another quick chat with Immo who had implementing the same thing he smacked me around and said in the most polite German accent “Why don’t you just use C# idiot?”  Okay, I added the idiot part, but I felt like he was typing it and then deleted that part before hitting send.  Knowing that Blazor renders everything and then re-renders when things change I just had to implement some checking logic in the foreach loop.  First I needed to add the filter input field:

<div class="form-group">
    <input class="form-control" type="text" placeholder="Filter..." 
           @bind="Filter" 
           @bind:event="oninput">
</div>
<table class="table table-striped">
...
</table>

Observe that I added an @bind and @bind:event attributes that enable me to wire these up to properties and client-side events.  So I’m telling it to bind the input to my ‘Field’ property and do this on ‘oninput’ (basically when the keys are typed in the input box).  Now off to implement the property.  I’m doing this simply in the @code block of the page itself:

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }

    public string Filter { get; set; }
}

And then I needed to implement the logic for filtering.  I’m doing a global filter so that I can control whatever fields I want searched/filtered.  I basically have the IsVisible function called each iteration and deciding if it should be rendered.  For this sample I’m looking at if the summary contains the filter text or if the celsius or farenheit temperatures start with the digits being entered.  I actually have access to the item model so I could even filter off of something not visible if I wanted (which would be weird for your users, so you probably shouldn’t do that).  Here’s what I implemented:

public bool IsVisible(WeatherForecast forecast)
{
    if (string.IsNullOrEmpty(Filter))
        return true;

    if (forecast.Summary.Contains(Filter, StringComparison.OrdinalIgnoreCase))
        return true;

    if (forecast.TemperatureC.ToString().StartsWith(Filter) || forecast.TemperatureF.ToString().StartsWith(Filter))
        return true;

    return false;
}

Implementing the filter

Once I had the parameter, input event, and the logic, now I just needed to implement that in my loop.  A simple change to the foreach loop does the trick:

<table class="table table-striped">
    <thead class="thead-light">
        <tr>
            <th scope="col">Date</th>
            <th scope="col">Temp. (C)</th>
            <th scope="col">Temp. (F)</th>
            <th scope="col">Summary</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var forecast in forecasts)
        {
            if (!IsVisible(forecast))
                continue;
            <tr>
                <td>@forecast.Date.ToShortDateString()</td>
                <td>@forecast.TemperatureC</td>
                <td>@forecast.TemperatureF</td>
                <td>@forecast.Summary</td>
            </tr>
        }
    </tbody>
</table>

Now when I type it automatically filters the view based on input.  Like a thing of beauty.  Here it is in action:

Animation of table being filtered

Pretty awesome.  While I’ve used the default template here to show this example, this technique can of course be applied to your logic.  I’ve put this in a repo to look at more detailed (this is running .NET 5-rc2 bits) at timheuer/BlazorFilteringWithBootstrap.

More advanced filtering

This was a simple use case and worked fine for me.  But there are more advanced use-cases, better user experiences to provide more logic to the filter (i.e., define your own contains versus equals, etc.) and that’s where 3rd party components come in.  There are a lot that provide built-in grids that have this capability.  Here are just a few:

Just to name a few popular ones.  These are all great components authored by proven vendors in the .NET component space.  These are way richer than simple filtering and provide a plethora of capabilities on top of grid-based rendering of large sets of data.  I recommend if you have those needs you check them out.

I’m enjoying my own journey writing Blazor apps and hope you found this dumb little sample useful.  If not, that’s cool.  I mainly am bookmarking here for my own use later when I forget and need to search…maybe I’ll find it back on my own site.

Hope this helps!

| Comments

Recently I embarked on porting the TagLib# library to a Portable Class Library (PCL).  In my efforts I noted some frustration I had of the “convert and compile” flow to find issues.  Well, turns out I didn’t have to do that much pain as pointed out by Daniel in the comments!  The .NET team has released a tool to help out us developers called the API Portability Analyzer (currently in Alpha).  This tool basically looks at any existing .NET assembly and gives you a report to help you see where the APIs used are supported in the various .NET profiles available.

The tool is a single command-line exe and is as simple as launching:

ApiPort.exe path-to-your-assembly-file.dll

I recommend putting this in your path somewhere so you don’t have to remember the full path to launch.  The output from the console tells you very little and only really about what you it is doing:

Microsoft (R) API Portability Analyzer version 1.0 (alpha)
Copyright (C) Microsoft Corporation. All rights reserved.

To learn more about how this tool works, including the data we are collecting, go here - http://go.microsoft.com/fwlink/?LinkId=397652

Identifying assemblies to scan. Done in 0.01s.
Detecting assembly references. Processed 1/1 files.Done in 0.23s.
Sending data to service. Done in 2.88s.
Computing report. Processed 508 items.Done in 0.02s.
Writing report. Done in 0.17s.

Replaced output file "c:\ApiPortAnalysis.xlsx"

You may notice that the tool says ‘sending’ and yes, it is communicating with a public service.  The team notes this in the download:

NOTE: During the process of identifying the .NET APIs used by a binary Microsoft collects the list of .NET APIs used by the user submitted binaries. Microsoft also collects the names of various user created APIs. The tool does not collect the binary code, only names of APIs are collected. Microsoft will also collect assembly information such as assembly references for the binary & the Target Framework Moniker (TFM).

The real value is in the output data conveniently formatted into a pre-filterable Excel document.  The process was fairly fast for me, but I suspect might take longer for larger libraries (duh).  An example of the output is like the one here directly showing the TagLib# data that I used above.

If you read my previous post you will see that the areas I had frustrations about are clearly identified in the Unsupported columns for my target platform.  The tool attempts to recommend some alternatives when it can.  I can imagine this gets better over time as the recommendations for TagLib# were only two, whereas it should have provided recommendations for XmlDocument/XmlElement/etc. to the XLINQ equivalent areas.

In the end though, this is a helpful tool for those looking to convert.  I wish I had known about it in advance, but now that I know it is in my toolbox and my PATH!

Hope this helps!

| Comments

Today Visual Studio 2008 has released SP1 which not only brings some fixes, but also is an added value service pack, bringing some new functionality to WPF as well as enabling a “client” deployment pack of the .NET framework so that those deploying .NET framework with your client applications can have a much smaller footprint (by about 80+%).

With the release of SP1 for Visual Studio 2008 today, the Silverlight team has also updated their tools for Silverlight 2 Beta 2.  Read again: a tools update for Silverlight 2 Beta 2 is needed and available for you.  If you install Visual Studio 2008 SP1 and your Silverlight projects aren’t working anymore, that’s why!

Here’s the download links:

Please note that this update to the Silverlight tools can be used for Visual Studio 2008 RTM as well as the just-released SP1, but NOT for VS 2008 SP1 beta.  Yeah, if that’s mind blurring, let’s boil it down:

Do you want to install VS2008 SP1 (release) and still work with Silverlight 2 applications?  If yes, download the updated Silverlight tools and install after you install VS208 SP1.

I hope that makes your decision easier.  Oh and if you installed SP1 Beta at any time, check out this post from Heath.

| Comments

finally want to try out that feature to debug your apps and step into System.Web.dll?  it has arrived.

shawn burke has all the blow-by-blow details on setting it up.

| Comments

as some of you know i've been silent for a lot of december due to a series of unfortunate incidents.  the worst of which was a phone call that my wife was being air-evac'd from our neighborhood.  yeah, not a good call.  she was hit by a car while cycling.  she is getting better now after a surgery and physical therapy.  not back 100%, not even 70% but getting better daily.  in the midst of all of this, i've been battling kidney stones.  anyone who has had these knows that pain killers are your best friend right now.  i've had 3 over the month of december and have 1 more still in the track...and it sucks going day-to-day not knowing if it will be a painful day...so if you see me bust out the ziplock with two pills in it...you know it's a bad day :-).

anyhow, i came home today from going into the office and my wife asked me what the 'nm .net user group' was.  i gave her that 'why are you snooping on me and how did you figure out my email password' look.  then she handed me this card:

PIC-0001.jpg

wow.  way cool.  the folks of the new mexico .net user group community sent my wife and me a card.  some well wishes to my family to get better.  i thought that was a very thoughtful gesture on behalf of them and from my family a very sincere and humble 'thank you' goes out to you all.  we've been blessed with a lot fo local and distant friends and maybe i'll get around to posting some thoughts on being humble and accepting help...but i'll have to think of a geek twist on it ;-)

i've really enjoyed seeing the growth of the new mexico .net community over the past 2 years thanks in part to a lot of people.  i think they are even experiencing growing pains right now, which can be frustrating but is always a sign of success i believe.

so thanks again to the new mexico .net user group -- if you are a developer in new mexico, you need to be a part of this community.  it is growing and they are doing exciting things.  there are passionate people involved helping drive direction to serve the community...so get out there and be a part of it!