2

我已经搜索并尝试了几天,最后必须在这里提出问题。我有一个 Silverlight 5 应用程序,使用 MVVM Light,我希望能够在主视图中动态切换视图。

为了简单起见,假设我有 2 个按钮。

Button1 将切换到 TestView1。

Button2 将切换到 TestView2。

 <Button Content="TestView1" Grid.Column="1" Command="{Binding CallTestView1Command}" HorizontalAlignment="Left" Margin="185,17,0,0" VerticalAlignment="Top" Width="75"/>
    <Button Content="TestView2" Grid.Column="1" Command="{Binding CallTestView2Command}" HorizontalAlignment="Left" Margin="280,17,0,0" VerticalAlignment="Top" Width="75"/>

我这样做的方法是将relaycommand绑定到按钮,然后实例化相应视图的新视图模型。IE:

private RelayCommand _callTestView1Command;
    public RelayCommand CallTestView1Command
    {
        get
        {
            return _callTestView1Command ??
                   (_callTestView1Command = new RelayCommand(() =>
                       {
                           CurrentView = ViewModelLocator.NinjectKernel.Get<TestViewModel1>();
                       }));
        }
    }

然后将 CurrentViewmodel 设置为新的视图模型。在 MainView 中,我已将 CurrentView 绑定到 ContentControl:

<Border x:Name="displayedView" Grid.Row="2">
        <ContentControl Content="{Binding CurrentView}" />
    </Border>

这实际上会在某种程度上起作用,因为 CurrentView 会发生变化,但它不会实际显示视图的内容,它只是显示实例化的 ViewModel 的命名空间。

到目前为止,我主要使用了从这些来源获得的知识:

http://rachel53461.wordpress.com/2011/05/28/switching-between-viewsusercontrols-using-mvvm/

将视图加载到 ContentControl 并通过单击按钮更改其属性

但他们并没有解决我的问题,或者我不太明白如何实际显示视图。:-(

那么有人对如何使用 GalaSoft 的 MVVM Light 在 Silverlight 5 中正确切换视图有很好的解释。

谢谢

4

4 回答 4

2

您缺少的部分是DataTemplates告诉 WPF 如何呈现您的 ViewModel

<Window.Resources>
    <DataTemplate TargetType="{x:Type local:TestViewModel1}">
        <local:TestView1 />
    </DataTemplate>

    <DataTemplate TargetType="{x:Type local:TestViewModel2}">
        <local:TestView2 />
    </DataTemplate>
</Window.Resources>

当您在可视树中插入对象时,例如将ViewModel对象放入ContentControl.ContentTextBlock.ToString()namespace.classnameViewModelContentControl

DataTemplate通过在您的Resources某处定义一个隐式(即 aDataTemplate只有一个已TargetType定义的 - no ),您告诉 WPF 在尝试绘制该对象的任何时候x:Key使用指定的对象来绘制指定的对象,而不是使用绑定到对象的默认值。DataTemplateTextBlock.ToString()

应该注意的是,DataTemplates在 Silverlight 的早期版本中不支持隐式,但在 5.0+ 中支持它们。对于 Silverlight 的早期版本,我通常使用DataTemplateSelector代替。

于 2012-11-27T14:19:55.653 回答
1

所以我实际上解决了这个问题,不需要在MainView中创建数据模板,这是我不喜欢的。imo当我们谈论切换视图时, MainView应该对它正在显示的视图一无所知。

先决条件:对于此解决方案,您必须使用GalaSoft 的 MVVM Light

这是我的测试解决方案:我的MainView中添加了两个按钮,每个按钮都会打开一个新视图。clickevent 绑定到命令。

<Button Content="TestView1" Grid.Column="1" Command="{Binding CallTestView1Command}" HorizontalAlignment="Left" Margin="185,17,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="TestView2" Grid.Column="1" Command="{Binding CallTestView2Command}" HorizontalAlignment="Left" Margin="280,17,0,0" VerticalAlignment="Top" Width="75"/>

MainView我有一个边框,它应该包含可以切换的视图。由于所有视图都从UserControl继承,因此我将内容绑定到MainViewModel的属性CurrentView

    <Border x:Name="displayedView" Grid.Row="2">
        <UserControl Content="{Binding CurrentView}" />
    </Border>

MainViewModel我有属性 CurrentView。

 public const string CurrentViewPropertyName = "CurrentView";

    private UserControl _currentView;

    /// <summary>
    /// Sets and gets the "CurrentView property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public UserControl CurrentView
    {
        get
        {
            return _currentView;
        }

        set
        {
            if (_currentView == value)
            {
                return;
            }

            RaisePropertyChanging(CurrentViewPropertyName);
            _currentView = value;
            RaisePropertyChanged(CurrentViewPropertyName);
        }
    }

单击按钮时,会在MainViewModel中调用相应的命令:

        private RelayCommand _callTestView1Command;
    public RelayCommand CallTestView1Command
    {
        get
        {
            return _callTestView1Command ??
                   (_callTestView1Command = new RelayCommand(() =>
                       {
                           CurrentView = new TestView1();
                       }));
        }
    }

    private RelayCommand _callTestView2Command;
    public RelayCommand CallTestView2Command
    {
        get
        {
            return _callTestView2Command ??
                   (_callTestView2Command = new RelayCommand(() =>
                   {
                       CurrentView = new TestView2();
                   }));
        }
    }

正如所见,每个命令都会将CurrentView设置为新视图,并且视图将在MainView中切换,因为CurrentView将引发 ProperTyChanged 事件。

于 2012-10-16T07:14:51.047 回答
1

我首先建议您不要通过 ContentControl 显示您的视图,而是考虑使用 silverlight 工具包中的导航框架。此外,我们不希望我们的 ViewModel 创建 Views ......那不是很好。但是,如果我们的 ViewModel 执行业务逻辑并确定要显示哪个视图,我们不介意。在此处获取工具包:http: //silverlight.codeplex.com/

现在在您的主页中设置您的 XAML:

<Border x:Name="displayedView" Grid.Row="2"> 
        <navigation:Frame x:Name="ContentFrame" /> 
    </Border> 

由于您使用的是 MVVM Light,我们将使用消息传递。您的视图模型将获得更改视图的命令,确定要更改的视图,然后向主页发送消息以指示它更改视图。

在您的主页中为导航请求设置一个侦听器,如下所示:

public MainPage()
{
    InitializeComponent();  
    Messenger.Default.Register<Uri>(this, "NavigationRequest", (uri) => ContentFrame.Navigate(uri));
}

接下来,在您的视图模型中设置您的命令。

    private RelayCommand _callTestView1Command;         
public RelayCommand CallTestView1Command         
{         
    get         
    {         
        return _callTestView1Command ??         
               (_callTestView1Command = new RelayCommand(() =>         
                   {         
                        Messenger.Default.Send<Uri>(new Uri("/Views/.../Page.xaml", UriKind.Relative), "NavigationRequest");

                   }));         
    }         
}   

这些是对我有用的基础知识。您可以对此进行扩展并获得真正的“架构”。例如,您可以为发送导航请求的视图模型创建一个基类,创建一个生成 URI 的辅助类(因此它们不会在您的应用程序中的任何地方进行硬编码等等。祝您好运!

于 2012-10-15T12:19:14.837 回答
0

这实际上会在某种程度上起作用,因为 CurrentView 会发生变化,但它不会实际显示视图的内容,它只是显示实例化的 ViewModel 的命名空间。

因为您将CurrentView属性更改为视图模型实例并将其绑定为内容。这是错误的,因为内容应该是一个视图,您应该DataContext将该视图的设置为视图模型。

您可以在这里做的最简单的事情是在命令中创建一个 View 实例并将 viewmodel 设置为其 DataContext ,然后您可以将视图设置为CurrentView属性。当然,这会违反MVVM 模式,因此您应该将此责任转移到单独的组件中。我建议您不要编写自己的导航逻辑,而是选择现有的解决方案,因为这种任务并不像看起来那么简单。

我建议使用棱镜库

于 2012-10-15T11:14:06.393 回答