Maddy is the program manager/ owner of Microsoft’s Aspire. This is new, exciting and powerful.
More about Aspire
This from 2009:
Yudkowsky poses the following canonical problem:
1% of women at age forty who participate in routine screening have breast cancer. 80% of women with breast cancer will get positive mammographies. 9.6% of women without breast cancer will also get positive mammographies.
A woman in this age group had a positive mammography in a routine screening. What is the probability that she actually has breast cancer?
The frightening thing is that only 15% of doctors get this right. And they’re off by a lot. That is, the average answer is in the range of 80% while the correct answer is 7.8%. Apparently, there is something about the way we think about the problem that makes 7.8% hard to accept, and Yudkowsky does a great job of walking you through the logic in painfully small steps.
Let’s try something similar here…
What Do We Know & What Does It Imply?
We have three pieces of information:
1% of sample are TRUE (that is, they have cancer)
80% of sample who are TRUE will test TRUE
9.6% of sample who are FALSE will test TRUE.
On the face of it, we should guess that the percentage of women who test TRUE who actually are TRUE (test positive and actually have cancer) is pretty small based on two facts provided: the actual percentage of women from the sample who are TRUE (regardless of testing) is only 1%, and the test has a false positive for 9.6% of those tested.
So, to solve this:
1) Assume we have a sample of 1000 women (I use 1000 to reduce the amount I have to talk about fractional people, but I don’t use 10,000 as I get lost in the zeros).
2) We know that the reality is that of the 1,000 women, 10 will have cancer (1%).
990 = no cancer
10 = cancer
3) Of the 10 who have cancer, 8 will test positive
8 out 1000 women tested will test True and are True
4) Of the 990 with no cancer 9.6% will also test positive = 990 * .096 = 95.04.
95.04 women out of 1,000 will test True but are False.
5) The total number testing true is 8 + 95.04 = 103.04.
Of these, 8 actually have Cancer.
6) So the value for tests positive (103.04) versus is positive (8) is 8/103.4 or 0.773 or 7.8%
Microsoft has a wonderful tutorial on pattern matching, in which you model a lock (to raise or lower a ship when there would otherwise be a waterfall). They model the two doors and the water level.
While their example is excellent it is long, and in this blog post I’m going to take the essence of pattern matching using their example.
We start with a state machine:
The chart indicates whether the gate should be opened or closed based on the new setting and the current status of the gate as well as the water level. We read it as follows: if the new setting is closed, it doesn’t matter what the starting state of the gate is, nor the water level, we close the gate (first three lines).
On the other hand, if the gate is closed (line 4) and we give it a new state of open and the water level is high, then we open the gate. If, on line 5, we tell it to open from a closed state, but the water level is low then we have an error (don’t open when the water is low).
Finally, if we say open and it is open and the water level is high, then we do, in fact, open.
These states can be modeled in a switch expression using pattern matching where true = open and false = closed:
HighWaterGateOpen = (open, HighWaterGateOpen, CanalLockWaterLevel) switch{(false, false, WaterLevel.High) => false,(false, false, WaterLevel.Low) => false,(false, true, WaterLevel.High) => false,(true, false, WaterLevel.High) => true,(true, false, WaterLevel.Low) => throw new InvalidOperationException("Cannot open high gate when the water is low"),(true, true, WaterLevel.High) => true,
As you can see, the first three arms of this expression start false and end false, as we saw above. Next, we have the case where the new state is true, the current state is false and the Water level is high. This causes the gate to open (true).
But it gets easier. First, we need the default case. In the latest C# an underscore matches anything. So we add
_ => throw new InvalidOperationException(“Invalid internal state”),
as the default, meaning if anything else comes up, it is invalid.
Note that, as we said, the first three arms all evaluate to false. We can replace them with
(false, _, _) => false,
You read this as, if the first value is false (the new condition) then no matter what the second and third conditions are, we will evaluate to false.
Next we need to know what to do if the new state is true. This is slightly tricker as it depends on the water level:
(true, _*, WaterLevel.High) => true,* *(true, false, WaterLevel.Low) => throw new InvalidOperationException("Cannot open high gate when the water is low"),* => throw new InvalidOperationException("Invalid internal state"),
Thus, if the new state is true, and the water level is high (no matter the state of the gate), then we do open the gate. If the new state is open (from on original state o closed) and the water level is low then, uh oh.
Here is the final version of the method:
// Change the upper gate.public void SetHighGate(bool open){ HighWaterGateOpen = (open, HighWaterGateOpen, CanalLockWaterLevel) switch { (false, _, _) => false, (true, _, WaterLevel.High) => true, (true, false, WaterLevel.Low) => throw new InvalidOperationException("Cannot open high gate when the water is low"), _ => throw new InvalidOperationException("Invalid internal state"), };}
All of this is simpler, cleaner and thus easier to understand and maintain than a series of if statements or even a set of switch statements.
I admit it, I’ve struggled with pattern matching. In the next few blog posts I’ll explore this magic, starting today with switch expressions (not to be confused with switch statements).
The type of switch we’re familiar with is the switch statement:
namespace switchStatement;internal class Program{ static void Main(string[] args) { string day = string.Empty; day = GetDay(2); Console.WriteLine(day); } public static string GetDay(int dayNum) { string dayName; switch (dayNum) { case 0: dayName = "Sunday"; break; case 1: dayName = "Monday"; break; case 2: dayName = "Tuesday"; break; case 3: dayName = "Wednesday"; break; case 4: dayName = "Thursday"; break; case 5: dayName = "Friday"; break; case 6: dayName = "Saturday"; break; default: dayName = "Invalid day number"; break; } return dayName; }}
This will return Tuesday.
A switch expression has a slightly different syntax, but more important, it matches on a pattern. I’m going to use the example from Microsoft Learning (https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression) and take it apart
public static class SwitchExample{ public enum Direction { Up, Down, Right, Left } public enum Orientation { North, South, East, West } public static Orientation ToOrientation(Direction direction) => direction switch { Direction.Up => Orientation.North, Direction.Right => Orientation.East, Direction.Down => Orientation.South, Direction.Left => Orientation.West, _ => throw new ArgumentOutOfRangeException(nameof(direction), $"Not expected direction value: {direction}"), }; public static void Main() { var direction = Direction.Right; Console.WriteLine($"Map view direction is {direction}"); Console.WriteLine($"Cardinal orientation is {ToOrientation(direction)}"); }}
The output of this is
Map view direction is RightCardinal orientation is East
The method ToOrientation takes a Direction and calls the switch expression (notice the placement of the keyword switch).
It then sets up the Direction to Orientation pattern matching. For example, it establishes that if the passed in parameter is Direction.Up (that is, the Up enumerated constant) then it is to be converted to Orientation.North, and so forth. (The underscore is a new way of indicating no value, or in this case, the default).
The various expressions are called “arms” and are separated by commas. Each arm contains a pattern and an expression. In the first arm, Direction.Up returns the expression Orientation.North.
It is this pattern matching that I’ll be exploring in the next few blog posts.
Until now, if you wanted to access the last item in a list you had to use a slightly cumbersome syntax. C# 13 introduces the “hat” operator (^) where ^1 is the last element in your collection, ^2 is the penultimate member, etc.
Like many things, this is best illustrated with an example. In the following code I create a simple Person class and initialize a list
internal class Program { static void Main(string[] args) { var tester = new Tester(); tester.Test(); } } public class Tester() { public void Test() { var john = new Person { Name = "John", Age = 25 }; var jane = new Person { Name = "Jane", Age = 30 }; var joe = new Person { Name = "Joe", Age = 35 }; var people = new List<Person> { john, jane, joe }; } } public class Person() { public string Name { get; set; } public int Age { get; set; } }
Straight forward. Now, if I want to access the last person in this list I can write
var lastPerson = people[^1]; Console.WriteLine($"Last person is {lastPerson.Name} who is {lastPerson.Age} years old.");
As you can see, this is concise and easy to understand. You read it as “lastPerson is equal to one back from the end of people.” Let’s run it:
Last person is Joe who is 35 years old.
That is all there is to it. Easy to use and somewhat helpful in simplifying your code.
This short post will kick off a series covering some of the new features in C#.
One small but much requested feature is the ability to use any kind of collection for params. Previously you had to pass in an array:
public void MyMethod(int firstParam, params string[] otherParams) { foreach (var param in otherParams) { Console.WriteLine(param); } }
But now you can pass in any kind of collection,
public void MyMethod(int firstParam, params List<string> otherParams) { foreach (var param in otherParams) { Console.WriteLine(param); } }
This can save a great deal of fussing, converting your collection to an array and back.
Please note that this is a preview feature. Fortunately, Intellisense will convert your project for you. When you put this in you’ll get the dreaded red squiggly. Click on the light bulb and let it convert your project. Hey! Presto! it works.
We’ll look at a few bigger features in coming blog posts.
I sense that a lot of us have had trouble keeping up with the rapid growth of C# features. My guess is that most of us fell off the cliff somewhere around C# 7 (we’re up to 13/14). I have in mind to write a book that assumes you are already a C# programmer and brings you up to speed on the latest features and techniques.
Here are just a few topics I’d cover:
1. Switch Expressions
2. Pattern matching
3. Tuples
4. Records
5. Dynamic binding
I would not cover such topics as if statements, etc., nor even basic polymorphism.
The book would be as short as possible, providing hands-on examples but no fluff. Further, I wuld not show the evolution of a feature, but rather just teach the most modern version.
Would such a book be of interest to you? I’d like to get a sense of the audience before starting.
Please send me a note at jesseliberty@gmail.com
Two years ago, I made a list of my indispensable tools. Here is a quick updated version:
Lists are always subjective, but it is helpful, I think, to exchange favorites now and again. Feel free to add yours to the comments. Here’s my list in no particular order
Note that nearly all of these are free. I do remember the days when a program like Lotus 123 cost something in the hundreds of dollars. It makes me laugh when I see people look at an app and say, “$4, naah, too expensive.”
I am not affiliated with any of these.
As I say, grab these, and if there are others that you use, please note them in the comments.
Thanks
My cache blew up my site. The good people at GoDaddy fixed me up, but I lost a good bit of the past 12 years of content (through my own stupidity). Never fear, however, all the new stuff is intact.
In addition, I took the opportunity to upgrade, so the site should be faster and backed up daily, and while I was at it, we upped the security. So, all in all, there was a silver lining.
An important part of creating APIs is interacting with data storage. While you can use any number of database programs, a common way to store simple data is in data tables. This is particularly useful when you are recording API calls as part of your telemetry.
Storage tables are not inherently relational. The goal is to keep storage tables simple. This makes them ideal for keeping lists, logging, creating progress entries, and so forth.In this demo, we’ll create a storage table that tracks exceptions thrown during execution of our program. Let’s create a console app that just throws exceptions every few seconds.
Create a new console app and name it TableStorageConsoleApp. Choose .NET 8 (or 9) and check Do not use top-level statements.
In main, create a forever loop and have it throw an exception. We want the exceptions to be thrown randomly.
I’m having trouble with WordPress layout, so please forgive the fonts in this post. I’ll sort it out ASAP.
try
{
Random rand = new Random();
var random = rand.Next(0, 10);
switch (random)
{
case 0:
throw new ArgumentException(“Argument Exception”);
case 1:
throw new ArgumentNullException(“Argument Null
Exception”);
case 2:
throw new ArgumentOutOfRangeException(“Argument Out Of
Range Exception”);
case 3:
throw new DivideByZeroException(“Divide By Zero
Exception”);
case 4:
throw new FileNotFoundException(“File Not Found
Exception”);
case 5:
throw new FormatException(“Format Exception”);
case 6:
throw new IndexOutOfRangeException(“Index Out Of Range
Exception”);
case 7:
throw new InvalidOperationException(“Invalid Operation
Exception”);
case 8:
throw new KeyNotFoundException(“Key Not Found Exception”);
case 9:
throw new NotImplementedException(“Not Implemented
Exception”);
case 10:
throw new NotSupportedException(“Not Supported
Exception”);
default:
throw new Exception(“Generic Exception – you should never
see this”);
}
}
Now we can catch each exception and put it into our table.
The key thing here is that the table has Partition keys and Row Keys. Partition keys aggregate rows, and makes retrieval much faster.
TableServiceClient is a NuGet package. We call Upsert and sleep for two seconds.
The table model itself looks like this:
public class TableModel : ITableEntity
{
required public string PartitionKey { get; set; }
required public string RowKey { get; set; }
public DateTimeOffset? Timestamp { get; set; }
public string? Message { get; set; }
public ETag ETag { get; set; } = ETag.All;
}
(Etag is used for optimist concurrency and must be in every table model.
Here is UpsertEntityAsync
public async Task UpsertEntityAsync(TableModel entity){var response = await _tableCreationTask;var table = _tableServiceClient.GetTableClient(response.Value.Name);return await table.UpsertEntityAsync(entity);}
To get started, we declare two member variables at the top of the class: private readonly TableServiceClient _tableServiceClient; private readonly Task> _tableCreationTask;Notice that the second member is of type Task. Both Response andTableItem are supplied by the Azure NuGet package. The constructor takes TableServiceClientpublic StorageTableService(TableServiceClient tableServiceClient){_tableServiceClient = tableServiceClient;_tableCreationTask = _tableServiceClient.CreateTableIfNotExistsAsync(“ExceptionsTable”);}It is here that we create the table if it doesn’t exist and name it ExceptionsTable.All the Upsert method needs to do is call tableCreationTask and wait to get back Response. With that in hand, it is ready to call GetTableClient onTableServiceClient, passing in the name of the table. Finally, we call UpsertEntityAsync on the table passing in TableModel.
Your output should be a simple table with one row for each exception thrown.The next step is to migrate this to Azure which we will do in the next blog post.
Note, this post is based on my forthcoming book Programming APIs with C# and .NET from Packt. Which will be available the end of November 2024.
jesseliberty.com just crossed 1MM views (lifetime). So pleased you’ve stuck with me. See find me in menu to continue the dialog.
Mads Torgersen, lead designer of C# joins me to talk about what’s new in C# 13 and much more
Performance is king (well, after accuracy) in APIs. Sending a request to the Database only to discover that the request is invalid is a waste of resources. Thus, we want to validate the request as soon as it hits the endpoint.FluentValidation is a great tool for creating validators. It installs as a NuGet package. Also grab the version for ASP.Net.
To get going, add a using statement.
Using FluentValidation
Next, create a class that derives from AbstractValidator.
*public class CarNotDeletedValidator : AbstractValidator<Car>*
This example uses the Car class from my forthcoming book Creating .NET APIs with C#.
Put your validation rules in the constructor. Each rule is created by using the keyword RuleFor and a lambda expression that indicates which property you want to validate and the validation rule.
using Cars.Data.DTOs; using FluentValidation;namespace Cars.Validators{ public class CarNotDeletedValidator : AbstractValidator<CarDto> { **public CarNotDeletedValidator() { RuleFor(x => x.Is\_Deleted).Equal("0"); }** } }
The Equal operator is one of many that you can find at the FluentValidation documentation page: https://docs.fluentvalidation.net/en/latest/built-in-validators.html.
We’ll test the data and then either compare it to what is valid and return an error if appropriate, or, more commonly, we’ll throw an exception if the data fails validation.
Assuming that it passes validation we can continue to the Database. If however it fails, we can return a meaningful error to the sender.
This site has been quiet for a few months while I finish up my book (.NET APIs with C#). I’m happy to reboot both the blog and Yet Another Podcast, starting soon with an interview of Mads Torgerson (lead designer of C#)!
To get things rolling, I’m going to pick up my series on creating APIs, based on my forthcoming book (scheduled to be in bookstores mid-November).
I will be speaking at Boston Code Camp this November as well. In fact, once the election is passed (I’m spending 10+ hours/week on campaigning) I expect to be putting in a lot of time on this blog.
I hope you will join me as I get back to work providing (hopefully useful) information to the community.
As always, you can reach me at jesseliberty@gmail.com
Scott Hunter (VP Microsoft) joins Yet Another Podcast’s reboot to talk about Aspire, Azure and much more. Do not miss this episode… Aspire will blow you away!
Links to follow.
In the previous post, I introduced Swagger and showed how to set up your project for Swagger. In this post I will show how to add Swagger comments to annotate your program.
In earlier posts we looked at the database of cars and the Get method that retrieves the entire list. That can be quite a lot of data going over the wire. What we want instead is to send pages. I’ll show that briefly and then we’ll annotate that code.
In the CarController we’ll have a Get method that takes three parameters: showDeleted, pageNumber and pageSize. The first we’ve seen before, it determines whether the list returned to the caller will include our deleted records. The second, pageNumber, will designate which page of data we want to return (zero based). The third parameter, pageSize, will designate how many records to return per page.
Thus, if we were to write
Get(false,3,4)
we would expect to get back records 17, 18, 19 and 20, because page 0 would have records 1-4, page 1 would have 5-8, etc.
Here is the compete endpoint that will directly call our repository (we won’t bother with a service for this example).
public async Task<IEnumerable<Car>> Get([FromRoute] bool showDeleted, int pageNumber, int pageSize ){ return await _carRepository.Get(showDeleted, pageNumber, pageSize);}
When the repository is called, the parameters are passed in, and it does its magic. For now, however, we are only concerned with documenting this method. We do that with XML comments, designated by three forward slash marks (///).
First, we will document the purpose of the endpoint; that is, what it does. We do that in the summary
/// <summary>/// Get all the cars in the Database /// </summary>
Next, we want to document the parameters
/// <param name="returnDeletedRecords">If true, the method will return all the records,/// including the ones that have been deleted</param>/// <param name="pageOffset">which page to display</param>/// <param name="pageSize">how many records to display per page</param>
Finally, I’m going to document the possible response codes. Note, these are, by no means, all that you can document, but they’ll give us a good idea of how it is done
/// <response code="200">Cars returned</response>/// <response code="404">Specified Car not found</response>/// <response code="500">An Internal Server Error prevented the request from being executed.</response>
When an error is encountered and we return one of these codes, the text we’ve specified goes along for the ride, which is enormously helpful to the calling client.
At the top of the swagger page is our summary
At each parameter is our designated text
Finally, each of the error codes is documented
It is a best practice to document all of the endpoints. Many developers go further, and document all of the methods in both the service and the repository; that is a decision to be made by the team. Since the endpoint is the only thing visible to the client, it has the greatest claim on your time and effort. Remember, “comments rust,” and that is as true for Swagger comments as any other.
This is part 6 in a series about building APIs in .NET using C#. The previous (part 5) entry is here, and the series starts here.
As you know, an API sits between a client and the back end. It is imperative for the client programmer to know not only what an API does, but what the URL is, what verbs it supports and what parameters are available.
Fortunately, there is an open standard and free server: Open API and Swashbuckle. You install these once for each project and then you can just use them, as we’ll see.
This post will show you how to install them, using Visual Studio. You’ll obtain the bits you need using NuGet. Start by installing Swashbuckle.AspNetCore.
Go to your project’s properties and choose Application and Console Application. Then choose Output under Build and scroll down to where you can check “Generate a file containing API documentation”
Open Program.cs and add the Swagger generator to the services collection:
builder.Services.AddSwaggerGen( x => { x.SwaggerDoc( "v1", new OpenApiInfo { Title = $"{Assembly.GetExecutingAssembly().GetName().Name}", Version = "Version 1", Description = "Create documentation for myApp", Contact = new OpenApiContact { Name = "Jesse Liberty", Email = "yourName@gmail.com", Url = new Uri("https://jesseliberty.com") } }); var xmlFilename = System.IO.Path.Combine(System.AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"); c.IncludeXmlComments(xmlFilename);});That's it, you are now ready to create Swagger documentation. We'll review how to do so in the next installment.
An experiment in supplementing the API material with video. This will be rough at first…
In the previous posting we saw how to create an API to get all the cars in our database. In this posting we’ll look at the remaining CRUD (Create Review Update Delete) operations.
As you may remember, we created a controller named CarController. ASP.NET will strip off the word Controller, leaving us with Car, which we will use to access the endpoints of our API.
An endpoint is just a URL that takes us to the operation we want.
We looked at GetAll, let’s take a look at Get. In this case, we have an id for the car we want, but we want all the details of that car. Simple!
First we need a method in our controller:
[HttpGet**("{id}")]**public async Task<ActionResult<Car>> Get(int id){ var car = await \_carRepository.Get(id); if (car == null) { return NotFound(); } return car;}
Notice that next to the HttpGet attribute we indicate that the endpoint will take the id of the car we want
[HttpGet("{id}")]
This means we need to modify the URL to access the endpoint by adding the actual id of the desired record.
The first thing we do is call the repository, passing in the id.
public async Task<Car?> Get(int id){ var query = "select * from car where id=@id"; using var db = databaseConnectionFactory.GetConnection(); return await db.QuerySingleOrDefaultAsync<Car>(query, new {id});}
In the Get method of the repo we create our query, get our connection and execute the query returning the value we retrieved (if any). This is very close to what we did previously.
Back in the controller, we check to ensure that we received a Car. If not, we return NotFound which is a shorthand way of returning a 404 message. Otherwise we return the Car as a Json object. You can see this in Postman:
We’ll issue a Get command passing in the URL, ending with the id of the car we want (in this case 4)
Notice that we get back a 200, indicating success. In the body of the returned Json we get back all the details of the Car. (If you decide to use DTOs you can get whatever subset of the information makes sense):
{ “id”: 4, “name”: “subaru impreza”, “mpg”: “16”, “cylinders”: “8”, “displacement”: “304”, “horsepower”: “150”, “weight”: “3433”, “acceleration”: “12”, “model_year”: “22”, “origin”: “usa”, “is_deleted”: “0”}PostAdding a Car to the database is quite similar. We need a method in the controller and one in the repo. Here is the controller method:
[HttpPost]public async Task<ActionResult<Car>> Post([FromBody] Car car){ try { car = await **\_carService.Insert(car)**; } catch (Exception e) { return BadRequest(e); } return CreatedAtAction(nameof(Get), new { id = car.Id }, car);}
Look at the attribute in the parameter ([FromBody]. This indicates to the API that the data needed to insert this Car will be in the body of the call. The alternative is FromQuery. You can, in fact, use both in one call.
Note: CreatedAction causes a return code of 201, which is what we want. Here’s the body we’ll insert:
{ “name”: “chevrolet chevelle malibu”, “mpg”: “18”, “cylinders”: “8”, “displacement”: “307”, “horsepower”: “130”, “weight”: “3504”, “acceleration”: “12”, “model_year”: “70”, “origin”: “usa”, “is_deleted”: “0” }When we click Send this data is sent to the API which returns 201 (created) and in the body of the returned data we see the new id assigned to this car
{ “id”: 409, “name”: “chevrolet chevelle malibu”, “mpg”: “18”, “cylinders”: “8”, “displacement”: “307”, “horsepower”: “130”, “weight”: “3504”, “acceleration”: “12”, “model_year”: “70”, “origin”: “usa”, “is_deleted”: “0”}Service ClassNotice that this time, instead of calling the Repo directly, the method in the controller calls into a service class. A service class is a great way to get the logic out of the controller, where it does not belong, without putting it into the repo, where it also does not belong.
Here’s the top of the CarService
public class CarService : ICarService{ private readonly ICarRepository \_carRepository; public CarService(ICarRepository carRepository) { \_carRepository = carRepository; } public async Task<Car> Insert(Car car) { var newId = await \_carRepository.UpsertAsync(car); if (newId > 0) { car.Id = newId; } else { throw new Exception("Failed to insert car"); } return car; }
All the logic associated with this insert (e.g., making sure we get back a legitimate id from the repository, etc.) is encapsulated in the service.
This leaves the repository free to just talk to the database,
public async Task<int> UpsertAsync(Car car){using var db = databaseConnectionFactory.GetConnection();var sql = @"DECLARE @InsertedRows AS TABLE (Id int);MERGE INTO Car AS targetUSING (SELECT @Id AS Id, @Name AS Name, @Model\_Year AS Model\_Year, @Is\_Deleted AS Is\_Deleted, @Origin AS origin ) AS source ON target.Id = source.IdWHEN MATCHED THEN UPDATE SET Name = source.Name, Model\_Year = source.Model\_Year, Is\_Deleted = source.Is\_Deleted,Origin = source.OriginWHEN NOT MATCHED THENINSERT (Name, Model\_Year, Is\_Deleted, Origin)VALUES (source.Name, source.Model\_Year, source.Is\_Deleted, source.Origin)OUTPUT inserted.Id INTO @InsertedRows;SELECT Id FROM @InsertedRows;";var newId = await db.QuerySingleOrDefaultAsync<int>(sql, car);return newId == 0 ? car.Id : newId;}
Rather than having an insert and an update method, we combine that logic into this upsert method. This is a common idiom for database manipulation.
Note: to make this work, be sure to fill in all the fields for a car (or at least as many as you want to have in the Database.
DeleteAs noted earlier, we will implement a soft delete; that is, rather than actually removing the data from the database, we’ll just set the is_deleted column to true. This allows us to reverse the action, and make the row not-deleted by simply changing that value to false.
[HttpDelete(“{id}”)]
public async Task
{
try
{
await _carService.Delete(id);
}
catch (Exception e)
{
return BadRequest(e);
}
return NoContent();
}
As you would expect, the endpoint takes an id (the id of the car we want to delete). The controller then hands that off to the service, which calls the repository which, in turn, marks that id as deleted:
public async Task<int> DeleteAsync(int id){ using var db = databaseConnectionFactory.GetConnection(); var query = "UPDATE car SET Is\_Deleted = 1 WHERE Id = @Id"; return await db.ExecuteAsync(query, new { Id = id });}
If you are comfortable with SQL none of this will be very surprising. The key walkaway is:
SummaryIn this post we saw that endpoints are just URLs with (potentially) data in the body of the request. The controller handles the URL and in our case passes the id or other data to the service. The service handles the (business) logic and then delegates talking to the database to the repository.
BookThis posting is excerpted from my forthcoming book Building APIs with .NET and C# to be released next year by Packt.
We are, finally, ready to create our ASP.NET Core application that will host our traditional and our minimal APIs. (This series begins here.) The code for this blog post is available here:git clone https://github.com/JesseLiberty/Cars.git Please note that WordPress seems to … Continue reading →
In a previous post I said I was still looking for the right file comparison tool. I may have found it! I returned to ExamDiff Pro and voilà! the perfect combination of power and ease of use. I integrated it … Continue reading →
In part 2 of this series we created a simple database. In this part we’ll look at how to perform CRUD operations against that DataBase in anticipation of creating APIs for these operations. Dapper is a micro-ORM (Object Relational Mapper) … Continue reading →
I’m interviewed by my old friend J. Tower (of Trailhead Technology Partners) on his Blue Blazes YouTube program, talking about Unit Testing. Lots of fun discussing an important topic. Tune in here.
As noted in part 1 of this series, I will be building an application specifically to explore building APIs. To get started, I’ll want to build a back-end database. The application we’ll be simulating is a car dealership. Customers can … Continue reading →
While I’m still happily ensconced at CNH Industrial, I have changed my job. I’m no longer writing mobile applications (for the first time in about 7 years!) but rather am writing APIs using ASP.NET Core and C#. -The plan is … Continue reading →
I had the pleasure of turning the tables and being interviewed on WebRush with Jon Papa et al https://www.webrush.io/episodes/episode-240-theres-something-net-maui-with-jesse-liberty
https://www.packtpub.com/article-hub/writing-a-customized-cover-letter-for-a-specific-job-in-minutes-using-chatgpt
I wrote this blog post in September of last year, and looking at it today I realized that I don’t use a couple of these anymore: 1) Resharper: the overhead was borderline too much and most of the refactoring power … Continue reading →
I have changed jobs within my current company (CNH Industrial). I will no longer be doing mobile programming (for the first time in six years) and will be building APIs and back-end code!
I think you can expect fewer articles on mobile/ .NET MAUI programming, and more on ASP.NET Core, Azure Functions, APIs, Architecture, Microservices, etc.
I’m also scoping out writing a book which may include the following topics:
The book would assume only that you have some C# experience. We’d also cover tools, setup, and best practices. All of this would be in the context of a non-trivial application.
I’d be very interested in hearing your thoughts on such a book. Please feel free to send me email at jesseliberty@gmail.com.
I’ve posted my .NET MAUI For Xamarin.Forms Programmers and Advanced .NET MAUI videos on YouTube.
I’ll be presenting at Boston Code Camp on
This is a free, one-day event on Saturday, April 29, in Burlington, MA.
With the release of my newest book, .NET MAUI For C# Developers, I’m pleased to present occasional posts on advanced topics. If you are just starting out, however, you may want to take a look at my previous 15 part series in which I learn .NET MAUI or my second series that uses the app (Forget Me Not) that we’ll be using here. Finally, you can find my presentations on .NET MAUI and advanced .NET MAUI on YouTube, here.
Managing Visual State
Every VisualElement has a Visual State. For example, does the VisualElement have focus? Is it selected? Xaml allows you to change the presentation of that VisualElement (e.g., a button) based on that state.
The object that sets visual properties on a VisualElement based on its state is the Visual State Manager. The Visual State Manager selects from among a set of VisualStates and displays the view according to styles that you create.
Defining the common visual states
.NET MAUI defines a set of common visual states:
.NET MAUI also allows you to define your own visual states.
Button VisualState example
When you first come to the Login page in Forget Me Not, the Submit button is disabled. Once you fill in the two fields of Your Email and Password, the button should turn light green. If you tab to the button it should signify that it has the focus by turning fully green. You can do all this declarative with Visual States.
Visual State and Styles
You can set the visual state on an individual button, or, as we will do here, you can put the visual state XAML into a style and apply it to all the buttons. Here is the complete Style for buttons:
```
``` We start by declaring a normal Style, in this case implicit for every button. You may have one or more groups of visual states (we have one). The first group (and in this case the only one) is the CommonStates
We declare each VisualState in turn (here we’re starting with Normal). For each state, we can declare a set of Setters. Our first (and in this case only) Setter sets the BackgroundColor property
We then go on to set the Setters for all the other states. Notice that we did not set the Setter for PointerOver, which means that, on Windows and macOS, if you hover the mouse over the button there will be no change.
.NET MAUI defines specialized visual states for controls. For example, Button adds the Pressed state while CheckBox adds the IsChecked state and CollectionViews adds Selected.
The .NET MAUI community toolkit provides further help for managing the appearance and behavior of your app with a large collection of Behaviors.
I presented on .NET MAUI For Xamarin.Forms Programmers and Advanced .NET MAUI in Prague last week, and it was great (Prague, not the presentations).
All went well, but touring Prague was terrific. The city was founded in the 10th century and the architecture reflects a millennium of development. The city is immaculate and while only about ⅓ of the people I tried to talk to spoke English, many of those who did spoke it perfectly. The mass transit system is fantastic and the sites are literally awesome.
I’m very grateful to have had this opportunity.
Speaking at .NET MAUI Update
In Stores Now!
Very excited about this book. Feedback is very welcome at jesseliberty@gmail.com.
Thanks!
Excited to have Patrick Smacchia of NDepend on to discuss this amazing tool for creating world-class .NET applications.
Use Cases
Videos
Download NDepend
My latest book: Learn .NET MAUI — An Essential Guide for C# Developers will be released March 31, 2023.
Given the existence and likely enhancements to the .NET MAUI Community Markup Toolkit for C#, and that many people will come to MAUI with little or no XAML (or will know XAML and hate it), I was tempted to show all of the code in C#.
But the truth is that most extant User Interface code is in XAML and anything you can do in C# you can do in XAML. So, at least for the first edition, the majority of the code is in XAML with one full view recreation in C#
Here is the Table of Contents:
I’m eager to hear your ideas about this decision.
Thanks.
Triggers in .NET MAUI are not that different from triggers in Xamarin.Forms, but since this is not a frequently used feature, I thought I’d provide a quick deep-dive into their usage.
Triggers allow you to declare, in your XAML, how a control should appear based on data changes. You can combine state triggers with Visual State, a topic I’ll cover in a subsequent blog post.
This is the first of a series of short pieces based on material in my forthcoming book .NET MAUI For C# Developers (Packt* Publishing) which we are targeting for publication in early April.
For example, suppose we have a create account page, and we want the create button to be disabled if the user has not filled in a password. You can certainly do this in code (and .NET MAUI Community Toolkit will make this very easy with behaviors), but you can also do it declaratively in XAML using a DataTrigger.
<Button Command="{Binding DoCreateAccountCommand}" Grid.Column="1" Grid.Row="2" Style="{StaticResource LoginButton}" Text="Create Account"> <Button.Triggers> <DataTrigger Binding="{Binding Source={x:Reference passwordEntry}, Path=Text.Length}" TargetType="Button" Value="0"> <Setter Property="IsEnabled" Value="False" /> </DataTrigger> </Button.Triggers></Button>
Notice that the Button has a collection of Triggers. The type we want is a DataTrigger (as opposed, for example, to an event trigger). The trigger binds to the passwordEntry field’s Text.Length and looks for the value 0. If that is true, then the property IsEnabled is set to false. Once the Text.Length is not zero, the property is set to true.
That’s all it takes. You can see that triggers are often quite simple, but for some reason considered “advanced” and thus not used often; which is a shame because they can greatly simplify your code and make the logic easier to understand.
Note that the field you are checking (in this case password) must have its Text initialized to “” (in the ViewModel or code-behind, but of course the ViewModel is the right place). Otherwise it will be null, and the trigger may not act as expected.
In my next tutorial, I’ll tackle the more interesting and complex subject of Visual States.
———–
*This being my second book from Packt, I decided to ask how it is pronounced. Turns out it is one syllable, sounding more like packed than like packet. If you want to get it really right, say the word pack and sneak in a t sound at the end. (Just thought you’d want to know.)
I’m speaking about .NET MAUI in Prague on March 23 and 24. If you’re in the neighborhood…
https://maui.updatedays.cz/speakers/en?langChange=en
https://maui.updatedays.cz/#about/en
Picking the best blog posts is pretty painless as I’m the only one posting, so there is no one to insult, but picking the best podcasts risks slighting some of the amazing people who came on Yet Another Podcast.
5 Best Blog PostsThe best blog posts are those that either alone or in a series teach something valuable and current. For 2022, these stand out:
5 Best PodcastsWe had 11 fantastic podcasts in 2022, how do I pick the top five? The only reasonable approach is by their popularity. In date order, they are:
It was quite a year for me as well. I started my newest book .NET MAUI for C# Developers (Packt) to be released at the end of the summer (or, I hope, earlier!)
I also moved from Twitter to Mastodon, which was a big and terrific change. I opened my tiny book store, mostly to keep track of my favorite books, and I opened a new web site for my novel in search of an agent.
Along the way I shed 100 pounds, trained my dog not to pull and, oh yeah, worked full time writing mobile applications for CNH Industrial.
Welcome to what someone on Mastodon called 2020 v3. Let’s hope it is a good and safe year.
Simon (2 year old pointer-mix rescue)
David Ortinau, Program Manager .NET and voice of .NET MAUI discusses MAUI as a platform, Blazor Hybrid, Community Toolkits, as well as what’s on the road map for .NET MAUI.
What’s your opinion: XAML vs. Fluent C# for new MAUI programmers?
Please note that something went wrong with distributing this podcast and so I am reposting.
David Ortinau, Program Manager .NET and voice of .NET MAUI discusses MAUI as a platform, Blazor Hybrid, Community Toolkits, as well as what’s on the road map for .NET MAUI.
What’s your opinion: XAML vs. Fluent C# for new MAUI programmers?
Bill Wagner creates C# learning and reference materials for https://learn.microsoft.com. He works with colleagues on the C# team, related content teams, and customers to provide resources for everyone that wants to learn more about C#. He’s also a member of the ECMA C# Standardization committee, working to update the C# standard.
I asked Bill, to come talk about C# 11 and to do so from the perspective of a programmer who stopped following the newest additions to C# as of C# 7 or 8 or so. That is, how do we catch up if we’ve fallen behind on the latest features?
This is part one, in which we discuss, among other things, Pattern Matching.
Here is a link to the tutorial Bill describes.
And here is a link to the top of the C# documentation.
Mark Price joined me to discuss C# 11 and his books, C# 11 and .NET 7 and Apps and Services with .NET 7. A gremlin got into the audio and I only just discovered it today. I was able to recover the original, and am reposting. I apologize for the inconvenience. Let’s see if I can get Apple to push this replacement out to all the podcast providers.
Both books are available in my tiny book store, listed under Favorite books for programmers.
Mark Price, author of C# 11 and .NET 7 and Apps and Services with .NET 7 joins me to talk about C# 11
Picking up where we left off, I want to add unit tests to my program. Now, I know, I should have been using unit tests all along. I have no excuse and hang my head in shame. To get started, … Continue reading →
I have posted the (incomplete) code at https://github.com/jesseliberty/GraniteStateForgetMeNot and a video of much of the material captured in this series is now on YouTube
I’ve started a newsletter where I am publishing the first chapter of my novel, one sentence per day. This is not a techie novel, but check it out anyway. More at my fiction web site.
Part 2 of my discussion with Mads and Dustin on what’s new in C# 11 with a focus on when application developers will use the new features.
Joined today by Mads and Dustin to discuss what’s new in C# 11 with a focus on when application developers will use the new features.
Building on the previous postings, today I want to discuss the magic of Dependency Injection (DI) Dependency Injection makes for cleaner and more testable code. We’ll get into testing and Mocks in a later blog post, but using DI allows … Continue reading →
Building on the previous blog posts, here I’d like to illustrate how you can pass complex data from one page’s view model to another’s. Let’s assume we’ve tapped on the Buddies Icon on the tab bar and were taken to … Continue reading →
This is part 4 in an ongoing series in which I will build and dissect a non-trivial app. For details, please see the first in this series. Part 3 ended with a teaser about the Preferences Page. As you’ll remember, … Continue reading →
In the previous postings we looked at creating the basic app and adding a single, simple page. This post will really begin to get into it. We’re going to have a number of pages A page for you to enter … Continue reading →
In Part 1 we created the skeleton of Forget Me Not (and explained what it is). Here in Part 2 we’ll add an about page. This is so easy that this will be a short post. Create the page Creating … Continue reading →
My buddy in Argentina, Roberto Juarez, and I have set out to create a real-world, non-trivial program using .NET MAUI. This is a learning exercise, and I’d like to invite you to join us. We anticipate that (eventually) this will … Continue reading →
Lists are always subjective, but it is helpful, I think, to exchange favorites now and again. Feel free to add yours to the comments. Here’s my list in no particular order Visual Studio 2022 – goes without saying that this … Continue reading →
So let’s talk about something we don’t talk about. Many of us (programmers) are significantly overweight. You see it at every conference. I’ve heard 3xl referred to as a programmer’s medium. This year I decided to do something about it … Continue reading →
As an experienced XF programmer, you know that there are times you need a relational database, and SQLite has been the mobile db of choice for a very long time. In this post we’ll create a table in SQLite and … Continue reading →
Very excited to have Maddy back on Yet Another Podcast. Today we go beyond the basics to intermediate and advanced topics in .NET MAUI. Or wherever you get your podcasts.
Have I thanked James Montemagno yet? His 4 hour training video is the foundation of this series of posts (with his permission). Part 0 which kicks off this series is here. Platform Specific Services Now that we’ve covered platform services … Continue reading →
In this post we’ll do three things: Add a clear button to clear out the list of zip codes Add the Connected service to make sure we have internet connection before trying to get the zip codes Add the IMap … Continue reading →
We left off displaying the zip codes and going to the details, but not displaying the selected zip code. Let’s fix that and clean some things up. Choosing from the list and displaying the details In the previous version we … Continue reading →
This one should be short. We’re going to take a look at passing values when navigating. Passing in values requires that you pass a Dictionary, where the key is an arbitrary string and the object is the value you are … Continue reading →
Let’s take a quick look at simple navigation (in the next post we’ll look at some more you can do with navigation. As usual, we’ll start with the previous day’s code. To get started, we’ll add a button to the … Continue reading →
Once again, we’ll pick up where we left off. But today we’re in for some big changes. Let’s add an IsBusy property to use in the MainViewModel. We’ll use the same trick we did with _resultList: Let’s further assume you … Continue reading →
Busy week, so this one will be short. I’ve taken the code from Part 7 and copied it into Part 8. The source for 8 is here. So, what’s new? The most important improvement in 8 is the addition of … Continue reading →
Let’s pick up where we left off in the previous blog post, but it is time to clean up the app to use MVVM. First step: create a ViewModel folder and in that put two files: MainViewModel ViewModelBase MainViewModel is … Continue reading →
I’m going to start off where we were at the end of Part 5, but this time instead of creating two labels (for State and Zip) I’m going to create one label with MultiBinding:
When last we looked, we were returning a few countries. Let’s use ZipWise’s ability to look up a city name and give us all the info about all matching cities. We’ll then have fun with displaying that info. When I … Continue reading →
We’ve seen how to get a single zip code and display it in a series of labels. Let’s use a collection to take a look at how we might deal with that in MAUI. To get started, we’ll create a … Continue reading →
Our app will spring to life in AppShell.xaml. We’ll be putting a few additional things there, but key for now is the ShellContent element As you can see there are three attributes: the Title, the ContentTemplate and the Route. The … Continue reading →
As noted in part 0, I assume you are a Xamarin.Forms/C# programmer, familiar with Visual Studio. This series is not about converting your existing Xamarin.Forms apps; rather it is about converting your brain to MAUI. Since I’m learning as I’m going, your mileage … Continue reading →
As noted in part 0, I assume you are a Xamarin.Forms/C# programmer, familiar with Visual Studio. This series is not about converting your existing Xamarin.Forms apps; rather it is about converting your brain to MAUI. Since I’m learning as I’m … Continue reading →
Programming is not easy. It is made particularly difficult by legitimate statements such as these from a Xamarin.Forms project: This can be followed by If the first line doesn’t kill you then the last ones will.
I’m going to start a serious attempt to upgrade my skills from Xamarin.Forms to Maui. I’m not sure how difficult this will be, but I’m starting with James Montemagno’s excellent video/code course for beginners. Unfortunate for me, and perhaps for … Continue reading →
Incredibly pleased to have one of the pioneers in Agile programming: Robert “Uncle Bob” Martin. Uncle Bob is known for, among other things, his SOLID principles of development. He is the author of the seminal book Clean Code along with … Continue reading →
I expect most people my age have had great ideas they never patented. I’ll list a few here just to make myself feel better and to encourage you to post yours (these are ideas that are already patented or can’t … Continue reading →
I’m joined by James Montemagno, Principal Lead Program Manager for .NET Community at Microsoft, and the most enthusiastic person I know. James is the author of the .NET Presentations – .Net Maui In A Box, among many other things. You … Continue reading →
.visx files are magic as far as I’m concerned. Mads takes us through their history and how they have become much easier to create. vsixcookbook.com Yet Another Podcast is available wherever you get your podcasts.
Part 1 of Being a Visual Studio Champ – is now on video! This is a 3 part conference streaming from Denmark and world-wide. vschamp.com Do not miss the next one on Add-ons with (among others) Mads Kristensen. April 27, … Continue reading →
I love Visual Studio 2022. I spend all my work day in it. It is by far the best IDE I’ve ever worked with. Each iteration gets better, with amazing features. But I’m greedy, so here are some features I … Continue reading →
Jon Galloway comes on Yet Another Podcast to talk about… well, a lot of stuff. ASP.NET Core Minimal APIs .NET Upgrade Assistant Upgrading from ASP.NET MVC 5 to .NET 6 Upgrading Windows Forms to .NET 6 Upgrading WPF to .NET … Continue reading →
In this post we will examine one of the aspects of advanced databinding that many people find confusing. Binding . (that is, Binding dot). However, it is surprisingly easy to explain. Binding . allows you to access the entire binding … Continue reading →
Bill Wagner joins us once again, this time to talk about C# 10 and the evolving Microsoft. documentation. Check back here for links but I just couldn’t wait to publish this.
You want to bind to a collection of values and display each in turn, but it is possible that some of the objects in the list have null properties, or some properties are missing altogether. You can handle this with … Continue reading →
In the ugly old days, if you had data that you wanted to display you would put the data into a variable and then write some code to copy that data to a control on your page. If the data changed, your code had to update the display. If you had a list of data, you had a bit of code to write to get each item in the list displayed in turn.
Xamarin.Forms provides Databinding to do all that work for you. Essentially you say “here’s my data and I want it in this UI element over here. If the data changes, update the display for me.” Even better you can say “here is a collection of objects, and here is how I want you to display properties from each one in turn and if something is added to or taken from the collection, adjust the list accordingly.
“Databinding” is well named: you bind your data to a control, and as the data changes, that change is reflected in the control.
Note: In all our examples we explain only the parts that are relevant to Databinding. For more on XAML, search through this site, or check out the Microsoft documentation.
Binding to a property In the simplest case you want to bind to a single property in your code-behind. In that case, create the property
``` private string _welcomeText = "Welcome to Basic DataBindings!"; public string WelcomeText { get { return _welcomeText; } set { _welcomeText=value; } }
```
Now we’re going to add a label to the xaml page, but we’re going to tell that label to get its text from the property we just created
```
```
That really is all there is to databinding. You mark your Xaml that you want its Text to be from the property WelcomeText in the object you’ve set as the binding context.
Binding Context The binding context is nothing more than telling the UI where to get its data (typically a class — either the code-behind as we’ve done here, or in a View Model as you should.).
There are a couple ways to set the binding context. One is to set it directly in the constructor of the code behind, another and recently preferred approach is what we do in our example: set it in the Xaml.
```
```
I’ve set the binding context to the Bookstore class in the model folder. We’ll set all that up below.
Binding Mode Normally, your binding is from your source (the property) to the target control. But sometimes you want your data to go the other way (for example when the user is filling in a form).
```
```
With two way binding the user’s entry will be put in the Property. Here I used a placeholder, but you are free to initialize the Entry with a value and then replace that value with whatever the user enters.
There actually are a number of modes, but these are the two you’ll use 90% of the time.
Collections To show this, we need a bit of setup. I’ll create a folder named Model and in it create a class Book.
``` public class Book { public string Name { get; set; } public string Author { get; set; }
}
```
In the same file (because I’m lazy) I’ll create a class Bookstore, and stock it with a collection of three books.
```
public class BookStore
{
public string StoreName { get; set; }
public List
new Book
{
Name= "In Search of Lost Time",
Author="Proust",
}
};
Books = booksInStock;
}
}
```
With that data source, we’re ready to tell Xaml how to display each one.
Template In manufacturing you set up a template of what you want and then stamp them out one after the other. The same is true with databinding the contents of lists. We’ll set up how we want to display each book, and then feed the list to the list control and it will stamp out each item.
(Normally, I’d put the list data (the bookstore) in a ViewModel, but our focus here is on binding, not MVVM)
```
```
The first thing we see is the BindingContext being set.
Next we have our content, starting with a label that displays static text, the word Hello
Following that, we have our simple databinding as shown above, this time setting the text to whatever is in the property StoreName.
Now the fun begins. We declare a ListView element and set its ItemsSource to a list of objects; in this case the Books collection. Each member of that collection is a Book, and each Book has the properties Name and Author. These are the properties we want to display.
I think of it this way: the ListView takes one object off the collection at a time. In this case it is a Book. The template tells us which properties of that object to display.
The result is a list displaying the name and author (and because we are using a TextCell, the author is being treated as a detail.
Excelsior! With what you’ve seen here, you are ready for the rest of our series on Advanced Data Binding. The first in that series is here.
More about databinding from Microsoft here
Source Code here
Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen Pluralsight & LinkedIn Learning courses. He was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Xamarin Certified Mobile Developer and a Xamarin MVP and a Microsoft MVP.View all posts by Jesse Liberty →
Rodrigo Juarez is a full-stack and Xamarin Certified Mobile Professional developer. His mission is to solve complex problems for his clients focusing on the results, applying the most adequate technology available and best practices to ensure a cost-effective and high-quality solution. He has 20+ years of experience in a wide variety of projects in the development of applications for web, desktop and mobile using Microsoft technologies in areas such as management, services, insurance, pharmacy and banks. He can be reached at Rodrigo Juarez
En Español
There are times when you need to bind to a source but the source is not in the right format or otherwise needs to be manipulated.
For example, suppose, as we’ll show below, that you have a text entry and a button, but you only want the button enabled as long as there are one or more characters in the text entry, and of course if there is no text entered you want to disable button.
You could bind the button to a boolean property in your View Model and bind the text to another property and then on text changed you could test to see if there is text in the entry control and update the button. Yuck.
Value Converters For example, since “IsEnabled takes a boolean and the number of characters is an int, you need a way to convert that int into a bool. That is where value converters enter the picture.
The standard format for a value converter is
Note that frequently you won’t need ConvertBack. In that case, implement it to return null or to throw a NotImplemented exception.
Our converter is pretty common. Since we want to convert an int to a bool, we’ll use the clever name IntToBoolConverter.
Next, we implement the first method, Convert
``` public class IntToBoolConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return (int)value!=0; }
```
And for ConvertBack we’re going to say if the value is true, return 1 otherwise return 0
``` public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return (bool)value ? 1 : 0; }
```
Using the Converter Our test code is as simple as can be. We have an entry which has no text in it, and a button whose IsEnabled value depends on binding to that control, but converting the int (how many characters) to a bool (enable or not).
We start by creating a ResourceDictionary, in this case at the top of the XAML page (which is very common for resources you are only going to use on one page)
```
```
Note: For resources you are going to use on many pages, you will want to put the resource in a ResourceDictionary in app.xaml. You will access it in exactly the same way as all the ResourceDictionaries in a project are merged at compile time.
Notice that we’ve assigned a key to the converter, this allows us to use the key in the XAML.
```
```
The Entry does not know about the converter, but the button does: specifically its IsEnabled property binds to the Entry (by name) and sets the Path to the text.length (how many characters). For more on Binding Paths, please see Part 1 of this series: Paths.
Finally the IsEnabled binding invokes the converter. This will pass in the number of characters and if it is not zero it will return true (and enable the button), otherwise it will return false (and disable the button).
That’s all there is to it.
Note that this particular converter is so common that it is provided as part of the Xamarin Community Toolkit, which along with dozens of other very useful things, provides a number of common converters such as EnumToIntConverter, InvertedBoolConverter (change false to true and vice versa) and many others. You can find the Xamarin Community Toolkit here
Find out more about converters in the Microsoft Docs, here
Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen Pluralsight & LinkedIn Learning courses. He was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Xamarin Certified Mobile Developer and a Xamarin MVP and a Microsoft MVP
Rodrigo Juarez is a full-stack and Xamarin Certified Mobile Professional developer. His mission is to solve complex problems for his clients focusing on the results, applying the most adequate technology available and best practices to ensure a cost-effective and high-quality solution. He has 20+ years of experience in a wide variety of projects in the development of applications for web, desktop and mobile using Microsoft technologies in areas such as management, services, insurance, pharmacy and banks. He can be reached at Rodrigo Juarez
Note, this is the 1,300th post on this site!
.
This is the first in a series on advanced data binding. In this series we will look at: using value converters with binding, relative binding, the {Binding .} and {Binding self} constructs, and more.
We hope to release one of these every week or two.
Getting Started We will be posting Part 0 shortly.
Samples For each topic we discuss, we will provide a simple sample (as simple as possible but no simpler) which we’ll put up on Github and we’ll provide the URL in the blog post. We will walk through that sample to eliminate any confusion and to drive home what we’ve said about the topic.
Some of the samples we’ll make up for this series, others we’ll steal from the Microsoft documents. Which reminds me, why would you read this instead of the official documents? The answer, for me, is that the Microsoft documents are very thorough, but sometimes that can be overwhelming. Most important, however is that triangulating from multiple sources can help zero in on a full understanding.
Topic #1: Paths The use of the path keyword is a good, intermediate place to start. It can be used in a number of ways. The most frequent is either to point to a property of an object held in a resource, or to point to a property of a property.
Example Here is an example we can take apart. To create this example, I opened VS22 and created a new cross platform (Xamarin.Forms) application. This gave me MainPage.xaml and MainPage.xaml.cs which for this simple example is all we need.
I will leave MainPage.xaml.cs alone, and do all the work in MainPage.xaml. All of the use of path in this example will be declarative.
Here is the complete example:
```
<StackLayout Margin="10,50">
<TimePicker x:Name="timePicker" Time="17:05" />
<Label Text="{Binding Source={x:Reference timePicker}, Path=Time.TotalSeconds, StringFormat='{0} total seconds'}" />
<Slider
x:Name="slider"
BackgroundColor="DarkSlateGray"
Maximum="10"
Minimum="0"
ThumbColor="Red"
Value="4" />
<!-- Path and BindingContext set in the binding -->
<Label Text="{Binding Source={x:Reference slider}, Path=Value, StringFormat='The value of slider is {0}'}" />
<!-- Path as content property -->
<Label Text="{Binding Value, Source={x:Reference slider}, StringFormat='The value of slider is {0}'}" />
<!-- Path as content property & setting the binding context -->
<Label BindingContext="{x:Reference slider}" Text="{Binding Value, StringFormat='The value of slider is {0}'}" />
<Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture}, Path=DateTimeFormat.DayNames[3], StringFormat='The middle day of the week is {0}'}" />
</StackLayout>
```
The first step is to declare a TimePicker control named timePicker (the name will be important). We initialize its time to 17:05 (5:05pm).
We are now ready to access a property the TimePicker control, Time. But we don’t want that property, we want the subproperty TotalSeconds. No problem, we set the source to the TimePicker as a Reference using the name (timePicker) and then set the path to the subproperty we are interested in. We can then make use of the StringFormat clause to display the total seconds
Using path to capture a sub-property In the second part of this example,we declare a slider, and set a few attributes, including initializing its value to 4. We are now ready to access the slider and its value. If you have setup INotifyPropertyChanged, as you move the slider the value in the Label will be updated.
Tying the label to the value of the slider Notice that in the next part (Path as Content Property) we bind to the Value and then provide the source, and do not have to make the implied path explicit. That is, we could write
```
```
But in this case, the path is redundant.
We then see the option to set the BindingContext explicitly to the slider, and then we can continue to bind to the value .
The short story here is that there are a number of ways to set the (implicit or explicit) binding context (see Post 0)
In the final part of this example, we bind to the CurrentCulture which allows u to use an indexed path. Study this one a bit, it is not intuitive that you can do this.
The complete example Future posts will be a bit more complex and/or advanced, but we wanted to start out easy.
Additional documentation about binding path can be found here.
The source code for this example (and all examples in this series) can be found here.
This blog post and sample was written (as all will be) by Rodrigo Juarez and Jesse Liberty. Spanish translation for this post can be found here.
Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen Pluralsight & LinkedIn Learning courses. He was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Xamarin Certified Mobile Developer and a Xamarin MVP and a Microsoft MVP.
Rodrigo Juarez is a full-stack and Xamarin Certified Mobile Professional developer. His mission is to solve complex problems for his clients focusing on the results, applying the most adequate technology available and best practices to ensure a cost-effective and high-quality solution. He has 20+ years of experience in a wide variety of projects in the development of applications for web, desktop and mobile using Microsoft technologies in areas such as management, services, insurance, pharmacy and banks. He can be reached at Rodrigo Juarez
This knocked me out. Let’s say you have a value in one view model, and when you navigate to another page you want that value in the new page’s view model. Enter IQueryAttributable. (tough to say, even tougher to spell)
I have created a simple example. We’re going to start with an out of the box Xamarin.Forms project. As part of that we’ll get an AboutPage. At the bottom of the about page I’m going to add a button:
```
```
Nothing surprising here. Let’s follow that ShowIdCommand. For that we turn to the associated view model (also out of the box)
I’m going to add important data to the code behind: in this case an id whose value is “123”
I’m then going to add the Command ShowIdCommand which will invoke the ShowId method
``` private string id = "123";
public AboutViewModel() { Title="About"; }
private ICommand _showIdCommand;
public ICommand ShowIdCommand => _showIdCommand??(_showIdCommand= new Command(async param => await ShowId()));
```
(Note that I’ve removed the OpenWebCommand that normally comes with this file to keep things uncluttered.)
Now comes part one of the magic. I’ll use Shell navigation to go to a new page, but I’ll pass in the Id as a paramter. Note, I can name that parameter anything I like, in this case I’ll name it QueryId
``` protected async Task ShowId() { await Shell.Current.GoToAsync($"{nameof(MyNewPage)}?QueryId={id}"); }
```
We travel now to MyNewPage, but not to the code behind (yuck) but rather to the view model (yay!)
The first requirement is that you mark your view model as implementing IQueryAttributable
Next, create a local property Id. This you will fill from the parameter you passed in. To do that (and to fulfill the IQueryable interface) you add a method named ApplyQueryAttributes. This method’s parameter will be a dictionary which will be provided for you by magic. You do not have to fill the dictionary.
```
public void ApplyQueryAttributes(IDictionary
```
We simply check to see if the dictionary has a key matching the key we sent as a parameter, and if so we can extract the value (Id) and do whatever we like with it (in this case, I’m stashing it away in a local field). You can, of course, check for as many parameters as you like.
I was so impressed by this I had to tell you.
Lance McCarthy talking about Maui, VS2022, community contributions and much more.
http://jesseliberty.com/wp-content/media/Show203.mp3 Referenced sites and source:
Resource 1 – CommonHelpers
That is the CommonHelpers NuGet package I was referring to. It not only is a good helper in a .NET project, but you can also look at it’s GitHub Actions to see how to automatically built, test and publish to NuGet.
Resource 2 – DevOpsExamples
That repo shows you how to build WPF, ASP.NET Core, WinForms, Console, Xamarin.Forms, .NET MAUI, Angular, React and Vue projects in GitHub Actions, Azure DevOps, GitLab CI and AppCenter (see the build status badges here).
The workflows can be found here https://github.com/LanceMcCarthy/DevOpsExamples/tree/main/.github/workflows
Resource 3 – MediaFileManager a real-world CI-CD example for WPF
This repo is for MediaFileManager, one of my real-world WPF apps that is published to the Microsoft Store. It shows you how to use GitHub Actions to automatically build MSIX packages and publish to the Microsoft Store.
Not only does it build and upload to the Store, but I also show how to build an msixbundle with an appinstaller file that gets uploaded to Azure Blob Storage so you can host your own mini-Microsoft Store for your non-Store users. Check out the mini-store page here Media File Manager (windows.net)
Resource 4 (bonus) – AI Powered Toilet Flusher for my Cat
I built a full system that uses AI, SignalR, Windows IoT, and Xamarin.Forms to automatically flush the human toilet when my cat uses it. You can see the companion blog post here Using Windows IoT, SignalR, Azure Custom Vision and Xamarin Forms to Flush a Toilet – DVLUP
Mads Kristensen talks about all the goodness in Visual Studio 2022
http://jesseliberty.com/wp-content/media/Show202.mp3
Here are 12 utilities I use every day. They are in no particular order. I spend most of my day programming in Visual Studio 2019.
NB: I’ve received free copies of some of these as a Microsoft MVP. But only because I asked, which I did only because I thought they were great.
Mads comes back on show 200 (!) to talk about all things C# 10, which will be released November 2021.
http://jesseliberty.com/wp-content/media/Show200.mp3