.NET Framework Bookmark and Share   
 index > Windows Presentation Foundation (WPF) > MVVM newbie question: simple modal dialogs
 

MVVM newbie question: simple modal dialogs

Hi group, I'm just starting with MVVM, using as a starting point the tutorials in MS MVVM Toolkit,and I have a trivial question to start with: say I have a file-open command of some sort:say I have aviewwith a button which should open the standard file-open dialog to let user choose the file; my viewmodel class in turn has an OpenFile command receving the file name as a parameter.
So the question is: where should I place the code for the OpenFileDialog? I cannot place it in the viewmodel, which requires to be tested without user interventions, so I must place it in the view; but this means that I have to handle the button click event and add some code behind which first opens the dialog and then invokes the command, rather than simply binding the button to the command in XAML. Of course every MVVM approach must face some practical compromises, I'd just like to know if there is any suggested way of handling these trivial cases.
Thanks!
Naftis
Hi Naftis,

Could you have an additional class which implements the dialog behaviour (inversion of control if you like) contained by the existing ViewModel which is currently opening your dialog? During your unit tests you could then pass a different implementation of this class (with a common interface or base class) which doesn't rely on user interaction but just passes back the desired value.

I hope this makes sense (it's quite early in the morning, I don't think I've quite woken up yet!)

Gareth


Gareth Wynn
Some people do this by introducing the concept of a "View service", which is an interface that the VM holds and can call intoto displaymessageboxes or dialogs; the interface can be stubbed/mocked for testing. Others feel that this violates the spirit of MVVM because the VM does have a reference to a view-like object (not its actual view, mind you, but something that can affect the view).

I don't see anything wrong with the interface approach. However, there's a lot of work being done on using the Mediator pattern to make this more pure (Google for MVVM Mediator). The VM can have a reference to a mediator object, optionally usinga form of dependency injection, and use that to send messages. To me, this doesn't seem much different because logically there's still a concept of a "View service" - it's just addressed using messages instead of an interface.

-Steve
Programming blog: http://nitoprograms.blogspot.com/
Including my TCP/IP .NET Sockets FAQ
MSBuild user? Try out the DynamicExecute task in the MSBuild Extension Pack source; it's currently in Beta so get your comments in!
I will be at the Grand Rapids BarCamp 4 unconference - come on by, fellow Michiganders!
Stephen Cleary

Hi Naftis,

At present, Ihave no ideas withthe suggested way of this scenario. But as in my view, you can add the code which needs user interaction at last. Whentesting the OpenFile command method, we canpass theFileName to the method from test method. And after we assure the logic has no problems, we can then add the interaction code.

As an alternative, as you said, we can handle the button click event and add the code to open a file dialog. After that, we can pass the opened filename to the command through CommandParameter. In case you need, I just wrote the following code for your reference.

Xaml code:

                <MenuItem Command="{Binding ReadmeCommand}" Header="Readme" Click="MenuItem_Click">
                    <MenuItem.CommandParameter>
                        <Binding Source="{StaticResource data}" Path="FileName" Mode="TwoWay"></Binding>
                    </MenuItem.CommandParameter>
                </MenuItem>

C# code:

    public partial class MainView : Window
    {


        CommandData data;
        public MainView()
        {
            InitializeComponent();
            data = this.FindResource("data") as CommandData;
 
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            if (dialog.ShowDialog() == true)
            {
                data.FileName = dialog.FileName;
            }
                
        }
    }
    public class CommandData:INotifyPropertyChanged 
    {
        private string fileName;

        public string FileName
        {
            get
            {
                return fileName;
            }
            set
            {

                fileName = value;
                if (null != this.PropertyChanged)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("FileName"));
                }
            }
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
 
    }

If you have any problems with this, please feel free to let me know.


Best regards,
Bruce Zhou


Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
Bruce.Zhou
Thank you very much for the reply!
Anyway, it seems there is no simple solution for such trivial tasks: breaking rules using code behind, or some "spaghetti" code (somewhat like setting a hidden field in a HTML form to be later used by code). No sample of MVVM applications I've looked at until now deal with things like message boxes and the like, yet it's a rather trivial scenario.

Another one is exception handling: typically in my traditional WPF apps I catch some exception in code behind and display some message box; here instead I cannot put them in the viewmodel (which must remain testable without interactivity; and also, there is -as expected- no way the VM can know about the window consuming it); so I'm left with either (a) handle exception in code behind, with the same problems already seen (I must handle the click event and wrap the code in a try...catch block) or (b) use a generic unhandled exception handler at the application level, which is not appealing in many cases.

Anyway, I'll try going further moving from MVVM toolkit to the much more mature (and complex :) Prism and see if there I can find patterns for handling such scenarios. Probably it's just that I'm still thinking in an uncorrect way when looking at these models...

Thank you again
Naftis

Hi Naftis,

The problem comes to youdue tothe requirement thattest can't be blocked by user interaction. As before, I thinksuch kind of code can be added at last.For example, exception handling, we can log the exception into a file instead of displaying a messagebox in the test phase, and after all test passed, we can replace the log code with message box popup code.


Best regards,
Bruce Zhou


Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
Bruce.Zhou
Hi Naftis,

Could you have an additional class which implements the dialog behaviour (inversion of control if you like) contained by the existing ViewModel which is currently opening your dialog? During your unit tests you could then pass a different implementation of this class (with a common interface or base class) which doesn't rely on user interaction but just passes back the desired value.

I hope this makes sense (it's quite early in the morning, I don't think I've quite woken up yet!)

Gareth


Gareth Wynn

Thanks guys! This gives me different options, even if all require some "trick", but it's useful to know that I'm not missing something capital in my learning of this pattern. At any rate, as for your suggestions, such things (dialogs or exception messages) would be placed in the VM (either as conditional code or as Gareth suggests), not in the view, and this would be fine for allowing us to directly link user interface controls to VM commands without "polluting" the view with code behind.
Anyway, displaying e.g. a message box or a dialog from the VM seems to me (but maybe I'm just misunderstanding) somewhat a pattern-breaker, as I was inclined to think the VM as a totally view-agnostic, UI-less presenter layer; of course, the alternative is breaking the direct V-VM connection via binding and add some code behind in the view, but I don't know which would be "best" (or maybe it's just a matter of taste). Apart from this generic issue, I might find problems in using UI pieces in the VM: say for instance I must center a dialog in the owner window: in code behind I just set the Window's Owner property= this (or use a GetWindow(this) if it's a user control), but of course in a VM there is no reference to the view and thus no notion of the owner window. This would be another reason to add some code behind in the view, rather than coding in the VM. Anyway, thanks to all for the discussion, this allows newbies like me to have some more understanding of this pattern!

Naftis
Some people do this by introducing the concept of a "View service", which is an interface that the VM holds and can call intoto displaymessageboxes or dialogs; the interface can be stubbed/mocked for testing. Others feel that this violates the spirit of MVVM because the VM does have a reference to a view-like object (not its actual view, mind you, but something that can affect the view).

I don't see anything wrong with the interface approach. However, there's a lot of work being done on using the Mediator pattern to make this more pure (Google for MVVM Mediator). The VM can have a reference to a mediator object, optionally usinga form of dependency injection, and use that to send messages. To me, this doesn't seem much different because logically there's still a concept of a "View service" - it's just addressed using messages instead of an interface.

-Steve
Programming blog: http://nitoprograms.blogspot.com/
Including my TCP/IP .NET Sockets FAQ
MSBuild user? Try out the DynamicExecute task in the MSBuild Extension Pack source; it's currently in Beta so get your comments in!
I will be at the Grand Rapids BarCamp 4 unconference - come on by, fellow Michiganders!
Stephen Cleary
Thanks Stephen, I'll definitely have to look further into your suggestions, the mediator pattern and its current implementations; as for these, there are even too many implementations and frameworks floating around, but I'd like to stick with the most mature and MS-supported asin my projects Imust avoid 3rd party solutions. So after a start with MVVM Toolkit, which is probably too immature to be used, I was thinking of learning Prism, which seems to have a solid foundation even if it's documentation looks a little intimidating. Probably I'll have to eat the elephant one bit at a time... Do you guys know any useful tutorial or resource about this framework?
Naftis
Hi,
In codeplex where you download Prism you have good tutorials. Check the link:

http://www.codeplex.com/CompositeWPF

Regards,
Federico Benitez
My blog
Federico Benitez
We are using the solutionGareth and Stephen mentioned for a while (Separate services for Open-, SaveFileDialog and MessageBox). We have different implementations of this services for application and unit testing (mocks). It works fine for us. We are usingitalso withWindows.Forms(MVP).

As you sayed there are several implementations addressing your problem, take one that fits and go on.

You should not fear to break MVVM, because each one is taking a different view on this pattern.MVVM will evolve over time and we will see how this thingsshould be done the right (best) way in the future.

And YES, wehave codebehind we using TypeConvertersand sometimes we bind the Model directly to the View. MVVM is not the Holy Grail, its only a pattern.
Guenter Schwaiger
Just my 2 cents worth, but I can't help but be skeptical about all this MVVM ideology. Is tying your hands and jumping through hoops to do the simplest thing going to produce more sophisticated, intuitive software? I guess time will tell.

cz
cdfadsfgadfgfgwadgfwre
I was also skeptical at first. MVVM still has a few rough edges, like multiselection, and nicely sidesteps serious concerns like background processing and transaction logic by pushing them to the business layer.

However, MVVM more than makes up for it with its testability, IMO. That is the single most important advantage, so much so that I'm pushing my company to adopt MVVM on a mobile device (which doesn't support WPF, so we would end up with Windows forms connected to a ViewModel via code-behind). Other people stress the designer/developer separation that MVVM achieves, but I just haven't seen the reality of that one in my projects(yet).

I view MVVM as a set of good guidelines, not a strict set of rules. That's why I have yet to use a dependency injection framework - it just seems like overkill to introduce all that complexity just to hook up a few classes. So I end up with a dozen lines of initialization code for my MVVM projects, and to be honest it doesn't really bother me that much. :)

Back to the original point: I use MVVM because of its testability. Moving the view logic to the ViewModel enables unit testing (and regression testing!) of the view without having to use "program runner" programs. If you already have a decent business layer (and you should), then supporting MVVM is not much more thanintroducing ObservableCollection and INotifyPropertyChanged to the business layer and pulling all the code behind into a data-oriented ViewModel.

-Steve
Programming blog: http://nitoprograms.blogspot.com/
Including my TCP/IP .NET Sockets FAQ
MSBuild user? Try out the DynamicExecute task in the MSBuild Extension Pack source; it's currently in Beta so get your comments in!
I will be at the Grand Rapids BarCamp 4 unconference - come on by, fellow Michiganders!
Stephen Cleary
In the ViewModel layer, through the following line code, you should be able to find the Main window

System.Windows.Application.Current.MainWindow

-Jane
JJChen

You can use google to search for other answers

Custom Search

More Threads

• WPF UserControl
• Resize Notification Missing ?- Repost
• How to animate custom element in WPF?
• Getting Browser close event in xbap
• Is there any way to control the increment of a ScrollViewer?
• Keydown does not get fired up
• ItemsControl. How to customize selection indication?
• WPF - Is this a fit? Composite WPF (Prism), multiple screens/controls & 3rd Party Controls (Docking, Ribbon)
• UI Automation issue isung the Tab Control.
• How to modify DataTemplate Child Element Binding