在WPF中的xaml视图中打开另一个窗口

时间:2014-01-08 04:50:58

标签: c# wpf xaml mvvm viewmodel

我是Wpf的新手,并遵循MVVM模式来设计我的应用程序。我有一个ViewModel和一个View。通过设计,我的View了解我的ViewModel而反之则不然。如果我想在点击按钮时打开另一个窗口,我可以使用命令,当用户点击时,该命令将被路由到我的ViewModel。

但是我如何创建一个拥有自己的视图和ViewModel的窗口。我对此感到困惑。我想从Xaml本身调用新窗口,因为我的ViewModel不知道另一个视图,可能是它的viewmodel。

为了简单起见,

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

由于

2 个答案:

答案 0 :(得分:2)

我只需从View 1的代码隐藏中调用显示即可打开View 2.不应参与View 1中的ViewModel。

像这样:

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

你的下一个想法可能是“这不是违反MVVM吗?”不,我不会这么说。如果要将ViewModel视为MVVM的干净实现,则ViewModel不应该直接控制UI元素。如果您希望ViewModel中的某些内容触发Window打开,您可以始终使用事件或第三方库(如Caliburn)轻松实现此功能,而无需担心耦合。

答案 1 :(得分:1)

这就是我建议这样做的原因。因为在另一个视图模型中没有依赖视图。只需要编写一个对话框服务来打开任何视图作为弹出窗口(窗口)。 normaly Show()方法使用System.Windows依赖性以便更好地用作服务,然后我们可以对我们的应用程序进行单元测试。

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

用法..

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