4
votes

I am new to Wpf and following the MVVM pattern to design my application. I have a ViewModel and an View. By the design, my View knows about my ViewModel and the reverse is not. If i want to open another window upon click of a button, i could use a command and when user clicks, that command will be routed to my ViewModel.

But how would i create a window that will have it's own view and ViewModel. I am kind of confused in this. I want to invoke the new window from Xaml itself as my ViewModel does not know about the another view and probably it's viewmodel.

To keep it simple,

View1 -> (bound to) ViewModel1
View1 -> Button1.Click -> Command(bound to) ViewModel1
---- how to open View2 -> (bound to) ViewModel2------
Show View2.

Thanks

2

2 Answers

5
votes

I would just call Show from the code-behind of View 1 to open View 2. The ViewModel from View 1 should not be involved.

Like this:

private void Button_Click(object sender, RoutedEventArgs e)
{
    new View2().Show();
}

Your next thought might be "isn't this violating MVVM?" No, I wouldn't say so. The ViewModel should not have any direct control of UI elements if it is to be considered a clean implementation of MVVM. If you want something in the ViewModel to trigger the Window to open you can always use events or a 3rd party library like Caliburn to easily implement this without worrying about coupling.

1
votes

This is what i suggest to do that.because of there are no dependancy with view in another view model .simply you can write a dialog services to open any of view as popup(window). normaly Show() method use the System.Windows dependancy so better to use as service and then we can Unit test our application.

    public interface IDialogService
    {
        BaseViewModel ShowTitleDialog(BaseViewModel viewModel, UserControl view, string windowTitle);
    }

    public class DialogService : IDialogService
    {
        public BaseViewModel ShowTitleDialog(BaseViewModel viewModel, UserControl view, string windowTitle)
        {
            if (view == null && viewModel == null)
            {
                throw new ArgumentNullException("view is null");
            }

            RegisterTemplate(viewModel.GetType(), view.GetType());
            return ShowTitleDialog(viewModel, windowTitle);
        }
        private void RegisterTemplate(Type viewModelType, Type viewType)
        {
            const string xamlTemplate = "<DataTemplate DataType=\"{{x:Type vm:{0}}}\"><v:{1} /></DataTemplate>";
            var xaml = String.Format(System.Globalization.CultureInfo.InvariantCulture, xamlTemplate, viewModelType.Name, viewType.Name, viewModelType.Namespace, viewType.Namespace);

            var context = new ParserContext();

            context.XamlTypeMapper = new XamlTypeMapper(new string[0]);
            context.XamlTypeMapper.AddMappingProcessingInstruction("vm", viewModelType.Namespace, viewModelType.Assembly.FullName);
            context.XamlTypeMapper.AddMappingProcessingInstruction("v", viewType.Namespace, viewType.Assembly.FullName);

            context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
            context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
            context.XmlnsDictionary.Add("vm", "vm");
            context.XmlnsDictionary.Add("v", "v");

            var template = (DataTemplate)System.Windows.Markup.XamlReader.Parse(xaml, context);
            var key = template.DataTemplateKey;
            Application.Current.Resources[key] = template;
        }

        public BaseViewModel ShowTitleDialog(BaseViewModel viewModel, string windowTitle, bool isEnableScrollBars = false)
        {
            Window window = new Window();
            window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            ContentControl contentControl = new ContentControl();
            contentControl.Content = viewModel;

            if (!isEnableScrollBars)
            {
                window.Content = contentControl;
                window.SizeToContent = SizeToContent.WidthAndHeight; window.SizeToContent = SizeToContent.WidthAndHeight;
            }
            else
            {
                ScrollViewer scrollViewver = new ScrollViewer();
                scrollViewver.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
                scrollViewver.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
                scrollViewver.Content = contentControl;
                window.Height = 600;
                window.MaxHeight = 600;
                window.Content = scrollViewver;
            }

            window.Title = windowTitle;
            window.WindowStyle = WindowStyle.None;

            window.Owner = Application.Current.Windows.OfType<System.Windows.Window>().FirstOrDefault(x => x.IsMouseOver);
            window.ShowInTaskbar = false;
            window.ShowDialog();
            return viewModel;
        }
    }

Usage..

    class TestAViewModel
    {
      public void ClickEvent()
      {
        TestBViewModel viewModel = new TestBViewModel();
        viewModel.ShowThisView();
      }
    }

    class TestBViewModel
    {
      public void ShowThisView()
      {
         TestBViewModel viewModel = new TestBViewModel();
         TestBView view = new TestBView();
         view.DataContext = viewModel;

         IDialogService dialogCheckIn = new DialogService();
         dialogCheckIn.ShowTitleDialog(viewModel, view, "Title");
      }
    }