在Store App中使用MVVM进行页面导航

Mat*_*ias 12 c# wpf xaml mvvm windows-store-apps

我对这个问题感到非常头疼.我真的不喜欢商店应用程序,但在这种情况下我被迫使用它.我只和XAML合作了几个星期.

我的问题是:如何RelayCommand在我的ViewModel视图中调用我的(当然我的视图)?更好的是,使用URI更改它,以便我可以将命令参数传递给文件.

我完全迷失了.目前我this.Frame.Navigate(type type)在后面的View Code中使用浏览页面.

我真的和我的意思是真的很感谢从a到z的描述在这种情况下该做什么.

我认为我可以做一些事情,比如在我的View上构建一个framecontainer并将它发送到我的ViewModel,并从那里导航当前帧到另一个.但我不确定它在Store应用程序中是如何工作的.

我真的很抱歉缺少好的问题,但我正处于截止日期,我需要以适当的方式将我的View连接到我的ViewModel ..我不喜欢同时拥有Viewbehind和ViewModel代码.

SWi*_*lko 12

正如斯科特所说,你可以使用NavigationService.我首先创建一个接口,这个在本例中不需要,但如果你将来使用依赖注入(与viewmodels和服务的良好解决方案)将会很有用:)

INavigationService:

public interface INavigationService
{
    void Navigate(Type sourcePage);
    void Navigate(Type sourcePage, object parameter);
    void GoBack();
}
Run Code Online (Sandbox Code Playgroud)

NavigationService.cs将继承INavigationService,您将需要以下命名空间

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;


public sealed class NavigationService : INavigationService
{
    public void Navigate(Type sourcePage)
    {
        var frame = (Frame)Window.Current.Content;
        frame.Navigate(sourcePage);
    }

    public void Navigate(Type sourcePage, object parameter)
    {
        var frame = (Frame)Window.Current.Content;
        frame.Navigate(sourcePage, parameter);
    }

    public void GoBack()
    {
        var frame = (Frame)Window.Current.Content;
        frame.GoBack();
    }
}
Run Code Online (Sandbox Code Playgroud)

简单的ViewModel来显示RelayCommand示例.注意我使用DoSomething RelayCommand导航到另一个页面(Page2.xaml).

MyViewModel.cs

public class MyViewModel : INotifyPropertyChanged
{
    private INavigationService _navigationService;

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public MyViewModel(INavigationService navigationService)
    {
        _navigationService = navigationService;
    }

    private ICommand _doSomething;

    public ICommand DoSomething
    {
        get
        {
            return _doSomething ??
                new RelayCommand(() =>
                    {
                        _navigationService.Navigate(typeof(Page2));
                    });
        }
    }}
Run Code Online (Sandbox Code Playgroud)

在简单示例中,我在MainPage.cs中创建了viewmodel并添加了NavigationService,但您可以在其他地方执行此操作,具体取决于您的MVVM设置.

MainPage.cs

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();

        var vm = new MyViewModel(new NavigationService());
        this.DataContext = vm;
    }
}
Run Code Online (Sandbox Code Playgroud)

MainPage.xaml(绑定命令DoSomething)

 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button Width="200" Height="50" Content="Go to Page 2"
             Command="{Binding DoSomething}"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)

希望有所帮助.

  • VIewModels 不应该知道视图。 (2认同)

Lan*_*nce 11

有两种方法可以做到这一点,一种简单的方法是将视图中的中继命令操作传递给视图模型.

public MainPage()
{
  var vm = new MyViewModel();
  vm.GotoPage2Command = new RelayCommand(()=>{ Frame.Navigate(typeof(Page2)) });
  this.DataContext = vm;
}

<Button Command={Binding GoToPage2Command}>Go to Page 2</Button>
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用IocContainer和DependencyInjection.这是一种更加失败的耦合方法.

我们需要一个导航页面界面,这样我们就不需要引用或了解有关PageX或任何UI元素的任何内容,假设您的viewmodel位于一个不了解UI的单独项目中.

ViewModel项目:

  public interface INavigationPage
  {
    Type PageType { get; set; }
  }

  public interface INavigationService
  {
    void Navigate(INavigationPage page) { get; set; }
  }



public class MyViewModel : ViewModelBase
  {
    public MyViewModel(INavigationService navigationService, INavigationPage page)
    {
      GotoPage2Command = new RelayCommand(() => { navigationService.Navigate(page.PageType); })
    }

    private ICommand GotoPage2Command { get; private set; }
  }
Run Code Online (Sandbox Code Playgroud)

UI项目:

  public class NavigationService : INavigationService
    {
       //Assuming that you only navigate in the root frame
       Frame navigationFrame = Window.Current.Content as Frame;
       public void Navigate(INavigationPage page)
       {
          navigationFrame.Navigate(page.PageType);
       }
    }

public abstract class NavigationPage<T> : INavigationPage
{
   public NavigationPage()
   {
      this.PageType = typeof(T);
   }
}

public class NavigationPage1 : NavigationPage<Page1> { }


public class MainPage : Page
{
   public MainPage()
   {
      //I'll just place the container logic here, but you can place it in a bootstrapper or in app.xaml.cs if you want. 
      var container = new UnityContainer();
      container.RegisterType<INavigationPage, NavigationPage1>();
      container.RegisterType<INavigationService, NavigationService>();
      container.RegisterType<MyViewModel>();

      this.DataContext = container.Resolve<MyViewModel>();       
   }
}
Run Code Online (Sandbox Code Playgroud)