Loading indicator in Ag-Grid

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

Ag-Grid is a great data grid which supports React (amongst other frameworks). Here’s a couple of simple functions showing how to show and hide the loading indicator using the gridApi

showOverlay = () => {
  if (this.gridApi !== undefined) {
    this.gridApi.showLoadingOverlay();
  }
}

hideOverlay = () => {
  if (this.gridApi !== undefined) {
    this.gridApi.hideOverlay();
  }
}

File explorer extended search in Windows

File Explorer has (as we all know) a search box in the top right, ofcourse we can enter some text and File Explorer will search for filenames with that text and text within files, but there are more options to tailor our search.

See Common File Kinds.

Let’s look at some examples

File name search

If we prefix our search term with file: like this

file: MyFile
file:.sln

Then we only get search results for all files with the text as part of the filename or file extension.

File content search

If we prefix our search term with content: like this

content: SomeContent

Then we only get search results from within files (i.e. text search).

Kind

We can use the kind option along with file type, such as text, music etc. See Common File Kinds.

kind:text

The above list all text files.

Other file options

We can also use the following, other file options, for example finding

datemodified:lastweek
modified:lastweek
modified:05/10/2022
size:>500

The first two options are the same and list files modified last week. The size option lists files with a size larger than 500 bytes.

See also File Kind: Everything.

Boolean Operators

As you can see we can also use Boolean Operators.

XamDataGrid tips and tricks

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

The following is a general list of tips and tricks for working with the XamDataGrid. Primarily code/xaml which doesn’t require a full post of their own.

Enable/disable column sorting or change the way the sorting is applied

Simply set the LabelClickAction on the FieldSettings to “Nothing” to turn sorting off. You can also change the logic for sort in that you can set the sorting to single or multi field.

<igDP:XamDataGrid>
   <igDP:XamDataGrid.FieldSettings>
      <igDP:FieldSettings LabelClickAction="Nothing" />
   </igDP:XamDataGrid.FieldSettings>
</igDP:XamDataGrid>

Changing cell styles and more in code-behind

Sometimes our requirement is too dynamic for the declarative nature of XAML and/or may be difficult to handle via styles/triggers and converters so we need to write some code. The problem is getting at the cell object at the right time.

This is where the CellsInViewChanged event is useful, for example

private void CellsInViewChanged(object sender, CellsInViewChangedEventArgs e)
{
   foreach(var visibleDataBlock in e.CurrentCellsInView)
   {
      foreach(var record in visibleDataBlock.Records)
      {
         foreach(var field in visibleDataBlock.Fields)
         {
            var cellValuePresenter = CellValuePresenter.FromRecordAndField(record, field);
            // do something with the cell value presenter
         }
      }
   }
}

In the above code (which we seem to have to attach an event handler to, i.e. there’s no virtual method for deriving our own implementation from that I can see). We get a list of VisibleDataBlock items which we loop through to get the records and the fields. Using the CellValuePresenter.FromRecordAndField we can then get the CellValuePresenter where we can then change visual style directly, such as the cell background colour, we can make the cell’s editor readonly and so on.

How to stop a cell “appearing” to go into edit mode

We may set a cell’s editor to readonly but when the user clicks on the cell the cell changes colour as if switching to edit more and the caret is displayed, even though you cannot edit the field. A way to stop this happening is by overriding the OnEditModeStarting method in a subclassed grid control or intercepting the EditModeStarting event on the grid. For example

protected override void OnEditModeStarting(EditModeStartingEventArgs args)
{
   // required to stop the cell even entering edit mode
   var cvp = CellValuePresenter.FromCell(args.Cell);
   if (cvp != null)
   {
      args.Handled = args.Cancel = cvp.Editor.IsReadOnly;
   }
}

ASP.NET core and Ingress rules

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

You’ve implemented a service using ASP.NET deployed it to Kubernetes and all worked great, you then deploy a front end to use that service (as per the example in the Project Tye repo) again, all worked well. Whilst the Ingress mapped the path / to your front end services, the CSS an JS libs all worked fine, but then you change you Ingress route to (for example)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress
  namespace: default
spec:
  rules:
    - http:
        paths:
          - path: /frontend
            pathType: Prefix
            backend:
              service: 
                name: frontend
                port: 
                  number: 80

In the above, the rule for the path /frontend will run the frontend service. All looks good so you navigate to http://your-server-ip/frontend and, wait a moment. The front end and backend services are working, i.e. you see some HTML and you see results from the backend service but Edge/Chrome/whatever reports 404 of bootstrap and your CSS.

The simplest solution, but with the downside that you are putting knowledge of the deployment route into your front end service is to just add the following to Startup.cs

app.UsePathBase("/frontend");

Obviously if you’re using tye or your own environment configuration, you might prefer to get the “/frontend” string from the environment configuration instead of hard coding.

Alignment using string interpolation in C#

C#’s string interpolation supports alignment and format options

Alignment

Using the following syntax, {expression, alignment}, we can use negative alignment numbers for left-aligned expressions and positive numbers for right-aligned alignment. For example

var number = 123;
Console.WriteLine($"|{number,-10}|");
Console.WriteLine($"|{number,10}|");

This would produce the following

|123       |
|       123|

See also Alignment component.

Format String

We can use the following {expression, alignment:format} or {expression:format} syntax to add formatting, i.e.

var number = 123;
Console.WriteLine($"|{number, -10:F3}|");
Console.WriteLine($"|{number, 10:F3}|");

would produce the following

|123.000   |
|   123.000|

and

var number = 123;
Console.WriteLine($"|{number:F3}|");
Console.WriteLine($"|{number:F3}|");

would produce

|123.000|
|123.000|

See also Format string component.

Trying out Dapr

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

I’ve been messing around with microservices in one form or another. Once you start down this route (at least in a Microsoft world) you come across Dapr (Distributed Application Runtime). Let’s take a look at what it offers us.

To get started simple visit Getting started with Dapr and follow the steps to install and initialize Dapr, I’m going to reproduce the current steps here for completeness.

  • Install Dapr, I’m doing this on a Linux box hence using
    wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash
    
  • Verify the installation by running
    dapr
    
  • Initialize dapr by running
    dapr init
    

    this will download and set up components, which basically means it’s download and then run up openzipkin/zipkin, daprio/dapr and redis docker images, so now we can check those by running

    docker ps
    
  • Dapr creates a components directory, for Linix here $HOME/.dapr and for Windows here %USERPROFILE%\.dapr\

All installed, now what?

Dapr is a sidecar architecture which basically means it exposes HTTP and gRPC either via container or process. So applications do not need to reference Dapr’s runtime instead they use Dapr as a service. The sidecar pattern is classed as a cloud design pattern.

What Dapr’s done is given us some “standard” application combination, accessible via Dapr in an agnostic manner, i.e. via HTTP calls, we can run up an instance of Dapr using

dapr run --apo-id {your-app-id} --dapr-htt-port {the-port-to-access-dapr}

So for example dapr run –app-id myapp –dapr-http-port 3500 will run Dapr up on port 3500 with the app_id of myapp.

The output from the above command will show metrics running on (in my case) port 44333. We can access this from our browser.

By default, zipkin is running on port 9411 (just check docker ps) and can be accessed from your browser using http://{your-server-ip}:9411/zipkin/

As Redis is also running we can access it using the Redis CLI, for example

docker exec -it dapr_redis redis-cli

fetch, no-cors no custom context type

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

If you’re using the Javascript fetch api with mode set to ‘no-cors’ beware that this limits the set of headers you can use in your request. Specifically if you’re trying to interact with a server using application/json, the ‘no-cors’ will simply not apply that content-type.

See Using Fetch

In no-cors mode only the following are allowed

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type which can only take the following
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Creating a Visual Studio debug visualizer

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

A Visualizer is a feature where, if you run an app. and whilst debugging you put the mouse over a variable a little debugger popup appears. You have a drop down to display the value in the variable as XML, HTML etc.

  1. Create class lib project
  2. Add references to Microsoft.VisualStudio.DebuggerVisualizers.dll and System.Windows.Forms
using Microsoft.VisualStudio.DebuggerVisualizers;
using System.Windows.Forms;

[
    assembly: System.Diagnostics.DebuggerVisualizer(
        typeof(MyFirstVisualizer.DebuggerSide),
        typeof(VisualizerObjectSource),
        Target = typeof(System.String),
        Description = "My First Visualizer")
]
namespace MyFirstVisualizer
{
    public class DebuggerSide : DialogDebuggerVisualizer
    {
        protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
        {
            MessageBox.Show(objectProvider.GetObject().ToString());
        }

        public static void TestShowVisualizer(object objectToVisualize)
        {
            var visualizerHost = new VisualizerDevelopmentHost(objectToVisualize, typeof(DebuggerSide));
            visualizerHost.ShowVisualizer();
        }
    }
}

TestShowVisualizer allows us to test from a console app

  1. Create console app
  2. Add reference to Microsoft.VisualStudio.DebuggerVisualizers.dll and our project reference
class TestConsole
{
   static void Main(string[] args)
   {
      var myString = "Hello, World";
      DebuggerSide.TestShowVisualizer(myString);
   }
}

To install, copy to

{visual studio deployment folder};\Common7\Packages\Debugger\Visualizers

i.e. C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Packages\Debugger\Visualizers

and

MyDocuments\Visual Studio 2015\Visualizers

WPF Validation methods

How do we handle validation in WPF ?

Before we begin…

Let’s start by looking at the view model we’re going to work on and write our validation code for – this is a very simple model with a single property “Number” which could ofcourse represent anything you like.

public class NumberViewModel : INotifyPropertyChanged
{
   // standard implementation of INotifyPropertyChanged removed 
   private int number;

   public int Number
   {
      get { return number; }
      set
      {
         if (number != value)
         {
            number = value;
            OnPropertyChanged("Number");
         }
      }
   }
}

You can assume that OnPropertyChanged fires the INotifyPropertyChanged.PropertyChanged event, but I’ve removed the implementation for brevity.

We’ll be equally simple with our UI, which has the following XAML

<TextBox Text="{Binding Number}" />

Good old IDataErrorInfo

So if you’ve used IDataErrorInfo in WinForms, this will be very familiar to you. We can simple implement the IDataErrorInfo interface in our NumberViewModel and add something like the following

string IDataErrorInfo.Error
{
   get { return null; }
}

string IDataErrorInfo.this[string columnName]
{
   get
   {
      if (columnName == "Number")
      {
         if (number < 0)
            return "Number must be greater or equal to 0";
      }
      return null;
   }
}

To get the WPF binding to actually interact with the IDataErrorInfo we need to change the XAML to look like this

<TextBox Text="{Binding Number, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />

In the above our IDataErrorInfo.this indexer will be called each time the property changes, at which time we can handle the validation either within the view model or ofcourse via some other validation rule class.

ValidationRule validation

An alternative to the IDataErrorInfo route for validation are ValidationRules. A ValidateRule implementation of the previous validator is listed below

public class PostiveValidationRule : ValidationRule
{
   public override ValidationResult Validate(object value, CultureInfo cultureInfo)
   {
      int result;
      if (value != null && Int32.TryParse(value.ToString(), out result))
      {
         if (result < 0)
            return new ValidationResult(
               false, "Number must be greater or equal to 0");
      }
      return ValidationResult.ValidResult;
   }
}

To use the above rule in XAML we write the following

<TextBox>
   <TextBox.Text>
      <Binding Path="Number" 
            ValidatesOnDataErrors="True" 
            UpdateSourceTrigger="PropertyChanged">
         <Binding.ValidationRules>
            <validators:PostiveValidationRule />
         </Binding.ValidationRules>
      </Binding>
   </TextBox.Text>
</TextBox>

The ValidationRules (as the pluralism suggests) can have multiple rules listed.

INotifyDataErrorInfo

.NET 4.5 included the INotifyDataErrorInfo. This allows us to validate in a more asynchronous way in that we can raise the ErrorsChanged event when we have errors and report them so that the binding engine can then call the GetErrors method to get the list of errors.

BindingGroup

The previously highlighted validation methods tend to be aimed more at a specific view model, but what if our view is made up of multiple view models and we want to validate across them all. Then we can look to use the BindingGroup.

The BindingGroup creates a relationship between multiple bindings, which can be validated and updated together.

To put it another way, the BindingGroup allows us to validate a group of bindings at the same time. Our sample only has a view model but if we had multiple view models it could validate all the items that make up a BindingGroup. Let’s look at how we could create a BindingGroup.

<StackPanel>
   <StackPanel.BindingGroup>
     <BindingGroup Name="ValidDataGroup">
        <BindingGroup.ValidationRules>
           <validators:ValidDataValidationRule />
        </BindingGroup.ValidationRules>
     </BindingGroup>
   </StackPanel.BindingGroup>
   <TextBox Text="{Binding Text, ValidatesOnDataErrors=True, BindingGroupName=ValidDataGroup}" />

We give the BindingGroup a name and then we can assign this name to the various bindings – in this example we don’t actually need to use the group name on the textbox as it will be used within the validation, but hopefully you can see how the syntax would look.

Now let’s take a look at the ValidDataValidationRule code

public class ValidDataValidationRule : ValidationRule
{
   public override ValidationResult Validate(object value, CultureInfo cultureInfo)
   {
      var bindingGroup = (BindingGroup)value;
      if (bindingGroup != null)
      {
         var numberViewModel = bindingGroup.Items[0] as NumberViewModel;
         if (numberViewModel != null)
         {
            if (numberViewModel.Number < 0)
            {
               return new ValidationResult(
                  false, 
                  "Number must be greater or equal to 0");
            }
         } 
      }
      return ValidationResult.ValidResult;
   }		
}

The Items collection will contain the various groups that have been assigned the BindingGroup name and then we can validate across all the data contexts.

Unfortunately, this doesn’t just happen magically. Instead, we need to invoke it. If we give the name DataElement to the StackPanel and for the sake of simplicity we add a button with a Click handler, we can then call the BindingGroup’s CommitEdit method to force validation, i.e.

DataElement.BindingGroup.CommitEdit();

Note: The default style is to draw a read line around the control which fails validation, if you’ve placed the StackPanel as the top level Window you might need to add a margin to see the red border.

ValidationStep

On both the BindingGroup and ValidationRule we can set the ValidationStep property. This allows us to tell the binding mechanism at what stage it should invoke the validation rule.

This can be set to one of four values

CommittedValue: Runs the ValidationRule after the value has been committed to the source.
ConvertedProposedValue: Runs the Validation rule after a value is converetd.
RawProposedValue: Runs the validation before any conversion occurs.
UpdatedValue: Runs the ValidationRule after the source is updated.

Note: The above definitions were taken from ValidationStep Enumeration

Data annotations

Finally, let’s take a look at data annotations or more specifically validation attributes that are part of the System.ComplonentMode.DataAnnotations namespace.

With the data annotations we can apply attributes to a class or its members which denote the validation rules to be used. For example

public class ValidationModel
{
   [Required(ErrorMessage = "First name is a required field")]
   public string FirstName { get; set; }
}

In this example we’ve removed the get/set actual implementation, for brevity.

Now this code requires use to write code to validation the property, for example in our setter we might have code like this

var validationContext = new ValidationContext(this, null, null);
validationContext.MemberName = nameof(FirstName);
Validator.ValidateProperty(value, validationContext);

Enhancing the user interface

So far, I’ve not done anything to make the user experience any better regarding validation, i.e. you will only see a red border around our text box, but this doesn’t really help the user identify what’s gone wrong, so now let’s look at how we might change our UI to better reflect the validation failures.

Ofcourse, we’ve been busy creating error messages, but so far not shown them in the UI, so we could use something like the following

<TextBox Text="{Binding Number, 
      UpdateSourceTrigger=PropertyChanged, 
      ValidatesOnDataErrors=True}">
   <Validation.ErrorTemplate>
      <ControlTemplate>
         <StackPanel>
            <AdornedElementPlaceholder />
            <TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red"/>
         </StackPanel>
      </ControlTemplate>
   </Validation.ErrorTemplate>
</TextBox>

This will display the first error message just beneath the TextBox.

Another alternative is to style the text box with a trigger against the Validation.HasError property

<Style TargetType="{x:Type TextBox}">
   <Style.Triggers>
      <Trigger Property="Validation.HasError" Value="True">
         <Setter Property="Background" Value="Red" />
          <Setter Property="ToolTip"
             Value="{Binding RelativeSource={x:Static RelativeSource.Self},
             Path=(Validation.Errors)[0].ErrorContent}"/>
      </Trigger>
   </Style.Triggers>
</Style>

References

Data validation in WPF
Using BindingGroups For Greater Control Over Input Validation
BindingGroups For Total View Validation
WPF 3.5 SP1 Feature: BindingGroups with Item-level Validation
Validation in Windows Presentation Foundation

Assembly Redirects of Strong-Named Assemblies

It’s unfortunately all too often recently that I’ve need to redirect assemblies, so I thought I’d write a quick post on the subject.

Occasionally you may have a situation where one library (let’s call it Lib1) you’re using in .NET relies on a specific version of a another, strong-named, library (let’s call it Lib2). Then you go and update the library Lib2 to a newer version and things break. Lib1 expects a specific version of Lib2 and we’re not supplying it.

Simple open/add your App.config file – we then add something like this

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="Lib2" publicKeyToken="Lib2-PublicToken" culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-1.0.0.0" newVersion="2.0.0.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Obviously you replace Lib2 with the assembly that your code is dependent upon, you’ll also need to supply the publicKeyToken. The oldVersion is a range of versions from 0.0.0.0 to 1.0.0.0 in this case, meaning anything that required this assembly version 0 to 1 should now use version 2 (2.0.0.0).

When adding further assembly redirects we of just supply further dependentAssembly elements.

To find the publicKeyToken we can use the Strong Name utility (sn.exe) which can be found here (for example)

"%ProgramFiles%\\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\sn.exe" -T <assemblyName>

We can also find such information via the likes of ILSpy, by clicking on the assembly and in the right hand pane we’ll have information such as

// Microsoft.VisualC, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Further Reading

Strong-Named Assemblies
Redirecting Assembly Versions