Monthly Archives: October 2022

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

Computational Expressions, the “standard” methods

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.

So in a previous post I looked at my first attempt at creating a computational expression in F#. By anyone’s level this was basic. So I figured it was time to look at all the available “standard” methods available for a computational expression. By “standard” I means those which are implciitly recognized by F# as opposed to creating custom methods.

See Computation Expressions (F#) for more info.

There are plenty of posts on this subject from Microsoft or F# for fun or profit, so why am I writing yet another post – basically just to give my perspective and to help me remember this stuff.

Let’s start with the basics, we have a type SampleBuilder defined as

type SampleBuilder() =
   // our code will be filled is as required 
   // but an example might have just the following
   member this.Bind(m, f) = f m

We shall use the builder thus

let builder = SampleBuilder()

builder {
   // expressions, such as 
   let x = 100
}

and now to the various builder methods…

Bind

let! x = 100

// translates to

builder.Bind(100, (fun x -> expression))

So as can be seen, in essence the order of the arguments is reversed. So if we were to simply duplicate the way let binding works but in a computational expression we’d write something like

member this.Bind(m, f) = 
   f m

Return and ReturnFrom

At the time of writing this, I’m a little confused as to the difference between Return and ReturnFrom. Computation expressions and wrapper types states that the Return returns a wrapped type whilst ReturnFrom returns an unwrapped type. However it is seems it’s possible to pretty much return whatever I like as shown below

member this.Return(x) = x

member this.ReturnFrom(x) = x

Return is called when we have a return in the computation expression, i.e.

builder {
   return 100
} |> printfn "%A"

and ReturnFrom is used when return! exists, i.e.

builder {
   return! 100
} |> printfn "%A"

One slightly odd thing if you’re used to C# or the likes is that we can have multiple return and/or return! in a computational expression as per

builder {
   return 100
   return! 100
} |> printfn "%A"

As per multiple yield statements, we need a Combine method implemented in our builder to combine the return values. A return does not mean the rest of the computational expression is not executed, it means that the return values are combined to produce a value at the end of the workflow. So for example

builder {
   printfn "First"
   return 100
   printfn "Second"
   return 100
} |> printfn "%A"

Assuming our Return method and Combine are as simple as the following

member this.Return(x) = 
   printfn "Return"
   x

member this.Combine(a, b) = a + b

Then our output will look like the following

First
Return
Second
Return
200

In other words, the first printfn (actually the Delay builder method is called for each printfn) is called then the Return method, then the second printfn then the second Return, then the Combine is called. In this case Combine simply adds the return values together to produce the output of the workflow.

Combine

The combine method combines multiple values – so for example if you had something like the following

builder {
   yield 100
   yield 200
} |> printfn "%A"

without a combine method you’ll get the following compiler error This control construct may only be used if the computation expression builder defines a ‘Combine’ method. Simple enough to see the problem here. So we cannot yield more than once unless we implement a combine method. Here’s an example which implements the combine by creating a list and combining elements into a new list

member this.Combine(a, b) = a @ b

If we now compile this code we’ll get another error, “This control construct may only be used if the computation expression builder defines a ‘Delay’ method”. So we need to implement a Delay method. See the example listed for Delay below…

Delay

The Delay method allows the builder to delay the evaluation of a computational expression until it’s required. For example if we yield multiple times within a computational expression the idea is to combine the yields until we’re ready to invoke something.

The example above creates a list of the yields and then in the Delay we might want to do something with those combined yields. In this example below we’ll simply use the following code

member this.Delay(f) = f()

which essentially just invokes the function passed to the delay.

Run

Whilst the Delay method is used to delay evaluation, the Run method is mean’t to use the delayed expression, i.e. it might be to run something or the likes. An example which simply turns the list created by the combine into an array instead

member this.Run(f) = Array.ofList f

this is obviously a rather simplistic example, had our builder been creating the data for a web service call, for example, possibly run would make the call for us.

For

I again must point anybody reading this section to the excellent post Implementing a builder: The rest of the standard methods where an implementation of the For method is describe, for simplicity I’ll recreate it here

member this.For(sequence:seq<_>, body) =
   this.Using(sequence.GetEnumerator(),fun enum -> 
      this.While(enum.MoveNext, 
         this.Delay(fun () -> body enum.Current)))

The Using, While and Delay methods are described elsewhere in this post.

Here’s some sample code using the For method from our computational expression block

builder {        
   for i = 1 to 10 do
      printfn "%d" i
} 

TryFinally

An implementation of the TryFinally method is fairly straightforward

member this.TryFinally(body, compensation) =
   try this.ReturnFrom(body())
   finally compensation() 

and in usage within a computational expression block, we have

builder {        
   try
      let x = 1 / 0
      printfn "should not make it to here"
   finally
      printfn "exception"
} 

In the above code, when we step into the try block we will actually enter the TryFinally method and obviously this then takes over executing the body of the code and then executing the finally block.

TryWith

Very much like the TryFinally block, we have the following implementation

member this.TryWith(body, handler) =
   try this.ReturnFrom(body())
   with e -> handler e

and an example of the computational expression block might be

builder {        
   try
      let x = 1 / 0
      printfn "should not make it to here"
   with
   | :? DivideByZeroException -> printfn "divide by zero"
} 

Using

As the name suggests, this is used for IDisposable types. Here’s a sample of it’s implementation

member thisTryFinally(body, compensation) =
   try __.ReturnFrom(body())
   finally compensation() 

member this.Using(disposable:#System.IDisposable, body) =
   let body' = fun () -> body disposable
   this.TryFinally(body', fun () -> 
      match disposable with 
      | null -> () 
      | disp -> disp.Dispose())

The Using method relates to the use! keyword and hence we might have code such as

builder {        
   use! x = new MemoryStream()
   printfn "do something with the memory stream"
} 

So at the point use! is invoked our Using method takes over. We i

While

The example of a while loop in a computational expression was lifted from “Implementing a builder: The rest of the standard methods” and I highly recommend anyone visiting this post goes and reads the computational expression series on F# for fun and profit.

So our example code is as follows

let mutable i = 0
let test() = i < 5
let inc() = i <- i + 1

let builder = SampleBuilder()

builder {        
   while test() do
      printfn "%i" i
      inc()         
} |> ignore

It’s important to note that the three let statements at the top of the source must be global or you’ll get an error along the lines of “The mutable variable ‘i’ is used in an invalid way. Mutable variables cannot be captured by closures. Consider eliminating this use of mutation or using a heap-allocated mutable reference cell via ‘ref’ and ‘!’.”

So our builder code should look something like the following

member this.Bind(m, f) = f m

member this.Return(x) = x

member this.Zero() = this.Return ()

member this.Delay(f) = f

member this.Run(f) = f()

member this.While(guard, body) =
   if not (guard()) 
   then 
      this.Zero() 
   else
      this.Bind( body(), fun () -> 
         this.While(guard, body))  

So as can be seen, in the While method we are passed the guard and the body of the while loop and as expected we need to invoke these bits of code to evaluate them. When the guard completes we invoke the Zero method which in this case simply called the Return method. If the loop has not completed we simply keep looping.

Yield and YieldFrom

We can use yield or yield! from a computational expression, but to do so we need to implement the Yield and YieldFrom methods (respectively) on the builder, otherwise we’ll be greeted with the “This control construct may only be used if the computation expression builder defines a ‘Yield’ method”, here’s an example of the yield being used from a computational expression block

builder {
   yield 100
} |> printfn "%A"

// or

builder {
   yield! 100
} |> printfn "%A"

An example of the Yield and YieldFrom methods in the builder might look like the following

member this.Yield(x) = Some x

member this.YieldFrom(x) = x

Zero

You may have noticed, if you’ve written your own builder type that something like the following

builder {
}

// or

builder {
} |> ignore

doesn’t compile, this is because a computational expression must have something within the curly braces. So if instead we write the following

builder {
   printfn "Hello"
}

We’re get an altogether different error at compile time stating This control construct may only be used if the computational expression builder defines a ‘Zero’ method. Basically a computational expression must return something, either explicitly or implicitly. In this case Zero is used for any implicit return, so we could resolve this error using

member this.Zero() = ()

or ofcourse we might implicitly return the same thing we would with an explicit return such as

member this.Return(x) = x

member this.Zero() = this.Return ()

Properties, Binding, Property Wrappers and MVVM with Swift

Swift includes properties within the language (see Properties), but also supports (what we’d call in C#) property or data binding mechanisms.

Before we get started, I’m writing this post as a learning exercise, I’d suggest you checkout the references at the bottom of the post for a much more in depth look at this subject.

If you’re still reading, then let’s get started…

To begin with we’ll look at how we declare properties in Swift first. For those coming from C# or similar languages, then the simplest stored property looks just like a field

Property Declarations

struct MyModel {
    var id: String;
}

The above declaration is known as a stored property, in that we can store values with the specific instance of the MyModel type, this is really the equivalent of having a property with a default getter and setter.

We can also declare properties as readonly like this

struct MyModel {
    var id: String {
        return "SomeId"
    }
}

Both of the above examples are basically properties using “shorthand syntax”, like C# we can also create properties with get and set keywords – of course these are useful if the setting of the property (for example) does more than just assign a value, hence we have a form (notice you can use return or in these example we’re using implicit return

struct MyModel {
    private var _id: String = "SomeId"
        
    var id: String {
        get {
            _id
        }
        set {
            _id = newValue
        }
    }
}

Property Observer

Property observers allow us to monitor a property change. For example if you have a struct/class with the shorthand syntax for a property then we can willSet and/or didSet to our property, for example

struct MyModel {
    var id: String = "" {
        willSet(newTitle) {
            print("About to set value")
        }
        didSet {
            if title != oldValue {
                print("Set Value")
            }
        }
    }
}

Now when the property is about to be set, the willSet code is called and when a value changes didSet will be called. Obviously you wouldn’t want to do anything within these methods that could affect performance.

Property Wrapper

A Property Wrapper allows us to (well as the name suggests) wrap a property within a type that we can separate the storage of the property from functionality that acts upon that property. For example if our title has a length constraint, we might create a property wrapper to implement this functionality

@propertyWrapper
struct LengthConstraint {
    private var value = ""
    var wrappedValue: String {
        get { value }
        set { value = String(newValue.prefix(5)) }
    }
}

Property Binding

So what’s this got to do with binding/data binding/property binding? Well we’ve now seen how we declare propeties and can add property wrappers to the property. Within SwiftUI we can use the @Published property wrapper to our property which gets observed by a UI element and when the value changes updates the UI or in the case of TextField, when changes are made to the text field it’s placed into our property.

There are several different property wrappers for this type of functionality

  • @Published – this is used on property classes, such as ObservableObject subclasses.
  • @StateObject – this is used within a view to store an instance of an ObservableObject subclassed type
  • @State – this allows us to store bindable data within a view
  • @Binding – this is used in views which need to mutate a property owned by an ancestor view. In essences it’s like connecting to a parent’s property
  • @EnvironmentObject – this is a shared object stored within the environment and is used in situations where passing properties through a UI hierarchy or the likes becomes too cumbersome.
  • @Environment – this is used to connect to actual environment properties, such as reading whether the application is in dark theme or other SwiftUI properties

MVVM

We can declares @State and @Binding property wrappers (for example) within our view, but of course this can pollute the UI with view model state. If we prefer to go with a MVVM approach, i.e. separate the view from the view model, then we will start off by subclassing ObservableObject, for example here’s a minimal view model

@MainActor class ViewModel: ObservableObject {
    @Published var title: String = ""
}

@StateObject private var viewModel = ViewModel()

In the above code we declare and subclass of the ObservableObject and then we declare the properties that we wish to expose. The @StateObject line is what you’ll have in your ContentView to create an instance of the ObservableObject.

The @MainActor is used to denote that this class runs code on the main queue – essentially if you’re used to Windows UI programming this can be seen as equivalent to running code on the UI thread.

This of course might seem simpler to just declare properties like this, but then our model ends up more tightly coupled to the view than we might want

@State var title: String = ""

References

All SwiftUI property wrappers explained and compared
How to use @MainActor to run code on the main queue
What is the @Environment property wrapper?