Inventor, Addins, Modeless WPF Window

If you are building an add in for Inventor and want to setup your window to be modeless and always on top of Inventor itself, like a toolbar, you need to set the Owner property of the window itself and you can use the value stored in the “MainFrameHWND” property of the Inventor application object passed to your addin.

The not so straight forward part is that the Owner property expects a reference to a Window object and all we have is the handle to the Inventor window.

public partial class MyAddinWindow : Window
{
    public MyAddinWindow(int inventorWindowHandle)
    {
        InitializeWindow();

        // setup loaded event
        Loaded += (s, e) =>
        {
            WindowInteropHelper wih = new WindowInteropHandler(this);
            wih.Owner = (IntPtr) inventorWindowHandle;
        };
    }
}

WPF – Bring the Loaded Event to MVVM

In the spirit of bringing the “Closing” event to your view model, I also decided that I wanted an easy way to bring the “Loaded” event to my view model. This one I don’t like as much as many frameworks have some kind of navigation that can take care of this for you. But if you have a simple app and want to initialize your view model when your window is loaded, you might find this helpful.

Just like in the previous article, you could wire into the “Loaded” event on each window and then delegate to the view model. This does work, but does tend to repeat the same code over and over again. Instead of this I went in and did a solution that is similar to the “Closing” event.

First up is create an interface that defines an Action that will be called when the window is loaded.

public interface ILoadedAction
{
    void WindowLoaded();
}

And a delegate based implementation of the ILoadedAction interface. I like this because it probably takes care of 99% of my cases.

public class DelegateLoadedAction : ILoadedAction
{
    public Action LoadedActionDelegate { get; set; }

    public DelegateLoadedAction()
    {
    }

    public DelegateLoadedAction(Action action)
    {
        LoadedActionDelegate = action;
    }

    public void WindowLoaded()
    {
        LoadedActionDelegate?.Invoke();
    }
}

And finally, some attached properties for our Window.

public class LoadedBindings
{
    public static readonly DependencyProperty LoadedEnabledProperty =
        DependencyProperty.RegisterAttached(
            "LoadedEnabled",
            typeof(bool),
            typeof(LoadedBindings),
            new PropertyMetadata(false, new PropertyChangedCallback(OnLoadedEnabledPropertyChanged)));

    public static bool GetLoadedEnabled(DependencyObject sender) => (bool) sender.GetValue(LoadedEnabledProperty);
    public static void SetLoadedEnabled(DependencyObject sender, bool value) => sender.SetValue(LoadedEnabledProperty, value);

    private static void OnLoadedEnabledPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (sender is Window w)
        {
            bool newEnabled = (bool) e.NewValue;
            bool oldEnabled = (bool) e.OldValue;

            if (oldEnabled && !newEnabled)
                w.Loaded -= MyWindowLoaded;
            else if (!oldEnabled && newEnabled)
                w.Loaded += MyWindowLoaded;
        }
    }

    private static void MyWindowLoaded(object sender, RoutedEventArgs e)
    {
        ILoadedAction loadedAction = GetLoadedAction((Window) sender);
        loadedAction?.WindowLoaded();
    }


    public static readonly DependencyProperty LoadedActionProperty =
        DependencyProperty.RegisterAttached(
            "LoadedAction",
            typeof(ILoadedAction),
            typeof(LoadedBindings),
            new PropertyMetadata(null));

    public static ILoadedAction GetLoadedAction(DependencyObject sender) => (ILoadedAction) sender.GetValue(LoadedActionProperty);
    public static void SetLoadedAction(DependencyObject sender, ILoadedAction value) => sender.SetValue(LoadedActionProperty, value);
}

I created two attached properties, one to enable or disable this feature and one to bind to the interface that contains the action to execute when the window is loaded. You could make this even simpler by removing the enabled/disabled property, but I like the flexibility of being able to turn it on and off. If you did want to do that, you would have to define a DependencyPropertyChangedEvent for the LoadedActionProperty and subscribe and unsubscribe to the Loaded event there.

To use these properties, open up your window XAML file, add in the namespace declaration and define your properties.

<Window x:Class="SampleApp.MainWindow"
    xmlns:local="clr-namespace:SampleApp"

    local:LoadedBindings.LoadedEnabled="True"
    local:LoadedBindings.LoadedAction="{Binding LoadAction}">
</Window>

In the sample above I removed some of the other declarations and assumed that our attached properties were in the same namespace as our MainWindow class.

Next, in the view model class, we simply do this:

public class MainWindowViewModel : BaseViewModel
{
    /// constructor, properties etc ...
    /// ...

    private DelegateLoadedAction _loadAction = null;
    public DelegateLoadedAction LoadAction
    {
        get
        {
            return _loadAction ??
                (_loadAction = new DelegateLoadedAction(
                    () =>
                    {
                        /// do your window initialization here
                    }));
        }
    }
}

And that is about it. Now you don’t have to subscribe the Loaded event explicitly any longer and you can consolidate your code into the view model. You can also move any of those longer running operations that were in the constructor of the view model out.

Perhaps the next step will be to turn this and the Closing event code from the previous post into a nuget package that can be just installed into a project.

WPF – Bring Closing Event to MVVM

The Issue

I’m jumping around a bit, but I don’t get to work on a single project at a time, so I am going to switch gears to talk about some WPF work that I put together. In this project, I want to make sure that I can control when the user closes the window, regardless of whether they click on the “X” in the top-right or if they click the “Exit” button in the UI.

The problem that we have is that the logic that controls whether the user can close the window or not is in the view model. The exit button is controlled by the view model. But the “X” in the top-left corner can only be controlled by the Closing event in the code behind. You can use the event parameters to cancel the close. How can we leverage the logic in the view model to determine if the Window can close or not?

Hack Method

One thing we can do, is inside of the Closing event, we could query the view model to see if it is ok to exit or not. It’s not the greatest, it will be writing a lot of custom code in every window code behind.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Closing += MainWindow_Closing;
    }

    private void MainWindowClosing(object sender, CancelEventArgs a)
    {
        // make sure we have the view model class
        if (DataContext is MainWindowViewModel vm)
        {
            // check with the view model if should be canceled
            e.Cancel = vm.ShouldCancel();
        }
    }
}

Not pretty but it works.

Using Attached Properties

The way I chose to do it is to use DependencyProperty’s that participate in the XAML binding system and can attach to the view model directly and not have to wire up each and every window explicitly. To do this, we need to setup a few new properties. One for enabling or disabling this functionality; a second for a parameter to send back and forth from the view model; and finally, a third that will hold an object that contains an action that gets called when the window is attempted to be closed.

Let’s get started with the two dependency properties that are used for holding the can close implementation and the can close parameter that is passed back and forth. These properties have the following shapes.

public interface ICanCloseResult
{
    bool Cancel { get; set; }
}

public interface ICanCloseCheck
{
    void CheckCanClose(ICanCloseResult canCloseResult);
}

And here are the properties that hold these values.

public class CanCloseBinding
{
        public static readonly DependencyProperty CanCloseCheckProperty =
            DependencyProperty.RegisterAttached(
                "CanCloseCheck",
                typeof(ICanCloseCheck),
                typeof(CanCloseBinding),
                new PropertyMetadata(null));

        public static ICanCloseCheck GetCanCloseCheck(DependencyObject sender) => 
            (ICanCloseCheck) sender.GetValue(CanCloseCheckProperty);
        public static void SetCanCloseCheck(DependencyObject sender, ICanCloseCheck value) => 
            sender.SetValue(CanCloseCheckProperty, value);


        public static readonly DependencyProperty CanCloseCheckParameterProperty =
            DependencyProperty.RegisterAttached(
                "CanCloseCheckParameter",
                typeof(ICanCloseResult),
                typeof(CanCloseBinding),
                new PropertyMetadata(null));

        public static ICanCloseResult GetCanCloseCheckParameter(DependencyObject sender) => 
            (ICanCloseResult) sender.GetValue(CanCloseCheckParameterProperty);
        public static void SetCanCloseCheckParameter(DependencyObject sender, ICanCloseResult value) => 
            sender.SetValue(CanCloseCheckParameterProperty, value);
}

Next we have to build up the dependency property that enables or disables the functionality. The important thing this property does is, when it is set to true, it attaches an event handler to the Closing event of the window. Then, when that event is executed, it tries to get the instances of the other two parameters and execute them. So it looks like the following.

namespace CanClose.Views
{
public class CanCloseBinding
{
    // ... other properties here

    public static readonly DependencyProperty CheckCanCloseEnabledProperty =
        DependencyProperty.RegisterAttached(
            "CheckCanCloseEnabled",
            typeof(bool),
            typeof(CanCloseBinding),
            new PropertyMetadata(false, new PropertyChangedCallback(OnCheckCanClosePropertyChanged)));

    private static void OnCheckCanClosePropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (sender is Window w)
        {
            bool newEnabled = (bool) e.NewValue;
            bool oldEnabled = (bool) e.OldValue;

            if (oldEnabled && !newEnabled)
                w.Closing -= MyOwnWindowClosing; // remove the event handler for Closing from the Window
            else if (!oldEnabled && newEnabled)
                w.Closing += MyOwnWindowClosing; // add the event handler for Closing to the window
        }
    }

    public static bool GetCheckCanCloseEnabled(DependencyObject sender) => 
        (bool) sender.GetValue(CheckCanCloseEnabledProperty);
    public static void SetCheckCanCloseEnabled(DependencyObject sender, bool value) => 
        sender.SetValue(CheckCanCloseEnabledProperty, value);

    public static void MyOwnWindowClosing(object sender, CancelEventArgs e)
    {
        /// get the values from the dependency properties
        ICanCloseCheck q = GetCanCloseCheck((Window) sender);
        ICanCloseResult p = GetCanCloseCheckParameter((Window) sender);
        if (q == null || p == null)
            return;

        /// execute and save the value back to the CancelEventArgs object
        q.CheckCanClose(p);
        e.Cancel = p.Cancel;
    }
}
}

Finally, all we need to do is attach these properties to the window that we want to control from our view model. And that is done like this:

<Window x:Class="CanClose.Views.MainWindow"
    xmlns:local="clr-namespace:CanClose.Views"
    local:CanCloseBinding.CheckCanCloseEnabled="True"
    local:CanCloseBinding.CanCloseCheck="{Binding CCQuery}"
    local:CanCloseBinding.CanCloseCheckParameter="{Binding CCResult}"
    >
    <!-- stuff here -->
</Window>

And that is about it. If you want to see a sample, you can find it here.

VSTS and Automating Signing

Welcome

Happy new year everyone! Hopefully everyone had a good holidays (if that is your thing) and have come back refreshed, relaxed and ready for a new year. For my first post of 2018, I was going to switch it up from development and go into a bit of dev ops.

I was fortunate to see Donovan Brown present earlier this week at Microsoft Vancouver. It was a great presentation and demo and left me inspired to put some of those lessons to good use with one of my current projects, a .NET desktop addin.

Background

I am using Visual Studio Team Services Online for hosting my code repos, managing my backlog and bugs, but I haven’t made much use of the build systems. Setting up a build definition to build and run my unit test was pretty easy, and I was able to just use defaults for the most part.

But I had some struggles with how to automate the signing of the binaries. Afer doing some research on it, here is what I found and what worked for me.

Step 1

First we need to create a script of some kind to perform the actual signing of the files. I chose to use Powershell as I have never really worked with it before. In my Visual Studio solution directory I created a “build” folder and added the script there.

param($certFile, $pw, $buildDir)

Write-Host "****************************************"
Write-Host "****************************************"
Write-Host "*** S I G N I N G O U P U T ***"
Write-Host "****************************************"
Write-Host "****************************************"

Write-Host $buildDir
Write-Host $certFile

$exe = Get-ChildItem -Path "C:\program files (x86)\Windows Kits" -Recurse -Include signtool.exe | select -First 1
Write-Host $exe

$timestampUrl = "http://timestamp.comodoca.com/rfc3161"

ForEach ($file in (Get-ChildItem $buildDir))
{
  if ($file.Extension -eq ".dll")
  {
    Write-Host $file.FullName
    &$exe sign /f $certFile /p $pw -tr $timestampUrl $file.FullName
  }
  elseif ($file.Extension -eq ".exe")
  {
    Write-Host $file.FullName
    &$exe sign /f $certFile /p $pw -tr $timestampUrl $file.FullName
  }
}

So what is happening here? First thing is that this script takes three parameters:
– the location of the certification file
– the password for the certificate
– the build directory

We will look at how we get those parameters later during the task.

The first important thing the script does is locate the signing tool on the build agent. We know that it will be somewhere under the “C:\program files (x86)\Windows Kits” subdirectory, so we use the Get-ChildItem to recurse through that directory and return the first one it finds. It stores that location in a variable to be used later.

The next thing it doesis loop through the build directory for all of the .exe and .dll files. For each that it finds, it uses the sign tool, and the supplied certificate path and password to perform the signing.

The nice thing about the script above is that there is nothing in there that is project dependant. You can use this script on all of your projects.

Step 2

Next I had to upload my code signing certificate to VSTS. This is pretty easy to do, all you have to do is click on “Build and Release” on your menu, then click on “Library” and then “Secure Files”. Finally click on “+ Secure file” and upload your certificate.

codesignUploadSecureFiles

Step 3

Head over to your build definition by clicking “Builds” and then “Edit” from the build definition menu.

We are going to add a new task called “Download secure file”. You can give the task some kind of descriptive name, and then from the “Secure File” combo box, select your code signing certificate. I placed this task after the Test task.

codesignDownloadSecurefileTask

Now, if your tests pass, the build process will download the code signing certificate to your build host (either online or local). You should note that the build agent will clean up after itself.

Step 4

You need to add your certificate password to the list of variables for the build definition. In your build definition, click on variables and then “add” in the “Process Variables” group. Give your secret a name and provide the value. Don’t forget to click on the padlock to hide the value.

Once you save the build definition, the secret value is hidden. From the capture above you can see that I am unlocking my password and it doesn’t show the value.

Step 5

Finally, we just need to execute the script as a task in the build. Add a powershell task after the “download secure file” task that you created in step 3. You can make the type “File Path” and browse to the build script that we created in step 1 (remember to check it in). Next we need to add the arguments that the script is expecting.

codesignpowershellscript

Certificate file

The download secure files tasks dumps the files into the build agent work folder _temp directory. So the first parameter is “$(Agent.WorkFolder)_temp\CodeSigning2019.pfx”

Password

The process variable contains our password, and to reference it as a parameter for our script, we uses “$(pfxpassword)”. “pfxpassword” is the name in my build definition.

Build Output Directory

Finally we need to specify where the files that are to be signed are located. We use another built in variable. For my build definition it looks like this: “$(Build.SourcesDirectory)\SbSol\StructureBuilder\bin\release”

Setup Complete

And that is it. Now when your build is run, you should see the following output in the logs.

codesignbuildlogoutput

You can see where the script is started, it is the blue line. Notice that the password has been blanked out on the command line. You can see next that it is showing the location of the build directory and the certificate file and even the signtool.exe that it found on the build machine. Next you can see it looping through all of the output files and the output of the signing operation.

Wrapping up

That is how I did it. Seeing as I use Visual Studio for building my Xamarin Forms apps as well, I could probably do something similar to sign that output.

Using IValueConverter

I was down in Las Vegas all of last week for the Autodesk Forge DevCon and Autodesk University: a full four days of learning about all of the up and coming Autodesk products and technologies and networking. Lots of fun, lots of new people to talk to. I had a chat with a somewhat new’sh dev and he was complaining about the difficulties of using XAML. We delved into a bit of MVVM and he wanted to know, in effect, how to bind visual properties.

From there we went to the use of value converters and all the potential they have for presentation without having to embed visual elements and other complex logic into your view model. And it is available across WPF, UWP and Xamarin Forms.

A Simple Case

My first value converter was in WPF and making visual elements visible or not based on a value in my view model. Lets pretend we have some additional controls in our window that are only visible if the user is an accounting user. In our view model, it is a bool property named IsAccounting. If we try to bind the IsAccounting property to the control Visibility property, a binding error occurs that says the type of the value is incorrect for the target property: because of the error we won’t see the UI change.


<!-- fails -->
<TextBox Text="{Binding AccountCode}" Visibility="{Binding IsAccounting}" />

We need a value converter that will change the bool value to a Visibility value.


public class BoolToVisConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool v = (bool) value;
        return v ? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

To use it, make sure that you have the namespace that the value converter resides in declared in your Window XAML and then the converter itself referenced in the resource dictionary:

xmlns:local="clr-namespace:Demo"
<Window.Resources>
    <ResourceDictionary>
        <local:BoolToVisConverter x:Key="boolVisConverter" />
    </ResourceDictionary>
</Window.Resources>

Finally you add the converter to the binding expression of the control:


<TextBox Text={Binding SecretAccountCode} Visibility={Binding IsAccounting,Converter={StaticResource boolVisConverter}}" />

And the application looks like this:

2017-11-19boolvisconverter

I like this because it keeps the app logic free of the presentation code, and this makes your view model simpler, testable and portable.

Something More Powerful

Let’s take a look at where the IValueConverter can really help. In this example we will change the color of the text in a textbox based and an image based on the selected item in a combo box. I setup an enum with some employee types:

public enum EmployeeTypeEnum
{
	CEO,
	VicePres,
	EngDirector,
	Engineer,
}

and added EmployeeTypes and SelectedEmployeeType properties to the view model.


/// initialize this collection in the constructor with the enum values.
public ObservableCollection<EmployeeTypeEnum> EmployeeTypes { get; private set; } =
    new ObservableCollection<EmployeeTypeEnum>();

private EmployeeTypeEnum _selectedEmployeeType = EmployeeTypeEnum.CEO;
public EmployeeTypeEnum SelectedEmployeeType
{
    get => _selectedEmployeeType;
    set => SetProperty<EmployeeTypeEnum>(ref _selectedEmployeeType, value);
}

Here are our value converters, one of them will convert the SelectedEmployeeType value to a foreground color and the other will convert the SelectedEmployeeType value to an image.

public class EmployeeColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        EmployeeTypeEnum empType = (EmployeeTypeEnum) value;
        switch(empType)
        {
            case EmployeeTypeEnum.CEO:
                return Brushes.Aqua;
            case EmployeeTypeEnum.EngDirector:
                return Brushes.Green;
            case EmployeeTypeEnum.Engineer:
                return Brushes.Red;
            case EmployeeTypeEnum.VicePres:
                return Brushes.Blue;
            default:
                return Brushes.Black;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class EmployeeImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        EmployeeTypeEnum empType = (EmployeeTypeEnum) value;
        switch (empType)
        {
            case EmployeeTypeEnum.CEO:
                return new Uri("/ceo.png", UriKind.Relative);
            case EmployeeTypeEnum.EngDirector:
                return new Uri("/director.png", UriKind.Relative);
            case EmployeeTypeEnum.Engineer:
                return new Uri("/engineer.png", UriKind.Relative);
            case EmployeeTypeEnum.VicePres:
                return new Uri("/vicepres.png", UriKind.Relative);
	    default:
	        return null;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Add our converters to the resource dictionary:

<local:EmployeeColorConverter x:Key="empColorConverter" />
<local:EmployeeImageConverter x:Key="empImageConverter" />

The markup for our XAML looks like this


<ComboBox ItemsSource="{Binding EmployeeTypes}" SelectedItem="{Binding SelectedEmployeeType}" />
<TextBox Text="{Binding SelectedEmployeeType}" Foreground="{Binding SelectedEmployeeType,Converter={StaticResource empColorConverter}}" Margin="0,2" />

<Image Width="48" Height="48" Margin="4" Source="{Binding SelectedEmployeeType,Converter={StaticResource empImageConverter}}" />

And that is it. We have a simple and portable view model that can be used on other platforms.

2017-11-19_6-35-24

Feel free to check out the sample code in GitHub.

I also would like to give a shout-out to SyncFusion as I used their free MetroStudio icon generator to build my icons.