如何在MVVM Light和WPF中从Parent创建子窗口?

时间:2014-01-10 21:59:55

标签: c# wpf mvvm

我的主窗口上有一个按钮。当我点击它时,我希望在主窗口顶部弹出另一个窗口。

主窗口仍然可见,应该是这个新窗口的父窗口。

我一直在寻找并且不确定如何做到这一点,有些人建议使用Messenger来做到这一点,但并没有真正举一个例子。

1 个答案:

答案 0 :(得分:0)

嗨我没有MVVMLight所以我使用了自定义Messanger,因为它可以让图片更加清晰。

  

消息类型

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

消息

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; }
}
  

信使

    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)
    { 

    }

}
  

查看

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这里的第一个元素不是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));
    }
}
  

视图模型

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"));
    }
}

我希望这会有所帮助。这是一个易于理解的简单代码。