Zoom Rectangle with OxyPlot

Let’s stick to OxyPlot for some more time. This time, we would attempt to change the color of Zoom Rectangle. For those who are new to Oxyplot, the control allows you to zoom in a particular location by permitting the user to draw rectangles in the graph. This particular rectangle is known as Zoom Rectangle.

You can enable the Zoom Rectangle by using the PlotController.

public PlotController ChartController { get; set; }

ChartController = new PlotController();
ChartController.BindMouseDown(OxyMouseButton.Left, PlotCommands.ZoomRectangle);

You can now bind the PlotController with your OxyPlot PlotView instance in XAML.

<oxy:PlotView Model="{Binding Model}" Controller="{Binding ChartController,UpdateSourceTrigger=PropertyChanged}"/>

While would enable the Zoom Rectangle, you would ideally would like to do a bit of Customization, for example, changing the appearance(color) of the rectangle.

You can do so by customizing the ZoomRectangleTemplate. Let’s change the default color of the Zoom Rectangle we just created.

<oxy:PlotView Model="{Binding Model}" Controller="{Binding ChartController,UpdateSourceTrigger=PropertyChanged}">
<oxy:PlotView.ZoomRectangleTemplate>
<ControlTemplate>
<Border BorderBrush="Black" BorderThickness="1">
<Rectangle Fill="Orange" />
</Border>
</ControlTemplate>
</oxy:PlotView.ZoomRectangleTemplate>
</oxy:PlotView>

That’s all you need. You now have your fully customized Zoom Rectangle.

Oxyplot

Shaders with HLSL #03: Passing Additional Parameters

In previous parts of this series, we briefly discussed the need for Shaders and created our first Shader Program. In this subsequent part, we would be exploring on passing additional parameters to our Custom Shader.

In previous example, we replaced entire color of applied Control with a single color. What if we need to replace only certain colors, among different colors in the control. We would then need to pass the ‘color to replace’ and ‘new color’ to the Shader.

Step 01 : The Shader

Let’s write our Shader, again with HLSL. We will delve into details soon.

sampler2D input: register(s0);
float4 oldColor : register(c0);
float4 newColor : register(c1);

float4 main(float2 uv:TEXCOORD) : COLOR
{
float4 color = tex2D(input, uv);
if (color.r == oldColor.r && color.b == oldColor.b && color.g == oldColor.g)
{
return newColor;
}
return color;
}

We now have two additional parameters defined in the Line 2 & 3. While it follows the earlier parameter declaration, there is an important difference. For additional (non-image) parameters, we are using the C series registers, which are, as discussed in last post, floating point registers. We have two parameters, both of type float4, which would hold details of ‘old color‘ and ‘new color‘.

float4 oldColor : register(c0);
float4 newColor : register(c1);

In the first line of our main function, we see a new function, which we haven’t seen in previous example.

float4 color = tex2D(input, uv);

tex2D is a texture sampling intrinsic function, which generates a vector from its a sampler and a float2, which holds the two-dimensional texture cordinates at which the sampler is to be sampled. The cordinates (u and v), ranges from (0,0) to (1,1) as one moves from top-left to bottom-right.

In the subsequent code, which is self-explanatory, we compare the RGB values to decide whether we need to replace the color.

Step 02 : The ShaderEffect Class

Having written our Shader, the next obvious step is create our custom class derieved from ShaderEffect. Like in Shader code, we will write the code first and then explore the details.

public class ReplaceColorEffect : ShaderEffect
{
public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(ReplaceColorEffect), 0);
public Brush Input
{

get => ((Brush)(GetValue(InputProperty)));
set => SetValue(InputProperty, value);
}

public Color OldColor
{
get { return (Color)GetValue(OldColorProperty); }
set { SetValue(OldColorProperty, value); }
}

public static readonly DependencyProperty OldColorProperty =
DependencyProperty.Register("OldColor", typeof(Color), typeof(ReplaceColorEffect), new PropertyMetadata(Colors.Black,PixelShaderConstantCallback(0)));
public Color NewColor
{
get { return (Color)GetValue(NewColorProperty); }
set { SetValue(NewColorProperty, value); }
}

public static readonly DependencyProperty NewColorProperty =
DependencyProperty.Register("NewColor", typeof(Color), typeof(ReplaceColorEffect), new PropertyMetadata(Colors.Black, PixelShaderConstantCallback(1)));

public ReplaceColorEffect()
{
PixelShader pixelShader = new PixelShader();

pixelShader.UriSource = new Uri(@"E:\App Store\GitHub\anuviswan\LearningPoint\Shaders\ShaderExample001\Shader\ReplaceColor.ps", UriKind.Absolute);

PixelShader = pixelShader;
UpdateShaderValue(InputProperty);
UpdateShaderValue(OldColorProperty);
UpdateShaderValue(NewColorProperty);

}
}

While most of the code is pretty similiar to code in our previous example, ones that needs more attension is discussed below. The most significant difference is the two additional parameters, which are mapped to floating point registers (c registers) and how it is defined in C# code.

public Color OldColor
{
get { return (Color)GetValue(OldColorProperty); }
set { SetValue(OldColorProperty, value); }
}

public static readonly DependencyProperty OldColorProperty =
DependencyProperty.Register("OldColor", typeof(Color), typeof(ReplaceColorEffect), new PropertyMetadata(Colors.Black,PixelShaderConstantCallback(0)));

As observed in the code above, the declaration of dependency properties for c-registers are in the more familiar & conventional syntax, using the DependencyProperty class. What makes it different from normal dependency properties is the PixelShaderConstantCallback parameter of PropertyMetadata class. This tells the compiler that this is a special Dependency property which needs to be mapped to c-registers when communicating with the Shader application.

Rest of the code is pretty self-explanatory and XAML is no different than ones you might have seen countless times, using the dependency properties.

<shadereffects:ReplaceColorEffect OldColor="Red" NewColor="Green"/>

Hit F5 and you can now see your Shader in action. For complete code discussed in this series, please refer to my Github.

Complete Shader with HLSL Series

SharedSizeGroup: Managing Column Size across Grids

SharedSizeGroup is an underused WPF attribute, but one that can make life lot more easier when design WPF forms with multiple Grids that need to share a column size. Consider the screenshot below. The three pairs of Label and Textbox are in separate grids (with column width set to auto), resulting in an unorganized layout. It would far more better if the column width of first grid resizes itself to width of column in second grid.

Without SharedSizeGroup

You might often have to design more complex scenarios where you would love to retain the column size across Grids. This is where SharedSizeGroup comes into play. Let’s redefine our XAML with the attribute.

<Grid Margin="10,10,10,10">
        <StackPanel Grid.IsSharedSizeScope="True">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" SharedSizeGroup="ABC"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="Name"></TextBlock>
                <TextBox Grid.Column="1"/>
            </Grid>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" SharedSizeGroup="ABC"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="Full Name"></TextBlock>
                <TextBox Grid.Column="1"/>
            </Grid>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" SharedSizeGroup="ABC"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="Last Name"></TextBlock>
                <TextBox Grid.Column="1"/>
            </Grid>
        </StackPanel>
    </Grid>

 
Now the layout looks better organized.

With SharedSizeGroup

Caliburn.Micro #006 : Event Aggregators & Window Managers

Consider the classic scenario when you need to show the currently logged in User Name in your main Window, once you have successfully logged in. The The login Window is supposed to be a Modal Dialog, and isn’t remotely aware of the Label displaying Username in the Main Window.

WPF handles Modal Dialogs and messaging service between Views using Window Managers and Event Aggregators.

Event Aggregators allows a loosely coupled message parsing mechanism between different View Models in the system. As the Caliburn Micro Documentation states, an Event Aggregator is a service that provides the ability to publish an object from one entity to another in a loosely based fashion.

Let’s being by creating our Sample Application using the Caliburn.Micro Template Pack, which makes it easier to kick start a Caliburn.Micro based application. The complete sample code described in this post is available in Github.
Capture

 

We would be using MEF as our IoC Container. So let’s make changes to Bootstrapper to accommodate MEF. For sake of ease, we will remove the existing Bootstrapper and add MEF Template supplied along with the Caliburn.Micro Template Pack.

 

Capture1
We will now our Contract Interface and the required LoginView as well as our MainWindow (we will it ShellView). The skeleton of code looks like following now.
ShellView.Xaml
 <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
        </Grid.RowDefinitions>
        
        <StackPanel Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Label x:Name="UserName" FontWeight="Bold" FontSize="32"></Label>
        </StackPanel>
        
        <StackPanel Grid.Row="1" Margin="10,10,10,10">
            <Button Margin="5,5,5,5" cal:Message.Attach="[Event Click]=[Action PromptForLogin]">Login</Button>
        </StackPanel>
    </Grid> 

IShell Interface

    public interface IShell
    {

    }

ShellViewModel

  [Export(typeof(IShell))]
    public class ShellViewModel : PropertyChangedBase, IShell
    {
        private string _userName  = default;
        public string UserName
        {
            get => _userName;
            set
            {
                _userName = value;
                NotifyOfPropertyChange(nameof(UserName));
            }
        }

        public void PromptForLogin() {};

    }
We will add the skeleton code for Login Window as well before adding the code to invoke it as a separate Window (not Content Control).
LoginView.Xaml
 <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"></RowDefinition>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition Height="20"></RowDefinition>
        </Grid.RowDefinitions>
        
        <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Center" Background="Lavender">
            <Label>User Login</Label>
        </StackPanel>
        <TextBox Margin="5,5,5,5" Grid.Row="1" Name="UserName">UserName</TextBox>
        <TextBox Margin="5,5,5,5" Grid.Row="2" Name="Password">Password</TextBox>
        <Button Grid.Row="3" Margin="5,5,5,5" cal:Message.Attach="[Event Click]=[Action Validate(UserName,Password)]">Login</Button>
    </Grid>

ILogin Interface

public interface ILogin
{
    bool Validate(string userName, string passWord);
}

LoginViewModel

[Export(typeof(ILogin))]
public class LoginViewModel : ILogin
{
    // Since this is a demo, we will always return true
    public bool Validate(string userName, string passWord) => true;

}

Alright, so we have our barebone code ready. Time to link up the chain. The first task is to ensure we have ShellView as our primary start up Window, which we set by altering the code in our Bootstrapper.

protected override void OnStartup(object sender, StartupEventArgs e)
{
    DisplayRootViewFor();
}

The next task is to ensure the Login Window User Clicks Login Button. We do this by utilizing the Window Manager, which is injected (via Dependency Injection) into ShellViewModel. We will add a constructor for ShellViewModel decorated with the ImportingConstructor Attribute. We will also inject LoginViewModel as well in to the class. We will then use the WindowManager for invoking the LoginViewModel as a Modal Dialog. Our constructor and PromptForLogin Method looks like following now.

[ImportingConstructor]
public ShellViewModel(IWindowManager windowManager,ILogin loginWindow)
{

}

public void PromptForLogin() => _windowManager.ShowDialog(_loginWindow);

This opens up the Login Window for you. All good till now, the Login Window is displayed, and you type in the UserName & Password, and Click the Login button to invoke the Validate Method. But how do you pass the UserName information to the ShellViewModel ? This is where Event Aggregator comes into place.

Event Aggregators allows ViewModels to pass (broadcast) information (in a model) to any other View Models who has subscribed to the event. We will begin by creating the model which would contain the information that will passed along Event Aggregators.

public class UserInfoModel
{
     public string UserName { get; set; }
}

We will then inject an instance of EventAggregator in the LoginViewModel. We will also modify our Validate Method a bit. The LoginViewModel class now looks like following.

[Export(typeof(ILogin))]
public class LoginViewModel : ILogin
{
private IEventAggregator _eventAggregator;

[ImportingConstructor]
public LoginViewModel(IEventAggregator eventAggregator)
{
    _eventAggregator = eventAggregator;
    _eventAggregator.Subscribe(this);
}

// Since this is a demo, we will always return true
public bool Validate(string userName, string passWord)
{
    _eventAggregator.PublishOnUIThread(new UserInfoModel(){UserName = userName});
    return true;
}
}

As you can see, we have used the PublishOnUIThread Method of Event Aggregator to publish the UserInfoModel object to anyone listening. We will now move to our ShellViewModel and ensure the class is listening. We would also see how we access the message send by the Login View Model.

Let’s begin by modifying the ShellViewModel to inject the EventAggregator to ShellViewModel, Our constructor now looks as following.

[ImportingConstructor]
public ShellViewModel(IWindowManager windowManager,ILogin loginWindow, IEventAggregator eventAggregator)
{
    eventAggregator.Subscribe(this);
    windowManager.ShowDialog(loginWindow);
}

Now comes the most important part, we need to implement the IHandle interface, where T is the model of the event object, which in our case is UserInfoModel. The interface contains a single method Handle, which we implement soon. Prior to that, this is how our class declaration looks now.

public class ShellViewModel : PropertyChangedBase, IShell, IHandle

The Handle Method of IHandle Interface looks like following.

public void Handle(UserInfoModel message)
{
this.UserName = message.UserName;
}

As you can see, we have assigned the UserName property of ViewModel from the message passed by the EventAggregator. That’s all we need to do. The EventAggregator has passed the message to all subscribers in the message bus for that particular event model. We then capture the message by implementing the Handle Method in IHandle interface.

Caliburn.Micro

Caliburn.Micro is a extremely lightweight MVVM Framework. This series provides an introduction/refresher to developing WPF applications with Caliburn.Micro
1. Caliburn.Micro: Introduction
2. Caliburn.Micro: Bindable Collections & Events
3. Caliburn.Micro: Events (Short Hand Syntax)
4. Caliburn.Micro:Bootstrapper with SimpleContainer
5. Caliburn.Micro: Bootstrapper with MEF
6. Caliburn.Micro: Event Aggregators & Window Managers
7. Caliburn.Micro: Bootstrapper with Unity
8. Caliburn.Micro: Gesture Recognition using Short-Hand Syntax

 

Caliburn.Micro #005 : Bootstrapper with MEF

Previously, we learnt how to use SimpleContainer to set up our IoC Containers. We would be now looking into making the application more loosely coupled by leveraging the MEF. Just like with SimpleContainer, we would be focusing on the basic steps while configuring the IoC – Registering the IoC Container with Caliburn Micro and then registering the Service bindings. Let’s go ahead override the necessary methods

private CompositionContainer _Container;

protected override object GetInstance(Type service, string key)
{
  string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(service) : key;
  var exports = _Container.GetExportedValues(contract);
  if (exports.Any())
      return exports.First();
  else
      throw new Exception("Could not find the key");
}

protected override void BuildUp(object instance)
{
  _Container.SatisfyImportsOnce(instance);
}

protected override IEnumerable GetAllInstances(Type service)
{
  return _Container.GetExportedValues(AttributedModelServices.GetContractName(service));
}

We will now go ahead and register our Service Bindings. This is where things get interesting.

protected override void Configure()
{
  _Container = new CompositionContainer(
                new AggregateCatalog(AssemblySource.Instance.Select(x=> new AssemblyCatalog(x)).OfType())
                );
  var batch = new CompositionBatch();
  batch.AddExportedValue(new WindowManager());
  batch.AddExportedValue(new EventAggregator());
  batch.AddExportedValue(_Container);

  _Container.Compose(batch);
}

As seen in the code above, we are using the AssemblySource to parse the ViewModels in the Assembly.

That’s it in Bootstrapper, but do not forget to decorate your View Model class with [Export()] Attribute and Constructor with [ImportingConstructor]. (For injecting dependency)

[Export(typeof(IReport))]
public class ReportViewModel :Screen, IReport
{
  [ImportingConstructor]
  publicReportViewModel(IEventAggregator EventAggregator)
  {
    // Do Constructor tasks
  }
}

We will delve into EventAggregators later, but for the moment, consider it an example of how to inject a dependency in the constructor when working with MEF.

Code sample for this post can be found here. The complete list of tutorials on Caliburn.Micro can be accessed here

 

Caliburn.Micro #004 : Bootstrapper with SimpleContainer

Let’s take a step back and look into our Bootstrapper in detail now. The first version of Bootstrapper we declared earlier is a rather simple one, without utilizing the some of the functionalities which takes Caliburn.Micro, or for that matter, any MVVM Framework ahead. The implementation of IoC Container.
We would be concentrating into two different IoC Containers – a Caliburn.Micro in-build container called SimpleContainer and the MEF (Microsoft Extensibility Framework) based Container. In this first part, we would be concentrating on the SimpleContainer. Let’s begin by declaring the interface contract for our Shell View Model.
  public interface IShell
  {

  }
I would leave the implementation of ShellViewModel and ShellView to the discretion of the reader, considering that is not what we are focusing on this particular session. We would instead focus on the Bootstrapper Class and how we would be triggering the ShellViewModel from it by utilizing the IoC container. We would however, write our OnStartup method, triggering the ShellViewModel through the IShell interface.
protected override void OnStartup(object sender, StartupEventArgs e)
{
  this.DisplayRootViewFor();
}
SimpleContainer
The first step is to configure the container with the Caliburn Micro Framework. We accomplish this by overriding 3 methods, the GetInstance, GetAllInstances and BuildUp.
private SimpleContainer _Container = new SimpleContainer();

protected override object GetInstance(Type service, string key)
{
  return _Container.GetInstance(service, key);
}

protected override IEnumerable GetAllInstances(Type service)
{
  return _Container.GetAllInstances(service);
}

protected override void BuildUp(object instance)
{
  _Container.BuildUp(instance);
}
Service Binding
Most of the code above are self explanatory. Having registered/configured your IoC Container with the framework, the next task is to register your contracts. We do this by overriding the Configure Method.
protected override void Configure()
{
  _Container.Instance(new WindowManager());
  _Container.Singleton();
  _Container.PerRequest();
}
Notice the three different methods we have used to register the service bindings. The Instance Method registers a pre-constructed instance with the type. This is similar to the Singleton method, however with a significant difference. The instance of Instance Method is pre-constructed while for the Singleton Method registration, the instance of Type is created only when first requested.
That’s it, the IoC container would now do the magic for us, by resolving the contracts when required.
There is another approach (method) to register the Service Binding, which focuses on auto-resolution of the Type by scanning the assembly for any implementation of the particular contract. For example, if we need to replace the service binding of IShell with assembly inspection, we would do the following.
 _Container.AllTypesOf(Assembly.GetExecutingAssembly());
In the next part of Caliburn.Micro Tutorial, we will look into implementing the IoC container with the more advanced, MEF based IoC Containers.
Sample code for this section can be found here. For complete list of tutorials on Caliburn.Micro, please follow this link