简体   繁体   中英

WPF MVVM - Display Form in VM

I am new to MVVM and if I am doing any logic wrong please let me know.

Basically frmEpisodeView.xaml should be the startup window which is set here:

StartupUri="View/frmEpisodeView.xaml"

When this windows load's I want to check if the user has already used the application and there is a registry key available.

I have set datacontext for frmEpisodeView.xaml from the code behind as below

DataContext = new EpisodeViewModel();

In My EpisodeViewModel.cs I do the logic to check the registry key

public EpisodeViewModel() {

    if (Registry.GetValue("HKEY_CURRENT_USER", "URL", "") == null)
    {        
        //OPEN FORM HERE FRMLOGINVIEW.XAML
        ServerURL = Registry.GetValue("HKEY_CURRENT_USER", "URL", "").ToString();
    }
}

In the logic if the registry key is empty, a form should appear where the user logs in which then will save the entry on that page.

How can I get the form to appear?

The cleanest and i think easiest way to do this, is to write a helper class. Create an Interface for this Service and and then implement a method ShowWindow(object DataContext) to show a window you like and set the datacontext.

class WindowService:IWindowService
{
    public void showWindow<T>(object DataContext) where T: Window, new() 
    {
     ChildWindow window = new T();
     window.Datacontext = DataContext;
     window.Show();
    }
}

Another very elegant way is using an Action like this ( Source ):

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        DataContext = new MainViewModel(() => (new Window()).Show()); // would be actual window
    }
}

public class MainViewModel
{
    private Action popupAction;
    public MainViewModel(Action popupAction)
    {
        this.popupAction = popupAction;
    }

    public ICommand PopupCommand { get; set; }

    public void PopupCommandAction()
    {
        popupAction();
    }
}

public class SomeUnitTest
{
    public void TestVM()
    {
        var vm = new MainViewModel(() => { });
    }
}

So how I would initially lay out this as a quick example.

ViewModel

public class EpisodeViewModel
{
    private readonly IEpisodeModel episodeModel;

    private readonly IViewFinder viewFinder;

    public EpisodeViewModel(IEpisodeModel episodeModel, IViewFinder viewFnder)
    {
        this.episodeModel = episodeModel;
        this.viewFinder = viewFinder;
        CheckLoginPassed(this.episodeModel.LoginPassed);
    }

    private CheckLoginPassed(bool loginPassed)
    {
        if (!loginPassed)
        {
            this.viewFinder.LoadView<ILoginView>();
        }
    }
}

IView Interface

public interface IView
{
    void Show();
}

Model Interface

public interface IEpisodeModel
{
    bool LoginPassed
    {
        get;
    }
}

Model

public class EpisodeModel : IEpisodeModel
{
    private bool loginPassed;

    public EpisodeModel()
    {
        if (Registry.GetValue("HKEY_CURRENT_USER", "URL", "") == null)
        {
            loginPassed = false;
        }
    }

    public bool LoginPassed
    {
        get
        {
            return this.loginPassed;
        }
    }
}

IViewFinder Interface

public interface IViewFinder
{
    void LoadView<T>();
}

ViewFinder

public class ViewFinder : IViewFinder
{
    private readonly IEnumerable<IView> availableViews;

    public ViewFinder(IEnumerable<IView> availableViews)
    {
        this.availableViews = availableViews;
    }

    public void LoadView<T>()
    {
        var type = typeof(T);

        foreach (var view in this.availableViews)
        {
            if (view.GetType().IsAssignableFrom(type))
            {
                view.Show();
            }
        }
    }

I've written this with using an IoC in mind, if you don't have one I'd really look to getting one as it will be a massive help when resolving dependencies. This is just a basic example and I'd probably have a different object that was only for checking the registry that I provided the results to the Model from, but this should provide a start.

So in referring to the ILoginView this is an interface that simply inherits from IView , it doesn't actually provide any details. The IView interface is slightly weird as your views already implements a Show method whenever they also inherit from 'Window' so in effect you don't have to do anything, this simply provides an easier way to call show without having to actually know that what you are calling is a Window .

Another point is that my ViewFinder is relatively simple here although it would do for a small project I would probably look at something like MVVM Light to manage my MVVM handling as this comes with View handling and a simple Service Locator as standard.

Yes, this is a typical problem when doing MVVM. Many of these problems can be generalized as: How do I do this or that concrete "thing" in the concrete user interface as I should stick 100% inside my view model?

This kind and many other related problems have excellent answers in https://msdn.microsoft.com/en-us/library/gg406140.aspx (Developer's Guide to Microsoft Prism Library 5.0 for WPF) which I would highly recommend to you.

Personally I found it a great pleasure to read the book and the authors obviously know what they express themselves about.

Best regards,

Henrik Dahl

You could always put this view code in the App.xaml.cs constructor:

public App()
{
    if (Registry.GetValue("HKEY_CURRENT_USER", "URL", "") == null)
    {        
        //OPEN FORM HERE FRMLOGINVIEW.XAML
        StartupUri = new Uri("View/frmLoginView.xaml", UriKind.Relative);

        ServerURL = Registry.GetValue("HKEY_CURRENT_USER", "URL", "").ToString();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM