简体   繁体   中英

How to Create a Child Window From Parent in MVVM Light and WPF?

I have a button on my Main Window. When I click it I want another Window to popup on top of the Main Window.

Main Window is still visible and should be the parent of this new window.

I been looking around and not sure how to do it, some people suggested to use the Messenger to do this but did not really give an example.

Hi I didnt have MVVMLight so I have used custom Messanger because to make picture clearer how things work.

MessageType

public enum MessageType
{ 
    DataLoaded,
    OpenWindow,
    SetFocus,
    OpenExceptionWindow,
    Refresh
    //etc
}

Message

public class Message
{
    public Message(MessageType messageType, object message)
    {
        MessageType = messageType;
        MessageObject = message;
    }

    public MessageType MessageType { get; private set; }
    public object MessageObject { get; private set; }
}

Messanger

    public class Messanger
{
    //Singleton
    private Messanger()
    { }

    static Messanger instance;
    public static Messanger Instance
    { 
        get{return instance ?? (instance=new Messanger());}
    }

    static Dictionary<string, Action<Message>> dictionary = new Dictionary<string, Action<Message>>();

    //View Calls this and register the delegate corresponding to the unique token
    public void Register(string token,Action<Message> action)
    {
        if (dictionary.ContainsKey(token))
            throw new Exception("Already registered");
        if (action == null)
            throw new ArgumentNullException("action is null");

        dictionary.Add(token, action);
    }

    public void UnRegister(string token)
    { 
        if(dictionary.ContainsKey(token))
            dictionary.Remove(token);
    }

    //ViewModel Calls this and pass the token and Message.
    //the registered delegate is looked up in dictionary corresponding to that token and
    //Corresponding register delegate fired.
    public void SendMessage(string token,Message message)
    {
        if (dictionary.ContainsKey(token))
            dictionary[token](message);
    }
}

ViewBase

 public class ViewBase:Window
{
    protected  string Token { get; private set; }

    public ViewBase()
    {
        Token = Guid.NewGuid().ToString();

        //Register to Messanger
        Messanger.Instance.Register(Token, HandleMessages);

        //UnRegister On Closing or Closed
        this.Closing +=(s,e)=> Messanger.Instance.UnRegister(Token);
    }

    //Handle Common Messages to all Windows Here
    void HandleMessages(Message message)
    {
        switch (message.MessageType)
        { 
            case MessageType.OpenExceptionWindow:
                Exception ex = message.MessageObject as Exception;
                ExceptionWindow window = new ExceptionWindow();
                window.Exception = ex;
                window.ShowDialog();
                break;
                //other common cases should be handled here

            default : HandleWindowLevelMessage(message);
                break;

        }

    }

    protected virtual void HandleWindowLevelMessage(Message message)
    { 

    }

}

View

public partial class Mywindow : ViewBase
{
    public Mywindow()
    {
        InitializeComponent();
        DataContext = new MyViewModel(Token);
    }

    protected override void HandleWindowLevelMessage(Message message)
    {
        //open window according to OP Requirement
        if (message.MessageType == MessageType.OpenWindow)
        {
            string windowName = message.ToString();

            if (windowName != null)
            {
                //logic to get the window . I assume that OP have some logic to get the child window this is just temporary
                var window = Application.Current.Windows.OfType<Window>().FirstOrDefault(s=>s.Name==windowName);
                if (window != null)
                {
                   window.Owner=this;
                    window.Show();
                }
            }
        }

        base.HandleWindowLevelMessage(message);
    }
}

View.xaml Here first element is not Window now

<local:ViewBase x:Class="WpfApplication4.Mywindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication4"
    Title="Mywindow" Height="300" Width="300">
<Grid>
    <Button Content="ok" Click="Button_Click_1"/>
</Grid>

ViewModelBase

public class ViewModelBase : INotifyPropertyChanged
{
    public ViewModelBase(string token)
    {
        Token = token;
    }

    protected string Token { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    void RaisePropertyChanged(string propName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
}

ViewModel

public class MyViewModel : ViewModelBase
{
    public MyViewModel(string token)
        : base(token)
    {

    }

    //say OP want to open window on Command Execute
    public void OnCommand()
    {
        Messanger.Instance.SendMessage(Token, new Message(MessageType.OpenWindow, "MyChildWindow"));
    }
}

I hope this will help. This is simple code to understand feel free to ask.

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