Creating add-ons for WPF applications - c#

I have a simple database application where an user can add or delete persons. Moreover, the application has a button "Add new button to application". This application is built using Prism framework. There are two modules:
RibbonControlModule (contains three buttons - Add Person, Delete Person, Add new button to application)
PersonModule (contains logic of adding and deleting persons)
My requirement is to add new buttons at runtime.
Let's imagine a situation. I live in Washington and I am happy with these two buttons(Add Person and Delete Person). But my friend, Bob, who lives in New Jersey would like to add new button Edit Button without recompilation the whole application. That is, Bob writes dll where he can edit person and then clicks Add new button to application in RibbonControlModule. After that, EditPerson button is appeared in RibbonControl and, for example, in ContextMenu. Maybe EditPerson dll would be another Prism module, I do not know.
That is, my requirements are:
pluggable controls
is it possible to plug control without recompliation? (like add-ons or extensions(Classic Notes for Opera) in Browsers(no need to restart a browser to use add-ons))
other programmers can develop their add-ons without using my source code
after once an user plugged a control, then this new control should be always plugged in the application.
Is it possible using WPF, MVVM and Prism? I really like Prism and do not want to deny Prism, but if "the end justifies the means", I would like to use other technologies.
If it is possible, then how can I do it?

This is what the MEF plugin architecture was designed for.
In short, you create an SDK containing an interface for your plugins and provide that to your clients as a standalone library. Your client's plugins then implement this interface and export them with the MEF Export attribute, which your main application then imports.
Where it gets a little tricky is with data templating, which is often a key component of MVVM. To cut a long story short your plugins need to put their data templates in a resource dictionary, give that dictionary it's own partial class file and export it with MEF's [Export] attribute. Your main app then needs to import these and add them to the global ResourceDictionary's 'MergedDictionaries' array. This is generally done separate to all your view model classes which are imported in a separate pass. The net effect is that your plugins can provides both views and view models at runtime, plus the data templates that bind the two together, and it will all work as though they'd been statically compiled into your original application. It also means you can create a plugin API for your customers without exposing the internals of your main application.
This is a very involved topic, and given how general this question is I'll be surprised if this question isn't flagged. If you'd like more details then let me know and we can move it to a discussion page.

You can do what you are describing using Regions in Prism. You can add a named region to your Ribbon that allows Prism modules to plug in new buttons into that region when the module first loads or later when a user clicks a button in some UI of your module as you describe.
To do that, add an ItemsControl into some pane within your Ribbon where you want the plugged in controls to show up. Add the prism namespace as a XAML namespace like so:
xmlns:prism="http://prismlibrary/"
Then add the following attached property to your ItemsControl:
prism:RegionManager.RegionName="CustomModuleCommandRegion"
Then in your module, inject IRegionManager either in the Module class itself if the commands should be added as soon as the module is loaded, or elsewhere in a ViewModel if it won't happen until a particular view is loaded or some user interaction like you described:
public ConstructorForModuleOrViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
}
private SomeCommandHandler()
{
var commandButton = // create button and wire up command here)
_regionManager.AddViewToRegion(commandButton, "CustomModuleCommandRegion");
}
You also have the option of using the RegisterViewWithRegion method of the region manager to set up a factory method or just specify the type of the view (i.e. button) that you want to inject. But for a button you will need to wire up a command handler before (or after) placing it into the region, so the AddViewToRegion is probably more appropriate. If it is something that is context sensitive - i.e. you only want the button to show up in the ribbon perhaps when a selection is made in a view - then you can get the region from the region manager first, and then use the Add and Remove methods on IRegion to add and remove your view (button) dynamically like so:
IRegion region = _regionManager.Regions["CustomModuleCommandRegion"];
region.Add(myCommandView);
...
region.Remove(myCommandView);
Using the combination of Prism Modules and Regions you can achieve runtime extensibility of your app - i.e. this new functionality could be "dropped in" without needing to recompile the main app or other modules in the app. To do that you need to use either configuration to specify your modules so that can be edited in the deployed environment to add a module, or you can use the DirectoryModuleCatalog to scan a directory for modules on start up. Its even possible to use a FileSystemWatcher to watch a directory for modules that are dropped in while the app is running and have them light up immediately when placed in the watched directory.

Related

Insert a user interface in a DLL

In my project I have implemented this plugin manager:
https://code.msdn.microsoft.com/windowsdesktop/Creating-a-simple-plugin-b6174b62
In this way I can add .DLL file and make my project more modular.
I wanna know if in one of these .DLL plugin I can add a .xaml with user interface, and use it inside my main project to visualize the content of that xaml in my main GUI.
In this way I can make my app more modular not only by code library but also with user interface.
Thanks
If you create a project that contains WPF UserControl items, then as long as you expose those items through the DLL interface then you can utilise them in another project.
You should be able to verify this very easily by doing something like the following:
1) Within your 'DLL' project make a public class SquareControl, which is simply a UserControl under the hood, and specifically a canvas containing a red square of a fixed size.
2) Within your utilising project, reference the DLL.
3) Within your utilising project, in C# code somewhere create an instance of SquareControl, and check in the debugger that its properties are as you expect.
4) Then create a UserControl within your utilising project, and open VS Designer for that control. Within the empty Grid that has been created for you drop an instance of SquareControl, and you should be able to see this within Designer. Getting your xaml namespace definitions can be awkward the first time around but there's plenty of help available for that. Then fire up the application and see it there.

Transistion from Winforms to WPF MVVM

I have a program that at its heart is just a fancy Keyboard hook and wedge. The keyboard hook portion is a separate library from the main program. In the main program I gather all the keys that i want to monitor from a config file and instantiate the keyboard hook. The keys that I am monitoring have tasks that they can perform when the key is pressed and/or when it is released. (Tasks such as open a program, turn on a scanner..etc) Since the project started in Winforms I felt that it would be a good idea to make a folder in this library called Controls. I made a dialog Form that a user could select what task they wanted to perform. There has been a need for me to switch from Winforms to WPF. So it is nothing to add Winform controls to a class library. From trial and error it appears that doing the same thing for WPF user controls is a different story. So I decided it would be easier to just created a new WPF Usercontrol project. (If it is possible can you please leave a comment about how to?)
So I am new to WPF, and decided that this particular library would be good to use the MVVM pattern to get my feet wet. It is small in that I only have 6 subclasses of Type AbstractTask. Part of me is itching to use Abstract Task my Model. I'm not sure how yet, but I think that it is my Model. I'll have to add a description string field to it for my View, but that shouldn't be a problem. Since atleast one of my Tasks needs extra information (such as RunProgramTask) I figure I should also put a ?Action? in to "verify" that all the correct information is given. again.. that should be easy.
So in the end I have 2 questions.
Does my theory comply with the MVVM pattern?
Should I move all my Hooks and Tasks and such over to the new WPF project and delete the old project? Or should I just delete the Winforms controls out of my library and just imagine that it is one project?

What is the good way to interface Ribbon control with Caliburn Micro?

I'm using Caliburn Micro for my project, and I decided to use Fluent Ribbon as part of the UI. My ShellView is really simple, and it's laid out like this:
Ribbon Control with 4 tabs.
ActiveItem.
The Active item is dynamically changed depending on the Ribbon's selected tab.
Question:
What is the proper way to use Ribbon control as a second view for my currently active ViewModel (ActiveItem), while maintaining modularity and all the goodies which come inherit with CM itself? Also, what would it take to "share" my Ribbon control among my ViewModels?
Details:
My ShellViewModel is of type "Conductor.Collection.OneActive", and it changes the ActiveItem to specific ViewModel I associate with selected tab (when event is fired).
My Ribbon is defined in XAML like this:
<ContentControl x:Name="RibbonBar" Micro:View.Model="{Binding ActiveItem}" Micro:View.Context="Ribbon" />
As it shows, Ribbon control is bound to currently active item as it's context view. That actually works for one view, because due to default CMs conventions, where it looks for the contextual views in the sub namespace (e.g. if my path to the view is Views.TasksTabView, it will look for the Context view at Views.TasksTab.Ribbon).
Problem is, when I change the ActiveItem, context view can't be located anymore, due to the different namespace, so It only works for one Tab.
I've also tried writing my own ViewLocator convention but I had no success with it.
Thank you.
Unfortunatelly since there are no answers, I'll answer it myself.
I did manage to write the additional ViewLocator logic to locate my Ribbon, but that created some problems (It seems that binding in CM only works once, so after Ribbon being located and bound to the VM, additional context view changes do nothing. There were some hard to find bugs as well).
I've taken a different approach then. I've separated Ribbon to it's own ViewModel, and composited it to the shell with rest of the modules. It uses EventAggregator and I also Inject it where neccessary. Not approach I was hoping for, but it works for now.
If anyone posts better answer, I'll definitelly accept that one.

Having multiple active instances with PRISM

I have an application in PRISM, C#, and I wonder if I can do the following:
I've a button bar on the bottom of my appliction, which acts as my navigation area. The user can click on button A, and the dashboard of module A will pop up.
The user clicks on an item in the dashboard, and he comes to a details page about the item. He is in the pogress of making some changes, but he receives an email during this process.
He opens module B and makes a new item in module B.
--> There are 2 instances open at that moment, the details page of module A, and the add page of module B. I want the user to also visualy pick up on this, because there will be a "1" above the button for module A.
The question is, (how) can I do this with PRISM.
tl;dr; Does PRISM support multiple instanciated views? (it's the "managing" of open views, so you can chose which view to have open.)
I tried googling this, but I couldn't find anything related to it (probably because I'm not sure of how to call this, so I can't search on it :/)
Any info is much appreciated, thanks for your time.
Here's a very short intro on how this works out in Prism, including links to an unbelievably helpful section of MSDN:
Prism has regions, which is an abstraction for controls that can host one or more other controls (your views). Each region can have any number of views added to it, and at most one view in each region is active. The manner in which views (including what it means to be the active view) are displayed is dependent on the region adapter, which is an object created automatically by Prism based on what type of control hosts each region.
Adding to Jon's post.
You might want to use TabControl. If you put PRISM's region into TABCOntrol - you will be able to see all instances as tabs.
You can see decent sample with some XAML on how to close tabs here:
Menu service in Prism application CAL
So, on "inside" - PRISM will have either singleton views/viewmodels if you Export them with MEF by default. If you export those parts as NonShared - PRISM will keep multiple versions of same view inside container (MEF or Unity). However, with buttons - you won't get specific instance.
So, use TabControl as container like this:
Menu service in Prism application CAL
Or you can write your own region adapter and track instances in there.

How could you enable a WPF application to create user controls on the fly?

How could you create an application that could search through a directory, find user controls in the form of paired .xaml / .xaml.cs files, and compile/execute these on the fly? Is this possible? Is there an .exec() or .compile() class somewhere that could do this?
Basically what I want to do with this is have a WPF application that is running and by having the user fill out a form describing the kind of page/functionality he wants, the application could generate XAML and code behind files which are then immediately usable without having to recompile the application.
I'm assuming that this is to change the behaviour of the UI on a known application rather than a XAML/CS component generator for use in another application - after all there's already applications that do this - Expression Blend anyone?
Do you really need to recompile the underlying CS? As far as I can see it all you'll be doing is changing the apparent behaviour and look of the application and UI. This could be achieved by command binding within the xaml and styles for the components.
The reality is that in order to perform the functionality that you require you'll be giving the user a finite choice as to behaviour. You'll need to decide what behaviour is application and what is the UI.
Application bahaviour is governed by fixed commands (they could accept parameters to change behaviour).
UI behaviour (appearance, animation etc) is covered by the xaml. If the application runs in a browser window you could auto generate the xml needed as requried, linking it to the underlying app. commands and allow the browser to execute the new behaviour for you.
Is this a good idea? I can see a few problems with this.
How will the code behind 'know' how to interact with the rest of the application
Security? You will be allowing somebody to make system API calls on behalf of the main application
App domains???
Rather build up the forms using ItemsControls and DataTemplates. In the form where the user specifies what functionality he wants in the form, you will be presenting him with a list of 'building blocks' anyway. Make each 'building block' a ViewModel and associate each ViewModel with a DataTemplate 'UserControl'.

Categories

Resources