Verifying if View Exists for specified ViewModel

There might raise situations in your Project where you might be interested to check if the ViewModel specified has a corresponding View defined and gradefully handle the error, than throwing an exception.

Caliburn Micro’s ViewLocator class provides you methods that enables you to do exactly that.

if ((ViewLocator.LocateForModelType(typeof(DummyViewModel), null, null) is TextBlock tb
&& tb.Text.StartsWith("Cannot find", StringComparison.InvariantCultureIgnoreCase)))
{
// View does not exist, Terminate or redirect to another
}
else
{
// View found, redirect to intended one
}

Invoke UIElement’s Focus() Method From ViewModel

One of the things WPF developers often notice is inability to SetFocus on a particular control from the ViewModel. This problem can be however easily resolved using an attached property. Let’s examine the code.

We will begin by writing an attached property, for the purpose of example, named as IsFocused.

public class FocusExtension : DependencyObject
{
    public static bool GetIsFocused(DependencyObject dependencyObject) => (bool)dependencyObject.GetValue(IsFocusedProperty);
    public static void SetIsFocused(DependencyObject dependencyObject, bool value) => dependencyObject.SetValue(IsFocusedProperty, value);
    public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.RegisterAttached("IsFocused", typeof(bool), typeof(FocusExtension), new PropertyMetadata(false, IsFocusChanged));
    private static void IsFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
       if ((bool)e.NewValue)
       {
          d as UIElement).Focus();
       }
    }
}

The sole objective of the attached property is to call the Focus() method of the attached UI element when the IsFocused Property Changes. Since the attached property is bindable from ViewModel, we can now set Focus to any control from our View Model. Am using Caliburn.Micro for my MVVM Implementation

View

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Button Grid.Row="0" Grid.Column="0" Content="Set Focus" x:Name="SetFocusOnTextBox1"/>
        <TextBox Grid.Row="0" Grid.Column="1" Text="TextBox 1" ap:FocusExtension.IsFocused="{Binding IsTextBox1Focused}"  />
        <Button Grid.Row="1" Grid.Column="0" Content="Set Focus" x:Name="SetFocusOnTextBox2"/>
        <TextBox Grid.Row="1" Grid.Column="1" Text="TextBox 2" ap:FocusExtension.IsFocused="{Binding IsTextBox2Focused}"  />
        <Button Grid.Row="2" Grid.Column="0" Content="Set Focus" x:Name="SetFocusOnTextBox3"/>
        <TextBox Grid.Row="2" Grid.Column="1" Text="TextBox 3" ap:FocusExtension.IsFocused="{Binding IsTextBox3Focused}"  />
        <Button Grid.Row="3" Grid.Column="0" Content="Set Focus" x:Name="SetFocusOnTextBox4"/>
    </Grid>

ViewModel

public bool IsTextBox1Focused { get; set; }
public bool IsTextBox2Focused { get; set; }
public bool IsTextBox3Focused { get; set; }

public void SetFocusOnTextBox1()
{
   IsTextBox1Focused = true;
   NotifyOfPropertyChange(nameof(IsTextBox1Focused));
}

public void SetFocusOnTextBox2()
{
   IsTextBox2Focused = true;
   NotifyOfPropertyChange(nameof(IsTextBox2Focused));
}

public void SetFocusOnTextBox3()
{
   IsTextBox3Focused = true;
   NotifyOfPropertyChange(nameof(IsTextBox3Focused));
}

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

Binding Navigated Event in WebView Control

WebView Control in Xamarin.Form is a highly useful control for displaying a Web Page within your Mobile Application. You can either specify the URI that needs to displayed or you can provide the entire HTML Source to be displayed by assigning an instance of UrlWebViewSource to the Source Property of the control.

From an MVVM point of view, you can bind Source Property of the control to an instance of UrlWebViewSource.
<WebView Source="{Binding GatewayPageSource,Mode=TwoWay}" WidthRequest="500" HeightRequest="500"></WebView>

For Binding the control to an External URI, you could bind your ViewModel Property as follows.


public HtmlWebViewSource GatewayPageSource
 {
 get { return _GateWaySource; }
 set
 {
 SetProperty(ref _GateWaySource, value);
 }
 }

this.GatewayPageSource.BaseUrl = "urlpath";

For Binding the control to an HTML String, you could bind your ViewModel Property as follows.


this.GatewayPageSource.Html = "HtmlString"

One of the caveats however, is that two of the most important Events of the control, namely, Navigating and Navigated, is not Bindable. There are ways to get around this problem though.
The first method that was suggested to me was to use Behavior. I will probably try implementing this in one of later posts. The second approach, was possibly the easiest – create a custom control overriding the WebView and add the required properties.
public class AdvancedWebView : WebView
{
public static readonly BindableProperty NavigatedCommandProperty =
BindableProperty.Create(nameof(NavigatedCommand), typeof(ICommand), typeof(AdvancedWebView), null);

public AdvancedWebView()
{
Navigated += (s, e) =>
{
if (NavigatedCommand?.CanExecute(e) ?? false)
NavigatedCommand.Execute(e);
};
}

public ICommand NavigatedCommand
{
get { return (ICommand)GetValue(NavigatedCommandProperty); }
set { SetValue(NavigatedCommandProperty, value); }
}
}

The XAML with new Control would be as follows


<controls:AdvancedWebView Source="{Binding GatewayPageSource,Mode=TwoWay}"
NavigatedCommand="{Binding WebViewNavigatedCommand}"
WidthRequest="500" HeightRequest="500"/>

For keeping things simple, I have implemented only Navigated Event in the example, however, we could extend this functionality with Navigating Event as well.