本文介绍了WPF导航使用通过量MVVM模式的看法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用MVVM模式构建我的第一个WPF。有了这个comunity的帮助下,我设法创建我的模型,我的第一个视图模型和视图。现在我想一些复杂性添加到应用程序设计的基本应用布局界面。我的想法是至少有2个孩子的意见,一个主要的观点和他们几个XAML分开:

I'm building my first WPF using MVVM pattern. With the help of this comunity, I manage to create my Model, my first ViewModel and view. Now i want to add some complexity to the app designing the basic application layout interface. My idea is to have at least 2 child views and one main view and separate them on several XAML:


  • Main.XAML

  • Products.XAML

  • Clients.XAML

主要将有一个菜单和空间来加载子视图(产品和客户端)。现在下面MVVM模式视图之间的所有导航逻辑应该是一个ViewModel写。所以MI想法是有4的ViewModels:

Main will have a menu and a space to load child views (Products and Clients). Now following MVVM pattern all the navigation logic between views should be write on a ViewModel. So mi idea is to have 4 ViewModels:


  • MainViewModel

  • ProductsViewModel

  • ClientsViewModel

  • NavigationViewModel

所以NavigationViewModel应该包含孩子的ViewModels的集合? ?和活跃的视图模型是分辩

So NavigationViewModel should contain a collection of child viewmodels? and an active viewmodel is that rigth?

所以我的问题是:

1)我怎样才能加载diferent意见(产品,客户端)上的主视图使用MVVM模式?

1) How can I load diferent views (Products, Clients) on Main view using MVVM pattern?

2)如何实现导航视图模型

2) How do I implement navigation viewModel

3)我如何控制打开或活动视图的最大数量?

3) How can I control the max number of open or active views?

4)如何才能打开视图之间切换?

4) How can I switch between open views?

我已经做了很多搜索和阅读,但没有找到与WPF加载主视图内多个视图MVVM导航的任何简单的工作示例。许多然后:

I have been doing a lot of search and reading and couldn't find any simple working example of MVVM navigation with WPF that loads multiple views inside a main view. Many of then:

1)使用外部工具,至极我不想现在就用

1) Use external toolkit, wich i don't want to use right now.

2)把所有的代码在一个XAML文件创建所有的意见,至极好好尝试一下似乎是一个好主意,因为我需要近80的观点来实现!

2) Put all the code for creating all the views in a single XAML file, wich doens't seems like a good idea because I need to implement near 80 views!

我在这里的分辩路径?任何帮助,特别是具有一些代码将apreciated。谢谢!

I'm in the rigth path here? Any help, especialy with some code will be apreciated. Thank You!

更新

所以,我建立以下测试项目@ LordTakkera意见,但会被卡住。这是我的解决方案看起来的样子:

So, i build a test project following @LordTakkera advices, but get stuck. This is how my solution looks like:

创建:


  • 两种模式(客户和产品)

一个主窗口和两个WPF用户控件(客户端和产品)XAML。

One MainWindow and two wpf user controls(Clients and Products) XAML.

三的ViewModels(客户端,产品及主要视图模型)

Three ViewModels (Clients, Products and Main ViewModel)

然后我对每个视图设置的DataContext对应视图模型。从那以后,我创建主窗口的ContentPresenter这样并将其绑定到视图模型的属性。

Then i set dataContext on each view to corresponding viewModel. After that I create MainWindow with the ContentPresenter like this and bind it to a property of the viewmodel.

MainWindow.XAML

<Window x:Class="PruevaMVVMNavNew.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="519" Width="890">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="80"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="20"/>
    </Grid.RowDefinitions>
    <Border Grid.Column="0" Grid.ColumnSpan="2" Background="AntiqueWhite" ></Border>
    <Border Grid.Row="1" Grid.RowSpan="2" Background="AliceBlue"></Border>
    <Border Grid.Row="1" Grid.Column="1" Background="CadetBlue"></Border>
    <ContentPresenter Grid.Row="1" Grid.Column="1" x:Name="ContentArea" Content="{Binding CurrentView}"/>
    <StackPanel Margin="5" Grid.Column="0" Grid.Row="1">
        <Button>Clients</Button>
        <Button>Products</Button>
    </StackPanel>
</Grid>



和也这是视图模型从主窗口:

And also this is viewmodel from MainWindow:

class Main_ViewModel : BaseViewModel
    {
        public Main_ViewModel()
        {
            CurrentView = new Clients();
        }

        private UserControl _currentView;
        public UserControl CurrentView
        {
            get
            {
                return _currentView;
            }
            set
            {
                if (value != _currentView)
                {
                    _currentView = value;
                    OnPropertyChanged("CurrentView");
                }
            }
        }

    }

所以这个负载默认客户端浏览和看起来像这样(这是恰到好处!):

So this load by default clients view and looks like this (which is just right!):

所以我想我需要一种方法来关联左边的按钮,具有一定viemodel和然后用主视图模型的CurrentView属性绑定它们。我怎样才能做到这一点?
谢谢!

So i suppose i need a way to relate the buttons on the left, with a certain viemodel and then bind them with CurrentView Property of Main viewModel. How can i do that?Thank You!

UPDATE2

据@LordTakkera意见我修改我的主视图模型是这样的:

According to @LordTakkera advice I modify my main viewModel this way:

class Main_ViewModel : BaseViewModel
    {
        public ICommand SwitchViewsCommand { get; private set; }

        public Main_ViewModel()
        {
            //CurrentView = new Clients();
            SwitchViewsCommand = new RelayCommand((parameter) => CurrentView = (UserControl)Activator.CreateInstance(parameter as Type));
        }

        private UserControl _currentView;
        public UserControl CurrentView
        {
            get
            {
                return _currentView;
            }
            set
            {
                if (value != _currentView)
                {
                    _currentView = value;
                    OnPropertyChanged("CurrentView");
                }
            }
        }
    }



我使用RelayCommand代替DelegateCommand但我认为它的工作方式相同。当我打的按钮和类型参数字符串其确定该命令执行,但我得到这个错误:

I use RelayCommand instead of DelegateCommand but I think it works the same way. The command is executed when I hit the buttons and the type parameter string its ok but i get this error:

翻译:值不能为空。参数名:类型。建议使用新关键字来创建对象实例
我不知道往哪里放新的关键字。我曾尝试CommandParameter,但它不会工作。任何想法?谢谢

Translation: Value cannot be null. Parameter name: type. Suggestion use New keyword to create object instanceI don't know where to put the New keyword. I have try on CommandParameter but it wont work. Any idea? Thanks

更新3

在所有的建议和帮助在这里recived和大量的工作,这是我最后的导航菜单和我的应用程序界面的基础。

After all the advices and help recived here, and a lot of work, here is my final navigation menu and the base for my application interface.


感谢所有的帮助。

推荐答案

我不知道你需要一个单独的导航视图模型,你可以很容易地把它变成主要的。无论哪种方式:

I'm not sure you need a separate "navigation" view model, you could easily put it into the main. Either way:

要分开你的孩子的意见,我会用一个简单的ContentPresenter你的主视图:

To separate your "child" views, I would use a simple ContentPresenter on your "main" view:

<ContentPresenter Content="{Binding CurrentView}"/>



实施后盾属性的最简单的方法是让一个用户控件,虽然有人会说,这样做违反了MVVM(因为视图模型现在依赖于一个查看级)。你可以做一个对象,但你失去了一些类型安全。每个视图会在这种情况下用户控件。

The easiest way to implement the backing property is to make it a UserControl, though some would argue that doing so violates MVVM (since the ViewModel is now dependent on a "View" class). You could make it an object, but you lose some type safety. Each view would be a UserControl in this case.

要在它们之间进行切换,您将需要某种形式的选择控制。我以前用单选按钮做到了这一点,你束缚他们,像这样:

To switch between them, you are going to need some sort of selection control. I've done this with radio buttons before, you bind them like so:

<RadioButton Content="View 1" IsChecked="{Binding Path=CurrentView, Converter={StaticResource InstanceEqualsConverter}, ConverterParameter={x:Type views:View1}"/>



该转换器很简单,在转换只是检查是否电流控制是一类参数,在ConvertBack则返回参数的新实例。

The converter is pretty simple, in "Convert" it just checks if the current control is a type of the parameter, in "ConvertBack" it returns a new instance of the parameter.

public class InstanceEqualsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (parameter as Type).IsInstanceOfType(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (bool)value ? Activator.CreateInstance(parameter as Type) : Binding.DoNothing;
    }
}



绑定到一个组合框或其它选择控制会遵循类似的模式。

Binding to a combobox or other selection control would follow a similar pattern.

当然,你也可以使用的DataTemplates(有一个选择,可惜不是我以前做过的),并将它们加载到利用合并后的字典你的资源(允许独立的XAML)。我个人比较喜欢的用户控制路线,挑选其中最适合你!

Of course you could also use DataTemplates (with a selector, unfortunately not something I have done before) and load them into your resources using merged dictionaries (allowing separate XAML). I personally prefer the user control route, pick which is best for you!

这做法是一次一个视图。这将是比较容易转换为多个视图(您的用户控件成为用户控件的集合,在转换器等使用。载)。

This approach is "one view at a time". It would be relatively easy to convert to multiple views (your UserControl becomes a collection of user controls, use .Contains in the converter etc.).

要使用按钮做到这一点,我会用命令,并采取CommandParameter的优势

To do this with buttons, I would use commands and take advantage of the CommandParameter.

按钮XAML会是什么样子:

The button XAML would look like:

<Button ... Command={Binding SwitchViewsCommand} CommandParameter={x:Type local:ClientsView}/>



然后你有一个委托指令(教程的)运行从转换器的激活代码:

Then you have a delegate command (tutorial here) that runs the activator code from the converter:

public ICommand SwitchViewsCommand {get; private set;}

public MainViewModel()
{
    SwitchViewsCommand = new DelegateCommand((parameter) => CurrentView = Activator.CreateInstance(parameter as Type));
}

这是我的头顶部,但应该是八九不离十。让我知道如何去!

That is off the top of my head, but should be pretty close. Let me know how it goes!

让我知道,如果我提供任何进一步的信息!

Let me know if I provide any further information!

更新:

要回答您的问题:


  1. 是,每次你推创建视图的新实例按钮。类型,用户控件>你可以很容易地通过举办词典<解决这个问题有预先创建的视图和索引到它。对于这个问题,你可以使用 Dictonary<弦乐,用户控件> 和使用简单的字符串作为变频器的参数。缺点是你的视图模型变得紧密地耦合到各种意见可以存在(因为它有填充说词典)。

  1. Yes, each time you push the button a new instance of the view is created. You could easily fix this by holding a Dictionary<Type, UserControl> that has pre-created views and index into it. For that matter, you could use a Dictonary<String, UserControl> and use simple strings as the converter parameters. The disadvantage is that your ViewModel becomes tightly coupled to the kinds of views it can present (since it has to populate said Dictionary).

类应该得到处置,只要没有其他人持有对它的引用(认为事件处理程序,它注册的)。

The class should get disposed, as long as no one else holds a reference to it (think event handlers that it registered for).

正如你指出的,只有一个观点是在同一时间创建,因此你不需要担心内存。你,当然,调用构造函数,但是这是不贵,尤其是在我们往往有大量的CPU空闲时间现代计算机。与往常一样,答案的性能问题就是基准它,因为只有你有机会获得预期的部署目标和整个源,看看有什么实际执行最好的。

As you point out, only one view is created at a time so you shouldn't need to worry about memory. You are, of course, calling a constructor but that isn't THAT expensive, particularly on modern computers where we tend to have plenty of CPU time to spare. As always, the answer to performance questions is "Benchmark it" because only you have access to the intended deployment targets and entire source to see what actually performs the best.

这篇关于WPF导航使用通过量MVVM模式的看法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 08:25