Lets say I have a component with a number of smaller components which check prerequisites before the first one will be initialized. They are not dependent on one another so I don't care about order and would like them to run simultaneously. I am using MEF and Caliburn.Micro for presentation.
I thought about this setup:
class Big
{
[ImportMany]
public IEnumerable<IBigPrerequisite> Prerequisites {get; set;}
public void Initialize(){...}
}
and
interface IBigPrerequisite
{
public bool IsBusy {...}
public bool Allow {...}
public void StartChecking();
}
Now what I would like to accomplish with this is that the classes implementing IBigPrerequisite can open up a window (for example "File X was not found - this could lead to errors. Continue?") - this should be possible.
But I would only want one window to be visible at a time. How would I accomplish that besides just going synchronously?
EDIT - since the question seemed too vague
I need these Actions to run specifically before Big will be activated. Let's say we switch up the activation logic to something like this:
Big big; //we got this through Importing somewhere in composition
var allow = true;
var count = 0;
if(!pre.Any()) //no prerequisites, show window immediately
windowManager.ShowWindow(big)
foreach(var pre in big.Prerequisities)
{
pre.PropertyChanged += (s, args) =>
{
if(args.PropertyName == "IsBusy" && !pre.IsBusy) // if a prerequisite finished it's check
{
allow = allow && pre.Allow; //if one prerequisite says nay we could just return, actually...
count++;
if(count == big.Prerequisites.Count() && allow)
windowManager.ShowWindow(big);
}
}
pre.StartChecking();
}
Now, I explicitly want the classes implementing IBigPrerequisite to be able to open a window, but in case all prerequisites are met (no user interaction required) no window should be showing. I do not wish to open up a window for every class here.
I am looking for a way to, say, give the IBigPrerequisite (which should probably be called IPrerequisiteViewModel anyways) a property like bool RequestsWindow {get;} and have the View only created when a) the viewmodel requests it and b) no other prerequisite window is open at the time.
Note: the code here is for illustration only as I am not sure how to implement this behaviour yet. I am not experienced with these frameworks (and concepts) so if this question seems silly please bear with me.
You are mixing concepts here.
Active view management in Caliburn.Micro is handled by the Conductor class. A Conductor-derived ViewModel can display a large number of Screen-derived ViewModels (or other Conductors). Available items are stored in the Items property.
You can find a much better description at "Screens, Conductors and Composition"
MEF has nothing to do with the Conductors and the composition mechanism, although it can be used to pass a list of items to a conductor. You can define an [ImportMany] constructor parameter or public property that receives the Screens to display during initializations and store them in the conductor's Items property.
Using a constructor parameter is more elegant, as you won't have to copy the items from your property's setter to the Items property.
Finally, you shouldn't display messages when creating your views and viewmodels. This is something that should be left for a later step, eg. during the Activate method. The Conductors and MEF get the parts together and build the UI. Executing actions and talking to the user should be done only after the composition step has finished.
I am going to answer this question myself detailing how I ended up solving this.
I made a LoaderViewModel : Conductor<PropertyChangedBase>.Collection.OneActive, IChild<Shell> and gave it a Queue<PropertyChangedBase>.
It has Show/HideWindow methods by traversing the Parent-Properties until it arrives at the Window-Level.
It has Queue and Dequeue methods. Queue is used when PropertyChanged is fired on a RequestsView-Property and calls Dequeue if there's either no ActiveItem or the ActiveItem is not marked as busy. Dequeue will activate a new item if there is one in the queue and then call ShowWindow, if there is no item it will call HideWindow instead.
The initial HideWindow is done in the ViewAttached-Event since if the window is hidden, CM seems to have some strange behaviour. Here, the parallel checking of the prerequisites is started and an event-handler registered similar to the one in the first post.
Sorry for being verbose, but the code has gotten a bit lengthy. If someone wants me to post it up write a comment.
Related
This question refers to a WPF application based on PRISM 5.0 and the MVVM pattern.
Sometimes when users make decisions, that could have unwanted or negative consequences, it is very common to ask the user, if he really wants to go on and proceed.
For example:
One common way, is to ask the user with a messagebox, if he really wants to delete data, that can not be restored after deletion.
The problem is:
If I call the MessageBox inside the ViewModel, the ViewModel becomes untestable from the outside.
//BAD!
public class ViewModel
{
public Boolean Delete()
{
//Blocking and therefore untestable in automatic UnitTests
MsgBoxResult result = MsgBox.Show("Do you really want to delete?");
if (result == yes) {//Do stuff that deletes data here;}
}
}
One possibility would be, to ask the question in a different private method, that calls the public method
//BETTER, BUT OK?
public class ViewModel
{
private void OnDeleteAction
{
MsgBoxResult result = MsgBox.Show("Do you really want to delete?");
if (result == yes) {Delete();}
}
public Boolean Delete()
{
//Testable from the outside again, because no blocking question
//Do stuff that deletes data here
}
My question: Is is this a good way or is there a more elegant way to ask the user inside a ViewModel? Can you give me a hint or link, what is the best for PRISM 5.0?
I know, that a rule of thumb is, not to use any UI elements in the ViewModel, but I see no alternative to a blocking MessageBox or something else, that blocks the process, before proceeding.
Thank you any hints!
There are two alternatives that I know of which can reduce coupling between View and ViewModel: using an interaction service, and firing interaction requests. Both are explained very well here; you might want to take a look.
The general idea is that you abstract how asynchronous interactions are done and work with something more similar to event-based logic while at the same time allowing the ViewModel to express that it wants to interact with the user as part of an operation; the net result is that you can document this interaction and unit test it.
Prism Interactivity is the way to go here. This allows you to do Confirmations, Notifications, and create custom dialogs that work well with the MVVM pattern. I use them successfully in my Prism applications.
Here are some links to some code in the Prism repo on GitHub:
Notification Request
Confirmation Request
Custom Content
Custom Request
I am writing a piece of software in c# .net 4.0 and am running into a wall in making sure that the code-base is extensible, re-usable and flexible in a particular area.
We have data coming into it that needs to be broken down in discrete organizational units. These units will need to be changed, sorted, deleted, and added to as the company grows.
No matter how we slice the data structure we keep running into a boat-load of conditional statements (upwards of 100 or so to start) that we are trying to avoid, allowing us to modify the OUs easily.
We are hoping to find an object-oriented method that would allow us to route the object to different workflows based on properties of that object without having to add switch statements every time.
So, for example, let's say I have an object called "Order" come into the system. This object has 'orderItems' inside of it. Each of those different kinds of 'orderItems' would need to fire a different function in the code to be handled appropriately. Each 'orderItem' has a different workflow. The conditional looks basically like this -
if(order.orderitem == 'photo')
{do this}
else if(order.orderitem == 'canvas')
{do this}
edit: Trying to clarify.
I'm not sure your question is very well defined, you need a lot more specifics here - a sample piece of data, sample piece of code, what have you tried...
No matter how we slice the data structure we keep running into a boat-load of conditional statements (upwards of 100 or so to start) that we are trying to avoid
This usually means you're trying to encode data in your code - just add a data field (or a few).
Chances are your ifs are linked to each other, it's hard to come up with 100 independent ifs - that would imply you have 100 independent branches for 100 independent data conditions. I haven't encountered such a thing in my career that really would require hard-coding 100 ifs.
Worst case scenario you can make an additional data field contain a config file or even a script of your choice. Either case - your data is incomplete if you need 100 ifs
With the update you've put in your question here's one simple approach, kind of low tech. You can do better with dependency injection and some configuration but that can get excessive too, so be careful:
public class OrderHandler{
public static Dictionary<string,OrderHandler> Handlers = new Dictionary<string,OrderHandler>(){
{"photo", new PhotoHandler()},
{"canvas", new CanvasHandler()},
};
public virtual void Handle(Order order){
var handler = handlers[order.OrderType];
handler.Handle(order);
}
}
public class PhotoHandler: OrderHandler{...}
public class CanvasHandler: OrderHandler{...}
What you could do is called - "Message Based Routing" or "Message Content Based" Routing - depending on how you implement it.
In short, instead of using conditional statements in your business logic, you should implement organizational units to look for the messages they are interested in.
For example:
Say your organization has following departments - "Plant Products", "Paper Products", "Utilities". Say there is only one place where the orders come in - Ordering (module).
here is a sample incoming message.
Party:"ABC Cop"
Department: "Plant Product"
Qty: 50
Product: "Some plan"
Publish out a message with this information. In the module that processes orders for "Plant Products" configure it such that it listens to a message that has "Department = Plant Products". This way, you push the onus on the department modules instead of on the main ordering module.
You can do this using NServiceBus, BizTalk, or any other ESB you might already have.
This is how you do in BizTalk and this is how you can do in NServiceBus
Have you considered sub-typing OrderItem?
public class PhotoOrderItem : OrderItem {}
public class CanvasOrderItem : OrderItem {}
Another option would be to use the Strategy pattern. Add an extra property to your OrderItem class definition for the OrderProcessStrategy and use a PhotoOrderStrategy/CanvasOrderStrategy to contain all of the different logic.
public class OrderItem{
public IOrderItemStrategy Strategy;
}
public interface IOrderItemStrategy{
public void Checkout();
public Control CheckoutStub{get;}
public bool PreCheckoutValidate();
}
public class PhotoOrderStrategy : IOrderItemStrategy{}
public class CanvasOrderStrategy : IOrderItemStrategy{}
Taking the specific example:
You could have some Evaluator that takes an order and iterates each line item. Instead of processing if logic raise events that carry in their event arguments the photo, canvas details.
Have a collection of objects 'Initiators' that define: 1)an handler that can process Evaluator messages, 2)a simple bool that can be set to indicate if they know what to do with something in the message, and 3)an Action or Process method which can perform or initiate the workflow. Design an interface to abstract these.
Issue the messages. Visit each Initiator, ask it if it can process the lineItem if it can tell it to do so. The processing is kicked off by the 'initiators' and they can call other workflows etc.
Name the pieces outlined above whatever best suits your domain. This should offer some flexibility. Problems may arise depending on concurrent processing requirements and workflow dependencies between the Initiators.
In general, without knowing a lot more detail, size of the project, workflows, use cases etc it is hard to comment.
I'm currently writing a rather small desktop application using the MVVM Approach. It also utilizes Entity Framework 6 for the database access. Right now, my top-level ViewModel instantiates the 'smaller' ones, and passes them the DbContext I'm using. The smaller ViewModels I use correspond to UserControls sitting in a separate TabItem each. But if I change something in the database in one tab and switch the tab afterwards, the UI isn't keeping up, logically, since there is no OnPropertyChanged("SomeObservableCollection") Happening.
I thought about just "refreshing everything inside" when a TabItem becomes active, but on one hand, I don't know how to do this (it would basically be doing OnPropertyChanged(..) for every UI-relevant property, right?), and on the other hand, it does seem neither elegant nor 'correct'.
What should I do about this? And is using one global DbContext even good practice? I read about short-lived DbContext instances being better, but I also found the opposite statement regarding desktop applications...
How do you handle this scenario? It can't be that rare actually, can it? Thanks!
You have to look at using a Messenger (MvvMLight) or EventAggregator (Caliburn.Micro).
So when your context has changed you pass the message about it and update your SomeObservableCollection so OnPropertyChanged("SomeObservableCollection") will be raised.
Might Help . I have done this in small project . any better solutions are welcomed.
**Viewmodel 1 Where changes occurs**
//database call
string result = _dataService.Insert(data);
if(result=="Success")
{
//notify viewmodels using default messenger instance
MessengerInstance.Send(new NotificationMessage("notifycollection"));
}
Viewmodel 2 where we receive notification
public AssignTimeSlotViewModel(IDataService dataService)
{
// registering the notification
MessengerInstance.Register<NotificationMessage>(this, receiveNotification);
}
#region Messenger - receivers
private void receiveNotification(NotificationMessage msg)
{
if (msg.Notification == "notifycollection")
{
/// Call Database to keep collection updated.
// raise propety changed event if neccessary.
// Do Something
}
}
#endregion
Thats not an easy subject at all.
If you handle with a small amount of data and performance is not a problem for you, you could update your bindings every time the view gets loaded. Here you can see how to accomplish that.
A Problem if you do that is, that you have to do some extra logic for saving last selected items and reselect them after the view gets loaded.
Using a messenger could be an option too. But in my experience the messenger could make thinks messy if it is not implemented correctly. For example please dont use some magic strings as messeages.
Is anything really wrong with a ViewModel opening additonal dialogues? Lets say I have a MainView and a MainViewModel. The MainViewModel is the datacontext for the MainView and does not, in fact, know or have any dependency on the mainview itself.
However, there are cases when the main view need to open dialogues that will affect the ViewModel data. For example, I may want show a dialogue and diplay some items to allow the users to select from. So, what I have settled on is this:
In my ViewModel, I have the following methods: AddItem, EditItem, and DeleteItem. However, in order to supply the items to add or edit, I need to present a list in some dialogue for the user to to choose from. Right now I have the ViewModel doing this only because I don't want to implement additional levels of abstraction for such simple tasks. Having the ViewModel do this means it can provide the list to be displayed to the user and, when the user finishes editing or selecting, it can easily update its member collections/properties.
Should I be shot for settling with this approach?
Shot? No. But there are good reasons for not doing this.
First, it kills testability of your ViewModel, as there's now a visual component in place. When you try to write automated unit tests against it, you'll still have to interact with it. You could mock it out, but it becomes more difficult to do so when you're calling UI methods.
Second, your viewmodel shouldn't care about what gets displayed. There's a real "separation of concern" issue when you start combining these things.
Third, it just has a "code smell."
There are a few things you can do to circumvent this issue. The first thing I would suggest is Don't use dialogs. Dialogs have their place, but programmers tend to overuse them. Rethink your design, and try to figure out how you can get the job done without interrupting the user.
Second, consider using a messaging framework to send messages between your viewmodel and view to do the navigation to the dialogs (if you absolutely have to use them). Messages are very easy to mock out and/or write unit tests around.
the easy way to do this: use a dialogservice - easy to use, easy to unittest!
see this.
I don't see any problems with ViewModels communicating with each other. The problem is if they start accessing the Views or other Dialogs since that will affect the systems testability.
If you really want a more loosely coupled system you could use some sort of messaging system for communication, but I doubt you need that here :-)
I always use a Seelctor service(just a basic dialog service) to do this - it's testable and mockable and keeps the code very SOLID.
class ViewModel
{
public ICommand ShowListSelectorForCounterparties { get; set; }
public IListSelectorService ListSelector { get; set; }
public void OnExecuteShowCounterpartySelector()
{
this.Counterparty = this.ListSelector.Select<Counterparty>();
}
}
where IListSelectorService can, at runtime, instantiate your dialog, present your list and return the selected item. The main good thing about running it this way is that your unit tests can mock the IListSelectorService.
I'm not sure if you are still looking for any help, but the approach that I have taken when it comes to dialogs is to have the view model raise an event that the view can then handle. The view can now do whatever it wants to get the data to the view model, so you can disply the dialog in the view without a problem. You pass the response from the dialog to the EventArgs of your event so that the view model has the data it is looking for in order to proceed.
For example:
Public Class View
Private WithEvents _VM AS new ViewModel()
Private Sub _VM_AddingItem(Sender AS Object, E AS ViewModel.ItemEventArgs)
Dim Dialog As new SomeDialog()
If Dialog.ShowDialog then
E.Item = Dialog.Item
Else
E.Cancel = True
End If
End Sub
End Class
Public Class ViewModel
Public Sub AddItem(Item AS Object)
Do Some Work here
End Sub
Private Sub _AddItem()
Dim Args AS New ItemEventArgs()
OnAddingItem(Args)
If not Args.Cancel Then AddItem(Args.Item)
End Sub
Protected Sub OnAddingItem()
RaiseEvent AddingItem(me, ItemEventArgs)
End Sub
Public Event AddingItem(Sender AS Object, E As ItemEventArgs)
Public Class ItemEventArgs
Public Property Item AS Object
Public Property Cancel AS Boolean = false
End Class
End Class
Then just wire up your command to the private _AddItem method which just raises the event to collect the necessary data for the AddItem method. I hope this helps :)
So I have a database (sql) management program I have been working on, dealing with items my company sells. For the main part of the program the item information is updated as the user goes through using some custom controls. That all works fine. But now I am on to the higher level section of the program that is adding/deleting/copying items. This cannot be "update on the fly", like editing item information, as it would be too easy to screw things up very badly. So I basically want to set up a file-> save type of deal for them here. How I see this working is creating all of the sql commands in a list and then running them all when saving.
The functions available here would be adding a new item, deleting an item, copying from another item, and renaming.
So it would be a list like:
insert...
update...
update...
delete...
update...
etc.
It would run through and execute all of the commands. The problem I am having is I already have a class that has methods to handle all of these functions. I can't think of a way to call all of those methods in a queue, and rewriting all the sql statements in another class seems stupid to me. Is there a way that I can remember a list of something like:
item.Rename()
item.ChangeSize()
item.Delete()
I feel like I'm overthinking this... or maybe underthinking... I don't know.
What you are looking for is a Command Pattern.
The basic idea is that you have an ICommand Interface which has a method Execute().
Then you implement multiple ConcreteCommand, e.g. a RenameCommand with a parameterized constructor or a property NewName.
Dont't forget to handle exceptions accordingly and maybe implement an Undo-Method as well, if these could occur. I don't know enough about your application to make assumptions here.
public interface ICommand
{
void Execute();
}
public class RenameCommand : ICommand
{
private string newName;
public RenameCommand(string newName)
{
this.newName = newName;
}
void ICommand.Execute()
{
item.rename(newName);
}
}