Caliburn Micro Winforms MEF Implementation - c#

My name is Max. I'm currently working on a projekt with caliburn micro.
I'm trying to create a plugin based application in C# with the help of MEF.
I'm using WPF. So I stripped my application to the bare minimum. The bindings with caliburn works fine in the test WPF application. The problem what I have now is that the ShellView (WPF UserControl) needs to live in an ElementHost of a WinForm 3rd party application.
I can't figure it out how to create the correct binding. So that the "magic" of caliburn also works in the winform application. Maybe one of you cracks can help me. I googled and tried this an entire day.
Your help would be very much appreciated.
Greets Max
Link to project:
https://www.dropbox.com/s/y88kgnh0wscy2jr/CaliburnMEF_Example.zip?dl=0

Sample that was provided on the CM GitHub its been there a while..., https://github.com/Caliburn-Micro/Caliburn.Micro/tree/master/samples/Caliburn.Micro.WinFormsInterop/Caliburn.Micro.WinFormsInterop
--edit--
You were close compare this code snippet to your current test project. You were missing a few key items... reference comments
protected override void StartRuntime()
{
base.StartRuntime();
var vm = IoC.Get<ShellViewModel>(); // ok
var view = ViewLocator.LocateForModel(vm, null, null); // needed
//binds the viewmodel to the view & wire up controls...
ViewModelBinder.Bind(vm, view, null); // required!
var activator = vm as IActivate; // required
if (activator != null)
activator.Activate(); // required
_host.Child = view; // since Forms is ViewFirst, by default.
}
Just a few extra steps to get it work with the ElementHost control. As for binding it should work as expected. If you are having issues with binding other controls (3rd party), you might have to create Conventions to support them. That is a very dependent on the controls themselves.

Related

Caliburn.micro and devexpress: insert tabs (dockpanel) from viewmodel when user clicks

Cheers all,
I'm searching to use the devexpress tool in my visual c# project (vs2013). I'm also using caliburn.micro and i've inserted the Caliburn.Micro.DevExpress reference. So, this is my environment.
The problem: I want create a container, where you can open some predefined tabs. You can navigate in the open tabs, close them and open others.
I'm in stuck with the integration of devexpress and caliburn. Without caliburn and mostly without MVVM pattern, it's easy. But how can I do this using my viewModel?
The result I want is like the example "Simple MDI" in [the official caliburn.micro documentation1]. Instead of the button "open tab", I've my menu in the upper side and, depending on which button is clicked, I want open the relative dockpanel/tab.
Now, in the xaml file, my container is a devexpress object, the "DocumentGroup". My goal is to add dynamically the DocumentPanel(s), like written above.
Is it clear the problem? Some ideas for solution?
UPDATE: in my viewModel I have:
namespace **.ViewModels
{
class MainWindowViewModel : Conductor<IScreen>.Collection.OneActive
{
public void addT() {
Debug.WriteLine("start");
ActivateItem(new ucImpiantiViewModel());
Debug.WriteLine("end");
}
}
}
And in the xaml I have:
...
<dxd:DocumentGroup x:Name="Items" ItemHeight="3*" SelectedTabIndex="0">
...
I thought this way was good, but still nothing.. the good new is only that the console.writeline are working!

WPF, MVVM, and effective navigation / control flow

I am currently building an application based on a real world scenario, to help me learn and understand WPF and MVVM. To that end I have read and worked through Karl Shifflett's "In The Box" VSIX, and I was able to adapt most of the concepts to the application that I am working on.
While I think MVVM is a powerful design pattern, it does (seemingly) make things that were once trivial (e.g. displaying messages, navigation, interacting with multiple window), not so trivial or straightforward. Now onto the crux of my problem / confusion.
The WPF application that I am working on is a Windows based application, and I am working from a set of basic requirements:
A basic login screen
After a successful login, close the login screen and open the actual application
Simulate a typical program workflow (opening "child" windows via button clicks, displaying modal windows, etc.)
Preform data validation / error handling
Log out
I am used to working with MDI Applications on a windows platform where interactions on a parent form cause child forms to open; I understand that MDI is not something that WPF supports and I am fine with approaching development from a different perspective. My UI would still work in a similar manner to a MDI application though: I have my application layout, and as I interact with that layout my application will respond by opening windows, displaying messages, and so on. It isn't clear to me (via MVVM) how to interact with multiple windows, or how well MVVM would scale to a large application with many windows / views.
I am not opposed to using something like Prism, but I haven't found a good article on how Prism approaches my particular problem very well. Any help, advice, feedback, or otherwise is greatly appreciated!
Have you tried looking at nRoute Framework?
A link can be found here
There are actually some good tuturials about prism
Link 1
Link 2 (Part II of Link1)
Link 3
For a more straight forrward application (not very complex and modular), you can always create a aplication, with a main window that manages child usercontrols (login window, menu window, other windows ...)
For example, create a window a contentpresenter in it, and in codebehind:
public partial class ShellWindow: Window
{
public enum PagesTypes { Login, Home }
PagesTypes currentOpenedPage;
LoginUserControl login;
HomeUserControl home;
public WindowController()
{
InitializeComponent();
login = new LoginUserControl ();
login.GoToPage += new LoginUserControl.ChangePageHandler(GoToPage);
GoToPage(PagesTypes.Login);
}
public void GoToPage(PagesTypes page)
{
switch (page)
{
case PagesTypes.Login:
//Close last opened usercontrol,
....
//open new usercontrol
login = new LoginUserControl();
contentpresenter.content = login;
break;
//other pages cases
....
}
currentOpenedPage = page;
}
}
And in for example the login usercontrol:
public partial class LoginUserControl : UserControl
{
internal delegate void ChangePageHandler(ShellWindow.PagesTypes toPage);
internal event ChangePageHandler GoToPage;
public LoginUserControl()
{...}
//Methods for login
.....
internal void LoginOK()
{
if(this.GoToPage != null)
GoToPage(ShellWindow.PagesTypes.Home);
}
}
You can build a good dynamic using this method changing usercontrols, simulating diferent windows.
Hope this gives you some ideas.
MVVMing your child windows actually can be kind of easy, especially if you decide that a tabbed interface is OK. Your outer window's view model simply has a collection of ChildWindowViewModel. You create a new tab just by creating the new view model, asking the outer window to add it to it's collection, and WPF's DataTemplate awesomeness will take care of the proper display. You'll have to do some fiddling to get tab 'close' operations working the way you want. It's kind of a pain but doable.
If you really want to do MDI, there's nothing built into WPF for it (I think Microsoft has decided that it is a bad UI pattern now?), but there may be 3rd party controls out there for it. Any good one will still mirror this solution where their MDI container control will bind to your list of child window view models.

What is the recommended way to open a new window using MVVM in WPF

Hello everyone and thanks in advance for your time.
I'm currently learning MVVM using WPF for a small Biz App that I'm writing. I have read a lot of articles about the MVVM pattern and found that one of the key areas is to decouple the ViewModel from the View as much as possible.
I want to open a new Window in my app but I'm not sure if I should open it from the ViewModel using an ICommand or directly from the view using a standard event. Someone I work with suggested that that I should use commands, but then I thought that this would mean having a reference to a View in my ViewModel, which according to what I understand is precisely what the MVVM pattern focuses on avoiding.
My understanding is that if a window will open for navigation purposes only and the process of opening that new windows has no effect on the Model, then I should keep all of this on the view using standard events.
I know in sw development everything "depends", but guess my question is there a "right"/standard way of doing this?
Best regards,
Daniel
Yes, VMs should communicate with Views utilizing the Events that Views can subscribe to...
In VM:
public event EventHandler<NotificationEventArgs<string>> DisplayOptionsNotice;
In View:
private readonly MainViewModel mvm;
...
mvm = DataContext as MainViewModel;
mvm.DisplayOptionsNotice += DisplayOptionsWindow;
...
private void DisplayOptionsWindow(object sender, NotificationEventArgs<string> e)
{
...
optionsWindow = new OptionsWindow { Owner = this };
optionsWindow.ShowDialog();
...
}
but then I thought that this would mean having a reference to a View in my ViewModel, which according to what I understand is precisely what the MVVM pattern focuses on avoiding.
In general, the way this is handled is via some form of inversion of control. Most MVVM frameworks will provide a service of some form to open a window, and use a Service Locator or Dependency Injection to provide the service to the ViewModel.
This allows your ViewModel to stay decoupled from the specific view rendering framework - you'd pass the service the new VM and say "Show this VM in a window", and that code would be platform specific.
As Reed said Service locator or DI will do the work and wont breake the MVVM pattern.
from my experience you will have to do three things:
First check about the Service Locator or Di see what more friendly for you and implement it.
Second start making the interface of IWindow\IWindowDialog that your view (windows\ Messagebox - if you like) will implement for example.
the last thing is to implement the windows\ messages.
it will take time to do it from scratch (I did it) but if you will focus one thing at a time.
you cut the time in half.
Good luck

Access Pivot Control from App.xaml.cs

In my MainPage.xaml, I created a Pivot Control: <controls:Pivot Title="Powder God" Name="PivotControl">.
My first pivot view is a HubTile that summarize all other individual pages. So my application bar will be different between the first pivot view and all other ones.
That's why I put my application bar in App.xaml's resource section, then load based on selected index of my pivot.
My question is:
In the application bar I will be using for all individual pages, I want to have a delete option, where I will remove that specific item (a view model) from my data context.
I know I can use PhoneApplicationFrame root = Application.Current.RootVisual as PhoneApplicationFrame; to access navigation services, but I don't know how can I reference to my pivot, so that I can get the selected index and proceed forward.
Thanks!
Using MVVM you SHOULDN'T do this:
((PageType)Application.Current.RootVisual).PivotControl. //Blah
PageType is whatever type PhoneApplicationFrame is that contains your PivotControl. If this doesn't work you need a Property in the RootVisual
PAGE
public Pivot MyPivot
{
get
{
return PivotControl;
}
}
APP
((PageType)RootVisual).MyPivot. //Blah
On one level Microsoft's suggestion of putting the ApplicationBar in App.xaml is great as it can be referenced from everywhere and would appear to encourage code reuse: however this question highlights the limit to this approach. An application bar is typically used to provide actions which are specific to the current page (or pivot item) and just because the buttons are the same you may not want the exact same code to run in each case.
In this case I think it would better to create a factory method that creates your common ApplicationBar with the click handlers you specify specific to your page/pivot item. For bonus points put the method in a new class (not App) so it doesn't get lost in all the boilerplate code there. Call this factory method in your page constructor and remember your ApplicationBar in your class. For multiple app bars, create them all up front and you can then easily switch between these app bars in your Pivot SelectionChanged code.
The alternative of creating the ApplicationBar in App.xaml and then retrieving this from the App.xaml.cs "Resources" ResourceDictionary in code, modifying the click callbacks, is more complicated in my opinion.
I wish they'd done a better job of implementing the ApplicationBar so people wouldn't want to do this. I've found that using the ApplicationBar forces you to add code to your Page.xaml.cs even if you use a framework like MVVM Light. This is still OK in MVVM as it's UI specific code that belongs in the View, but it makes things inconsistent if you're using ICommand everywhere else. Last time I decided it was better to create the entire ApplicationBar in code rather than hack this kind of thing via App.xaml.cs.
Update: There is a UserVoice request for a data bindable ApplicationBar.

Have object send message to MainPage

I have a class Target and a static property, in another class, called points. Each time the user hits a target, I want to increase the points. The reason I put points in a different static class is so that each Target object can access it.
The problem is that the textblock displaying the points exists in the MainPage and not in each Target object. Since I can't bind my XAML to a static property, how can I make it so that each Target object can somehow let the MainPage know that it should update the points textblock? thanks for any advice
You could totally apply the MVVM pattern here. If there is a static ViewModel that is bound to the main window, then you can raise a notification each time a property changes and the Views (all tied windows that display the data) will be automatially updated (re-bound).
I would recommend checking Laurent Bugnion's MVVM Light framework. It has a lot of this plumbing done for you, so all that needs to be done from your side is to put the parts together and bind them correctly.
Some resources worth checking for your situation:
WPF Apps With The
Model-View-ViewModel Design
Pattern (still applied to
Silverlight as a methodoloogy)
Model-View-ViewModel In Silverlight
2 Apps
If you need samples, take a look here.
Are Class Target and AnotherClass.points within the same name space? If so, may be the following helps:
/* In Window class */
Window w = new Window();
/* function where Target get hit */
w = this;
/* code to update points */
w.textbox1.Text = AnotherClass.points.ToString();

Categories

Resources