Dragging Shapes in Wpf

One of the projects I have in mind as my side-projects needs ability to drag-move shapes on a Canvas. I thought it would idea to explore the possibilities of achieving it via test projects first before starting the real one. So the goal of this article would be
* Create a Rectangle in a Canvas
* Support ability to Drag-move it within the Canvas boundary

Let’s begin by defining the basic UI including our Canvas and Rectangle. We would be using Caliburn Micro for supporting MVVM in the example.

<Canvas Grid.Row="2" Background="AliceBlue" >
<Rectangle Height="100" Width="100" Fill="Red" Canvas.Left="{Binding Left}" Canvas.Top="{Binding Top}" />
</Canvas>

Our ViewModel, at the moment looks like,

public class ShellViewModel:PropertyChangedBase
{
public double Left { get; set; } = 10;
public double Top { get; set; } = 10;
}

The Left and Top are double properties which will have the position of the Rectange with respect to the Canvas.

The next step is to capture the Mouse Position each time the User holds the Left Mouse Button down and drags the object. For this there are few things needs to be done. We need to detect when the Left Mouse Button is pressed down and released. Also, we need to trace the Mouse Position when the User holds the Left Mouse Down within the rectangle.

To detect the mouse position, we will write a Behavior.

public class MouseMoveBehavior:Behavior<Canvas>
{
public double MouseTop
{
get { return (double)GetValue(MouseTopProperty); }
set { SetValue(MouseTopProperty, value); }
}

public static readonly DependencyProperty MouseTopProperty =
DependencyProperty.Register("MouseTop", typeof(double), typeof(MouseMoveBehavior), new PropertyMetadata(0d));

public double MouseLeft
{
get { return (double)GetValue(MouseLeftProperty); }
set { SetValue(MouseLeftProperty, value); }
}

public static readonly DependencyProperty MouseLeftProperty =
DependencyProperty.Register("MouseLeft", typeof(double), typeof(MouseMoveBehavior), new PropertyMetadata(0d));

protected override void OnAttached()
{
AssociatedObject.MouseMove += AssociatedObject_MouseMove;
}

private void AssociatedObject_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
var currentPosition = e.GetPosition(AssociatedObject);
MouseLeft = currentPosition.X;
MouseTop = currentPosition.Y;
}

protected override void OnDetaching()
{
AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
}
}

The Behavior MouseMoveBehavior defines two Dependency Properties named MouseTop and MouseLeft indicating the X-Y cordinates of the mouse position. The behavior intends to capture the Mouse position using the MouseEventArgs.GetPosition and update the dependency properties with the Position.X and Position.Y values.

So, we have our behavior in place. Now is the time to update our Xaml to use our Behavior.

<Canvas Grid.Row="2" Background="AliceBlue" cal:Message.Attach="[Event MouseMove]=[Action MouseMove];
[Event PreviewMouseLeftButtonUp]=[Action MouseUp];[Event MouseLeave]=[Action MouseUp]" >
<i:Interaction.Behaviors>
<behaviors:MouseMoveBehavior MouseLeft="{Binding Left,Mode=TwoWay}" MouseTop="{Binding Top,Mode=TwoWay}"/>
</i:Interaction.Behaviors>
<Rectangle Height="100" Width="100" Fill="Red" Canvas.Left="{Binding Left}" Canvas.Top="{Binding Top}" cal:Message.Attach="[Event PreviewMouseLeftButtonDown]=[Action MouseDown]" />
</Canvas>

As you can observe, we are updating the Left and Top properties by capturing them in Behavior and assigning the the values of current mouse position. This would ensure the the shape would move along the mouse pointer.

But you want to update the Left and Top position only when the Mouse Left Button is pressed and dragged, not when it is freely moved. To help us achieve this, we will introduce three additional properties in our ViewModel. Let us rewrite our ViewModel. This would also explain why we are capturing the Mouse Events in the XAML, which was intensionally not explained till this point.

public class ShellViewModel:PropertyChangedBase
{
public double Left { get; set; } = 10;
public double Top { get; set; } = 10;

public double CurrentMouseX { get; set; }
public double CurrentMouseY { get; set; }

public bool IsShapeCaptured { get; set; }

public void MouseDown()
{
IsShapeCaptured = true;
NotifyOfPropertyChange(nameof(IsShapeCaptured));
}

public void MouseMove()
{
if (!IsShapeCaptured) return;
Left = CurrentMouseX;
Top = CurrentMouseY;
NotifyOfPropertyChange(nameof(Left));
NotifyOfPropertyChange(nameof(Top));
}

public void MouseUp()
{
IsShapeCaptured = false;
NotifyOfPropertyChange(nameof(IsShapeCaptured));
}
}

The IsShapeCaptured is enabled only when the Mouse Left Button is pressed. As soon as the Mouse Button is released, you are resetting the IsShapeCaptured flag. The MouseMove method ensures that the Left & Top properties (which are bound to the position of Shape) are updated only when the IsShapeCaptured is set.

I guesss that bit of code is quite self explanatory. This is one way to achieve the drag/drop functionality, but obviously there could be others. Will provide another solution in coming days.

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

 

Stimulsoft – Non-Modal Designer in WPF App, Part 2

In the previous post, we explored Supervising Controller Pattern to provide a solution to the issue we faced when using Stimulsoft Designer  Controller as an embedded control in WPF application. Even while we used the Supervising Controller Pattern, we still fiddled with the MVVM pattern by making the ViewModel “aware” of the View, even though it wasn’t depended. In this section, we would be exploring another method, through which could eliminate the ‘awareness’ factor, allowing us to work along the MVVM pattern with all its purity.
As in previous section, we will begin by adding the designer control in our XAML.
<wpfdesign:StiWpfDesignerControl></wpfdesign:StiWpfDesignerControl>
So how do we do resolve the issue this time around, without breaking the MVVM pattern ? Instead of Supervising Controller Pattern, we would instead on something which is native to the WPF. The Behaviours and Attached Properties
Behavior and Attached Property
Behavior allows us to Attach a new property the StiWpfDesignerControl, which is bindable.
public class ReportBehavior : Behavior
    {
        public static readonly DependencyProperty ReportSourceProperty = DependencyProperty.RegisterAttached("ReportSource", typeof(object), typeof(ReportBehavior), new PropertyMetadata(ReportSourceChanged));

        private static void ReportSourceChanged(DependencyObject DependencyObject, DependencyPropertyChangedEventArgs PropertyChangedEvent)
        {
            var stidesigner = DependencyObject as StiWpfDesignerControl;

            if (stidesigner != null)
                stidesigner.Report = PropertyChangedEvent.NewValue as Stimulsoft.Report.StiReport;
        }

        public static void SetReportSource(DependencyObject target, object value)
        {
            target.SetValue(ReportSourceProperty, value);
        }

        public static object GetReportSource(DependencyObject target)
        {
            return target.GetValue(ReportSourceProperty);
        }
As can be seen in the code above, we have defined a property called “ReportSource” which allows us to the set the Report Property of the Designer Controller.  We can now bind our property in our XAML
Putting it all together
      <wpfdesign:StiWpfDesignerControl local1:ReportBehavior.ReportSource="{Binding Path=ActiveReport}" x:Name="DesignerControl"  ></wpfdesign:StiWpfDesignerControl>
Don’t forget the namespace
xmlns:local1="clr-namespace:CM005.Behaviour"

 

Stimulsoft – Non-Modal Designer in WPF App

Stimulsoft Reports is one among the most powerful and easy to use Reporting Tools available. While this post is not focused on feature of Stimulsoft Reports, it is worth checking out the features in Stimulsoft Website.

 

Embedded Stimulsoft Designer Control and MVVM

The post would rather focus on displaying the powerful Stimulsoft Designer in a WPF application with Data Source being .Net Objects created at runtime. While this is pretty straightforward to do when you want to invoke the designer as a Modal Dialog, it becomes a little messier when you want the designer to be an embedded control, particularly when you want to stick to the MVVM Pattern.
Let’s first go ahead and place our designer control in the View first.
<wpfdesign:StiWpfDesignerControl></wpfdesign:StiWpfDesignerControl>

Don’t miss out adding the namespace

xmlns:wpfdesign="clr-namespace:Stimulsoft.Report.WpfDesign;assembly=Stimulsoft.Report.WpfDesign"

For sake of example, we would mock our business object rather than taking it out of Database

   public class Products
   {
       public string Name { get; set; }
       public decimal Price { get; set; }
   }

var   _ProductCollection = new List()
  {
  new ProductModel() { Name = "Product 1", Price = 100 },
  new ProductModel() { Name = "Product 2", Price = 200 }
  };

We do have a property ‘ActiveReport’ , which holds the report details and is responsible for synchronizing the dictionary. Let’s define the Property and synchronize our collection.


  private Stimulsoft.Report.StiReport _ActiveReport;

  public Stimulsoft.Report.StiReport ActiveReport
  {
  get { return _ActiveReport; }
  set
  {
  _ActiveReport = value;
  this.NotifyOfPropertyChange(nameof(ActiveReport));
  }
  }

And the code to register the collection with StiReport.

  ActiveReport = new Stimulsoft.Report.StiReport();
  ActiveReport.RegBusinessObject("Products", _ProductCollection);
  ActiveReport.Dictionary.Synchronize();

This is where our problems begin. We do not have a property (the Report Property doesn’t allow Binding) exposed by Stimulsoft Designer to which could bind the StiReport Instance. We can do it pragmatically by assigning the Report Property, but that would involve breaking the MVVM Structure. We would prefer not to do that, atleast not directly. So what would be our workaround ?

Supervising Controller Pattern

The workaround lies with having a Supervising Controlling Pattern. The Supervising Controller allows the ViewModel to be aware of the View, but not depended on it. Now this can be a tricky situation if someone questions whether this would be breaking the MVVM, considering as per MVVM, the ViewModel should be completely independent of View. Pretty much true, but when all doors are closed, there is nothing wrong in making the ViewModel ‘aware‘ of View, as long as it is not dependent on View and we do minimalist code in View. Remember, there is a significant difference in being aware and being dependent.

So how do we implement the Supervising Controlling Pattern and make the ViewModel aware of the View. We first being by creating the Contract interface through which the ViewModel would be interacting with View. Let’s call it ISupervisorController

  public interface ISupervisingController
  {
  void UpdateReportControl(Stimulsoft.Report.StiReport Report);
  }

As you can see, it has a single method called UpdateReportControl, accepting the StiReport instance. Let’s go ahead and implement it in the View. We will make that only minimalist work is done in the code behind class.

  public void UpdateReportControl(StiReport Report)
  {
  ReportDesigner.Report = Report;
  }

So with that done, we come to the most important part – how do we get an instance of View in the ViewModel ? Thanks to Caliburn.Micro, we do have a solution for that as well.

Screen and IViewAware

The Screen class in Caliburn.Micro utilizes an interface ‘IViewAware, which exposes a method called OnViewAttached which gives us reference to the attached View. All that left to do is override the method and use our Supervising Controller interface to call the method from View, which sets the Report property of Designer Control

  protected override void OnViewAttached(object view, object context)
  {
  base.OnViewAttached(view, context);
  (view as ISupervisingController).UpdateReportControl(ActiveReport);
  }

That’s it, you have your .Net Object Collection synchronized with the Designer. The entire source code described in this post can be found here