4 October 2019

Regular Avalonia

Programming.NETC#Development for LinuxDevelopment for Windows
Sometimes we don’t understand how the regular expression that we have composed works and want to check. There are many applications like regex101.com or vs code. I wanted to add one more to this list.

In this article we will see how you can wrap Regex in cross-platform graphics and create a simple application for testing regular expressions.


To create a project using avalonia ui, you need to install the templates from GitHub .
And create a project from the mvvm template.

 dotnet new avalonia.mvvm -o MyApp 

Design and layout

To create the main window, place all the components inside the grid.

            <RowDefinition Height = "5" />
            <RowDefinition Height = "Auto" />
            <RowDefinition Height = "5" />
            <RowDefinition Height = "*" />
            <RowDefinition Height = "5" />

Our application consists of 2 parts: the upper analogue of the toolbar and the workspace.

Consider the top

Here we have a field for a regular expression, a checkbox showing how to analyze the text (line by line or as a whole fragment) and a help button.

We use Dock panel as container. This control allows you to easily fill the container with elements, pressing them to different sides and ensuring no free space inside.

 <DockPanel Grid.Row = "1"> 

And fill it with a text input field:

 <TextBox Margin = "5, 0, 5, 0" Watermark = "Your regexp" AcceptsReturn = "False" Text = "{Binding RegText}" /> 

Here it is worth noting a pleasant trifle for Avalonia ui — the presence of watermark in text fields.

Add a checkbox with 2 states to the panel, as indicated by IsThreeState = «False» :

 <CheckBox DockPanel.Dock = "Right" Content = "By row" IsThreeState = "False" IsChecked = "{Binding IsChecked}" ToolTip.Tip = "Check for each row" /> 

And the button responsible for calling the help:

 <Button DockPanel.Dock = "Right" Content = "?" Margin = "5, 0, 5, 0" ToolTip.Tip = "Show hints" Command = "{Binding ShowHelp}" / > 


The main part will be placed in the grid:

 <Grid Grid.Row = "3">
                <ColumnDefinition Width = "*" />
                <ColumnDefinition Width = "Auto" />
                <ColumnDefinition Width = "0.75 *" />

The input field is represented by the text box:

 <TextBox Grid.Column = "0" AcceptsReturn = "True" ScrollViewer.VerticalScrollBarVisibility = "Auto" Text = "{Binding InputText}" /> 

The splitter allows you to choose a convenient visualization for your needs:

 <GridSplitter Grid.Column = "1" /> 

And the field responsible for displaying the result of applying regular expressions will be placed in the border because the text block does not have its own frame:

 <Border BorderBrush = "Gray" BorderThickness = "1" Grid.Column = "2">
                <TextBlock ScrollViewer.VerticalScrollBarVisibility = "Auto" Text = "{Binding OutputText}" />

Help window

To create a new window, let's turn to the terminal

 dotnet new avalonia.window -na MyApp -n MyNewWindow 

This window will contain only information and nothing else, so, ignoring the containers, make the listbox as achild of this window:

 <ListBox ScrollViewer.VerticalScrollBarVisibility = "Visible" VirtualizationMode = "None">

And fill it with the same elements as needed:

            <StackPanel Orientation = "Horizontal">
                <TextBlock Margin = "5" Text = "A single character of: a, b or c" />
                <TextBlock Margin = "5" Classes = "green" Text = "[abc]" />

The layout is quite simple: a stack panel with 2 fields, the only thing worth mentioning here is the Classes attribute, which allows us to stylize our windows like css (another nice feature of Avalonia.)

And actually paint the rules themselves in green:

        <Style Selector = "TextBlock.green">
            <Setter Property = "Foreground" Value = "Green" />

Mvvm functionality

First, let's take care of the fields for all the markup elements:
 private bool _isChecked;
private string _inputText;
private string _regText;
private string _outputText; 

Let's create methods that will return the results of the match with the original text:

 private void SetNoRowResult ()
            OutputText = string.Join (Environment.NewLine, new Regex (_regText) .Matches (_inputText));

And with the source text along the lines, for which we use Split
 private void SetRowResult ()
            var r = new Regex (_regText);
            var s = string.Empty;
            foreach (var line in _inputText.Split (Environment.NewLine, StringSplitOptions.RemoveEmptyEntries))
                s + = $ "- {Environment.NewLine}";
                s + = string.Join (Environment.NewLine, r.Matches (line));
                s + = $ "{Environment.NewLine} - {Environment.NewLine}";

            OutputText = s;

And add a method that displays the help window

 public void ShowHelp ()
            new HelpWindow (). Show ();

Properties and Bindings

An interesting feature of Avalonia is the ability to attach a method directly to a button:

 <Button Command = "{Binding ShowHelp}" /> 

Which we will use.

For others fields, we simply bind to the properties. An interesting feature here is that in avalonia, binding updates occur when the content of the control changes, which was done in the wpf: UpdateSourceTrigger = PropertyChanged in avalonia works by default.

And since the Avalonia mvvm template is included the Reactive UI, the properties are created using this library:

 public string RegText
            get => _regText;
                this.RaiseAndSetIfChanged (ref _regText, value);
                if (_isChecked) SetRowResult ();
                else SetNoRowResult ();

In conclusion

I hope that this article will be of interest not only to those who want to use my material and / or somehow improve it, but also to all those who are familiar with Avalonia or are looking for ways to create cross-platform applications in C#.

Source code ( here).

I would like to say thanks ForNeVeR kekekeks worldbeater
Hubs: Programming .NET C# Development for Linux Development for Windows
971 2
Leave a comment
Popular right now
Top of the last 24 hours