Md. Parwez Akhtar
Md. Parwez Akhtar

Reputation: 176

How to instantiate a dialog and record user input while MVVM pattern is used to create dialog in WPF

I am a C++ developer and new to WPF and MVVM. please bear with me if I choose any wrong word to ask my question

I have my Main application in MFC/C++ which is passing some data to C# library(CLI is used as middle layer). In C# library, there is a section of code where a dialog is opened , data is filled and user selection is notified to the calling object in below way -

public classA()
{
    MyDialog dlg = new MyDialog(param1, param2, param3)
    if(dlg.ShowDialog().GetValueOrDefault())
    {
        var name = dlg.name;
        var roll = dlg.roll;
    }
    else
    {
        var name = string.Empty;
        var roll = string.Empty;
    }
}

Now Dialog has been modified and implemented using MVVM pattern.

I have created below files as part of implementation- 1

  1. MyDialogView.Xaml
  2. MyDialogView.xaml.cs
  3. MyDialogViewModel.cs
  4. MyDialogModel.cs

My question is, how to instantiate the new dialog now from my classA so that data is filled using the parameters passed to dialog in same way as previously it was doing and record user selection without loosing any data and safely closing the view.

Upvotes: 0

Views: 1212

Answers (2)

dotNET
dotNET

Reputation: 35380

Standard MVVM approach works like this (at least when using MVVM Light):

  1. You have a VM layer, a Class Library.
  2. You have a View layer, a WPF Controls Library or WPF Application.
  3. View layer adds reference to VM layer. VM layer doesn't know anything about View.
  4. You create a normal public class for your dialog's VM. Call it DialogVM or whatever. Make sure this class inherits from MVVM Light's built-in ViewModelBase. This will get you access to change notification methods provided by MVVM Light. Might look like this in your case:

    public partial class DialogVM : ViewModelBase
    {
        private string _Name;
        public string Name
        {
          get { return _Name; }
          set { Set(ref _Name, value); }
        }
    
        private string _Roll;
        public string Roll
        {
          get { return _Roll; }
          set { Set(ref _Roll, value); }
        }
    }
    
  5. VM layer has a global static class called ViewModelLocator. This class performs IoC/DI and provides public static properties to expose different VMs. (In your case your dialog's VM goes to the VM project and the ViewModelLocator looks something like this:

    using System;
    
    namespace VMLayer
    {
      public class ViewModelLocator
      {
        static ViewModelLocator()
        {
          SimpleIoc.Default.Register<DialogVM>(true);
        }
    
        public static DialogVM MyDialog => SimpleIoc.Default.GetInstance<DialogVM>();
      }
    }
    
  6. Your dialog box (a Window) goes to View layer and uses this exposed property MyDialog to provide a DataContext for the dialog:

    <Window x:Class="GlasshouseTestingShell.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:vm="clr-namespace:VMLayer;assembly=VMLayer"
        DataContext="{x:Static vm:ViewModelLocator.MyDialog}"
        d:DataContext="{d:DesignInstance Type=vm:DialogVM}">
    </Window>
    
  7. Look how cleanly we have created View layer's DataContext without writing a line of C# code in the View layer. This is also elegant in the sense that you get all design-time Intellisense in Binding expressions and elsewhere.
  8. You now bind all your UI stuff (textboxes, buttons etc.) to the public properties and commands exposed by your dialog's VM. Still no lines in the code-behind. Might look like this in your case:

    <TextBox Text="{Binding Name}" />
    

Rest of the stuff is in C++:

  1. You add reference to your View and VM DLLs in your C++ project.
  2. Create an object of your dialog. It will automatically instantiate its VM and perform binding. You call ShowDialog() to bring it to screen.
  3. Use takes actions in the dialog and finally presses OK or Cancel.
  4. You capture dialog result and then access your dialog object's DataContext property, which is an object of DialogVM class. You can access user-supplied values from therein as Binding has updated those properties for you in the VM.

Upvotes: 3

Andy
Andy

Reputation: 12276

I'm not sure I follow all of your requirements but this is roughly how I'd approach such a task:

Instantiate the view and viewmodel in class A.

Set whatever parameters you want on your viewmodel. Either as properties or via constructor injection.

Set the datacontext of the view to the viewmodel.

Everything you need to bind should then bind between them.

showdialog the view.

The user edits in the view and changes persist to the viewmodel properties.

They finish editing and you then work with the viewmodel properties. Maybe one of them is the model you mention. Maybe the model is instantiated by the viewmodel to get data or by classA if that is more convenient. In the latter case you probably have to pass that model to the viewmodel.

Bearing in mind the above.

Some rough code:

public class ClassA
{
    MyDialogViewModel vm = new MyDialogViewModel { Name = "X", Roll = "Y" };
    MyDialog dlg = new MyDialog();
    dlg.ShowDialog();
    var name = vm.Name;
    var roll = vm.roll;

    // Do something to persist your data as necessary. Either here or in a model within the viewmodel
}

Name and Roll presumably bind to some textboxes Text properties in the view or some such.

If it's as simple as obtaining two string values then I see no advantage to actually having a model at all. On the other hand, if processing is more involved then of course the viewmodel might instantiate a model.

MyDialogViewModel should implement inotifypropertychanged and anything you need to bind should be a public property. Not sure if you'll need propertychanged notification but always implement it. Optionally raise propertychanged from property setters.

Upvotes: 1

Related Questions