如何在C#MVVM中打开其他窗口?

如何在C#MVVM中打开其他窗口?,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个简单的问题: 在我的应用程序中,我有一个“mainview”/main窗口。 从这一点,用户可以控制所有的事情,如数据库查询,搜索等 但是我需要点击菜单按钮打开一个属性窗口 因此,我将它绑定到我的搜索窗口命令: private ICommand searchwindowcommand; public ICommand SearchWindowCommand { get { if (se

我有一个简单的问题: 在我的应用程序中,我有一个“mainview”/main窗口。 从这一点,用户可以控制所有的事情,如数据库查询,搜索等

但是我需要点击菜单按钮打开一个属性窗口

因此,我将它绑定到我的搜索窗口命令

private ICommand searchwindowcommand;

       public ICommand SearchWindowCommand
       {
           get
           {
               if (searchwindowcommand == null)
               {
                   searchwindowcommand = new RelayCommand(p => ExcecuteSearchwindowcommand());
               }
               return searchwindowcommand;
           }
       }

       public void ExcecuteSearchwindowcommand()
       {


       }
通常我会这样打开它:(我让应用程序工作,但我没有使用mvvm,现在我必须重做应用程序并计算出mvvm:)

要显示另一个窗口,我必须在Executecommand中写入什么? 我应该为另一个视图创建新的viewmodel吗?(我想是的?)

编辑: 我的Startapplikationcode:

 public partial class MainWindow : Window

{
    public MainWindow()
    {
        InitializeComponent();
        SetupBindings();
    }

    private void SetupBindings()
    {
        pViewModelList viewModel = new pViewModelList();

        personlistview.DataContext = viewModel;
    }

}
我应该为另一个视图创建新的viewmodel吗?(我想是的?)

我必须在我的执行命令中写入什么才能显示其他命令 窗户

在这种情况下,我通常会在ViewModel中引发一个事件。视图将处理程序附加到此事件,并且实际的
ShowDialog()
在此处理程序中执行

下面是一些伪代码,展示了这个想法:

// ViewModel
public class MainViewModel
{
    public event EventHandler<EventArgs<UpdateViewModel>> UpdateRequested;

    private void ExecuteUpdate()
    {
        if (this.UpdateRequested != null)
        {
            var childVm = new UpdateViewModel(/* parameters related to the object being updated */);
            this.UpdateRequested(this, new EventArgs<UpdateViewModel>(childVm));
        }
    }
}

// View
public class MainView
{
    public MainView()
    {
        var vm = new MainViewModel();
        this.DataContext = vm;

        vm.UpdateRequested += (sender, e) =>
        {
            var updateView = new UpdateView();
            updateView.DataContext = e.Data;    // Gets the instance of the viewModel here

            updateView.ShowDialog();
        };
    }
}
//视图模型
公共类主视图模型
{
公共事件事件处理程序UpdateRequested;
私有void ExecuteUpdate()
{
if(this.UpdateRequested!=null)
{
var childVm=new UpdateViewModel(/*与正在更新的对象相关的参数*/);
this.UpdateRequested(this,neweventargs(childVm));
}
}
}
//看法
公共类主视图
{
公共主视图()
{
var vm=新的MainViewModel();
this.DataContext=vm;
vm.UpdateRequested+=(发件人,e)=>
{
var updateView=new updateView();
updateView.DataContext=e.Data;//在此处获取viewModel的实例
updateView.ShowDialog();
};
}
}

实际上,为每个视图创建新的viewmodel并不是必需的。但是你应该在你的案例中创建一个新的。要从viewmodel打开新窗口,请使用中介模式,如MVVM Light的Messenger service

在ViewModel中:

Messenger.Default.Send(ViewName.PropertyWindow);
MainWindow.cs

Messenger.Default.Register<ViewName>(this, ShowPropertyWindow);

private void ShowPropertyWindow(ViewName view)
{
  if(view == ViewName.PropertyWindow)
  {
    var propertyWindow = new PropertyWindow();
    propertyWindow.DataContext = new PropertyWindowViewModel();
    propertyWindow.Show();
  }
}
Messenger.Default.Register(这是ShowPropertyWindow);
私有void ShowPropertyWindow(视图名称视图)
{
if(view==ViewName.PropertyWindow)
{
var propertyWindow=新的propertyWindow();
propertyWindow.DataContext=新的PropertyWindowViewModel();
propertyWindow.Show();
}
}

我目前有一个类似的要求,用户希望在另一个窗口中打开报告

我(在MVVM中)通过在窗口类的实际实例周围使用“wrapper”类完成了这项工作,重要的是,包装器构造函数被传递到窗口将要渲染的ViewModel的接口。包装器具有用于“Show”、“Close”等的方法,这些方法隐藏了实际的窗口实现类

包装类的实例由服务类创建和跟踪,该服务类了解所有打开的窗口,并且能够在应用程序关闭或用户选择从另一个ViewModel关闭窗口时关闭所有窗口

希望这有意义

视图类:

 public partial class TearOffWindow : MetroWindow
    {
        public TearOffWindow()
        {
            InitializeComponent();
            SourceInitialized += (s, a) => this.HideMinimizeButtons();
        }
    }
包装器实现:

public sealed class TearOffWindowWrapper : IWindowWrapper<TearOffWindow>
    {
        private readonly TearOffWindow _window;

        public TearOffWindowWrapper(ITearOffViewModel viewModel)
        {
            _window = new TearOffWindow { DataContext = viewModel };
        }

        public event EventHandler Closed;

        public bool IsVisible
        {
            get
            {
                return _window.Visibility == Visibility.Visible;
            }

            set
            {
                _window.Visibility = value ? Visibility.Visible : Visibility.Hidden;
            }
        }

        public void Close()
        {
            _window.Close();
        }

        public void Show()
        {
            if (!_window.IsVisible)
            {
                _window.Closed += WindowOnClosed;

                _window.Show();
                _window.Activate();
            }
        }

        public void Activate()
        {
            if (_window.IsVisible)
            {
                _window.Activate();
            }
        }

        private void WindowOnClosed(object sender, EventArgs eventArgs)
        {
            _window.Closed -= WindowOnClosed;

            var closed = Closed;
            if (closed != null)
            {
                closed(this, EventArgs.Empty);
            }
        }
    }
我是否应该为另一个视图创建新的viewmodel?(我想是的?) 这取决于您的Viewmodel以及您试图使用它执行的操作

假设您显示了一个
列表
,用户可以在其中选择一个人并编辑此人。当然,您需要此模型的虚拟机,但如果它是一个
列表
,则无需创建新的
PersonVM
进行编辑,因为您的虚拟机应该能够处理这些事情

如何显示另一个窗口? 这只是一个简单的例子,肯定有点违反了丢失耦合的规则,因为它知道有视图,但不知道PersonV,因为PersonV是一个用户控件

   public void ExcecuteSearchwindowcommand()
   {
       var vm = //if you need to select a VM or create a new VM

       var v = new view(vm) // view is a modified Window

       v.ShowDialog()

      if(vm.Result)// Result will be an property which tells you
      {            // how the user closed the Window e.g. Save,Cancel, ...
      }
      //else or whatever

   }
view.cs

    // this are my constructors

    // obj is your vm
    public DetailV(object obj)
    {
        InitializeComponent();

        DataContext = obj;
        CPresenter.Content = obj;

        initializeCostumComponent();
    }

    // dataContext is your vm and 
    // content is an Usercontrol
    public DetailV(object dataContext, object content)
    {
        InitializeComponent();

        DataContext = dataContext;
        CPresenter.Content = content;

        initializeCostumComponent();
    }
view.xaml

<Window x:Class="view"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        SizeToContent="WidthAndHeight"
        WindowStartupLocation="CenterScreen"
        Top="150"
        DataContext="{Binding ElementName=CPresenter,Path=Content}"
        Title="{Binding DisplayTitle}" Loaded="Window_Loaded" TabIndex="99999999">
    <ScrollViewer Name="viewer"
                  VerticalScrollBarVisibility="Auto"
                  HorizontalScrollBarVisibility="Auto">
        <ScrollContentPresenter Name="CPresenter" />
    </ScrollViewer>
</Window>

现在,我使用ResourceDictionary来说明特定vm的默认视图

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

                     xmlns:vm="clr-namespace:NamespaceViewModel"
                     xmlns:vw="clr-namespace:NamespaceView">
    <DataTemplate DataType="{x:Type vm:PersonVM}">
        <vw:PersonV  />
    </DataTemplate>
</ResourceDictionary>


如果您现在有一个AdressVM,只需将它添加到您的ResourceDictionary中,它就可以工作了

我同意这个事件,但我认为新的ViewModel不是强制性的。这取决于新窗口的用途。嗨!问题是,我无法引用startapplikation,因为startapplikation已经引用了我的viewmodel(用于上下文?!)现在我不知道如何创建另一个窗口类别的实例来使用ShowDialog()编辑:目的只是在appconfig中设置一些内容,没什么特别的。@Xaruth事实上这不是强制性的。但是如果视图需要绑定,我个人总是为每个视图创建一个viewModel。这只是个人偏好,因此阅读代码的人更清楚地将视图与其关联viewModel@user3793935MVVM的主要规则是:视图引用viewModels,但viewModels不引用视图。我不知道你的StartAppLike(可能在问题中提供更多代码),但无论如何viewModel不能引用视图。Uff,对不起,我有点困惑。我在问题中提供了startapplikation代码(只是数据绑定…我想我可以对另一个窗口做同样的操作,然后用我的EXECUTECOMAND调用它)Hui,这是很多只用于打开窗口的代码;(我会试试,希望能奏效:)
<Window x:Class="view"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        SizeToContent="WidthAndHeight"
        WindowStartupLocation="CenterScreen"
        Top="150"
        DataContext="{Binding ElementName=CPresenter,Path=Content}"
        Title="{Binding DisplayTitle}" Loaded="Window_Loaded" TabIndex="99999999">
    <ScrollViewer Name="viewer"
                  VerticalScrollBarVisibility="Auto"
                  HorizontalScrollBarVisibility="Auto">
        <ScrollContentPresenter Name="CPresenter" />
    </ScrollViewer>
</Window>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

                     xmlns:vm="clr-namespace:NamespaceViewModel"
                     xmlns:vw="clr-namespace:NamespaceView">
    <DataTemplate DataType="{x:Type vm:PersonVM}">
        <vw:PersonV  />
    </DataTemplate>
</ResourceDictionary>