Forms and Windows in a binary plugin

Mar 11, 2015 at 5:53 PM
Hi,

I see that some example projects contain code to create their own windows but these projects seem to be standalone applications. Is it possible to create and display windows or custom dialogs from a binary plugin ?
All my attempts so far have failed to produce a visible window or dialog even though I don't get any error message from either Visual Studio at compilation time nor from Eclipse at runtime. I have tried InputBox from the VisualBasic assembly or the Form from the Windows.Forms assembly but to no avail.

Thanks for your help !
Mar 11, 2015 at 6:05 PM
Hello Julien,

You can definitely create your own windows in a binary plugin. Actually, Eclipse gives you a reference to a WPF windows that it creates and then you can add your own controls to it. You can see an example in the Plugin Tester project that I uploaded to Source Code/Eclipse Scripting API/projects/PluginTester.

This project actually contains two projects
  • PluginTester: a standalone API script which can be used to start your own plugins and test/debug them
  • PluginScriptExample: a very simple binary plugin that gets started from PluginTester (or from Eclipse) and shows some basic information in a WPF window.
Feel free to download them and modify the plugin to your own needs.

Eduardo
Coordinator
Mar 11, 2015 at 8:15 PM
Add some references to your project:

PresentationFramework
PresentationCore
WindowsBase
System.Xaml

Add the following code to your script file:
namespace VMS.TPS
{
    public class Script
    {
        public Script() { }

        public void Execute(ScriptContext context, System.Windows.Window window)
        {
            var myOwnWindow = new Window();
            myOwnWindow.Content = new Button() { Content = "PRESS ME!" };
            myOwnWindow.ShowDialog(); //Will block unitl your window is closed
        }
    }
}
Boom. After you close your window, a new blank window will open up. This is the window variable that was passed to you (that you chose not to use). You can inject straight into that window like
namespace VMS.TPS
{
    public class Script
    {
        public Script() { }

        public void Execute(ScriptContext context, System.Windows.Window window)
        {
            window.Content = new Button() { Content = "PRESS ME!" };
             //No need to call ShowDialog() here because Varian calls it on the end of this closure.
        }
    }
}
I don't recommend building a UI from code. It sucks. I need to get around to showing how to build in WPF. I have and old video on Youtube that shows the basic idea:
https://www.youtube.com/watch?v=GxA_29gqPog
Mar 12, 2015 at 10:05 AM
Thanks guys, got something to scribble on now !

Essentially, my code was similar to what you both suggested except for the additional Window type parameter to Script.Execute(). And I also realize now that this information was in plain sight on the documentation... I'll be more careful before I post a question next time.

Thanks again.
Mar 12, 2015 at 2:48 PM
Edited Mar 12, 2015 at 3:20 PM
I come back to you because I have some strange behaviour going on. Here are the stages I've been through so far, in chronological order:

1 - I didn't have the extra window parameter in execute() and no window would show up.
2 - I added the extra window parameter in execute() and a window would show up while the script is running. When the script ends I get an error message telling me that the Show() , ShowDialog() and some other function can't be performed on a window at that stage of the script. I don't know what this error is referring to as I have no line of code that attempts to perform any of these functions on a window.
3 - I remove the extra window parameter in execute() and the window still shows along with the error message.
4 - I remove all sorts of unused extra references in the project and the window no longer appears, nor the error message.

This sequence of events lets me think that VS may be doing something behind my back that tells Eclipse to pop that window up. IDEs are great but all this doing the dirty work for you can be a problem at times.

In addition, I'm also thinking that if this window really appears after the execute() function ends as rexcardan seem to say, the window can't really be used to interact with the script then. At best, this window can display some information but it'll be "read only" so to speak won't it ?

EDIT:
I found that I need to restart Eclipse for the changes to the modules referenced by the script to become apparent. This part of the question is solved but I still get a different error message about ShowMessage() being only applicable to hidden windows. Here again, I'm not trying to execute ShowMessage() at this stage of the script. Can error messages be "asynchronous" (i.e. be displayed at a different time from when the error occurs ?) ?

EDIT2:
After having watched your video, rexcardan, I realize that it may be because the windows I tried to display may have been empty, thus zero-sized.
Coordinator
Mar 13, 2015 at 3:09 AM
So where are we at? There is so much content in your post. Did you figure "it" out?
Mar 13, 2015 at 9:17 AM
Hi,

Looks like I've got "it" sorted now: I can reliably control the display of a window and the user can interact with it. I'm still looking for a way to not end up with an empty window to be closed by the user at the end of the script.
As you said rexcardan, the design of a UI through code is a PITA. Instead, I followed your suggestion/video tutorial about creating a form using the VS designer and that much is fine. The form has static public members which can be accessed by the script so information can travel between them two.

Thank you both for your help.
Mar 13, 2015 at 11:29 AM

I'm glad it's working for you. I still don't understand why you get that empty window at the end, are you creating your own window? I never saw something like that. If you could post some of your code maybe we could figure out what's going on.

Eduardo

**********************************************************
Electronic Mail is not secure, may not be read every day, and should not be used for urgent or sensitive issues

Mar 13, 2015 at 11:55 AM
Edited Mar 13, 2015 at 11:56 AM
I investigated that a bit and here are some clues:

I have two versions of the same script. One has the optional Window type parameter in Script.Execute() and the other hasn't. Everything else is the same.

If I run the script with the optional parameter FIRST, then the window will pop up for all subsequent run of either script.
If however I run the script without the optional parameter FIRST, then the window will not pop up for all subsequent run of either script.

In other words, it depends on which script is run first and the difference is the optional Window type parameter being present or not.
I've also noticed that while Eclipse lets me delete scripts while it's running, the first script to have been run cannot be deleted and is considered to be in use by Windows during the whole Eclipse session.
Mar 13, 2015 at 3:15 PM
I'm not sure why that's happening. When you say you have two copies of the same script, does that mean that they have the same name? In that case, Eclipse will only load the first one you run, and when you try to run the second one it will actually still be running the first one because the dll is in memory until the end of the session.

You can try creating a new project with these three files:

UISample.cs
using System;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections.Generic;
using VMS.TPS.Common.Model.API;
using VMS.TPS.Common.Model.Types;

using UISample;

namespace VMS.TPS
{
  public class Script
  {
    public Script()
    {
    }

    public void Execute(ScriptContext context , System.Windows.Window window)
    {
        MainControl mainCtrl = new MainControl();
        mainCtrl.Context = context;

        var dockPanel = new System.Windows.Controls.DockPanel();
        dockPanel.Children.Add(mainCtrl);
        window.Content = dockPanel;
    }
  }
}
MainControl.xaml
<UserControl x:Class="UISample.MainControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Orientation="Horizontal">
            <Label Content="Hello patient: " VerticalAlignment="Center"/>
            <TextBox Name="txtHello" VerticalAlignment="Center" Margin="10,0,0,0" MinWidth="100"/>
        </StackPanel>
    </Grid>
</UserControl>
MainControl.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using varianAPI = VMS.TPS.Common.Model.API;
using varianTypes = VMS.TPS.Common.Model.Types;

namespace UISample
{
    /// <summary>
    /// Interaction logic for MainControl.xaml
    /// </summary>
    public partial class MainControl : UserControl
    {

        public varianAPI.ScriptContext Context
        {
            set
            {
                txtHello.Text = value.Patient.LastName + ", " + value.Patient.FirstName;
            }
        }

        public MainControl()
        {
            InitializeComponent();
        }
    }
}
and you should get the expected behavior; a window will pop up with a simple Hello Patient message and when you close the window the script will end.

Hope this helps,
Eduardo
Marked as answer by rexcardan on 3/16/2015 at 11:24 AM
Mar 13, 2015 at 5:03 PM
Hi Eduardo,

I've tested your script above and it behaves as you described.

In addition, I made the following experiment on your code : If I create my own container window rather than using the System.Windows.Window type window passed as argument of Script.Execute(), I get the empty window that appears at the end of the script. I thus conclude that this window is simply, as rexcardan hinted, the System.Windows.Window window that automatically pops up if the optional argument is present in Script.Execute().
The ambiguity was that the instructions (and your messages) let me think (my bad) for a while that the optional argument is needed if the script is ever going to display any window at all beyond message boxes.
Now it's clearer ; to generate windows, custom message boxes or forms, a developer can either use the optional window argument and assign controls to it OR not add the optional argument and create his/her own window dynamically or from a designer template. Or both but in that case, the empty window will pop as happened to me at first.

And to clarify on my previous message, the two identical scripts run in succession are of course named differently. The code is the same except for the optional argument and the names are different. What I'm still not clear about is why the first script to be run is so important.

Thanks,

J.