Proper approach while creating MVVM WPF App

I would like to ask you how to create proper MVVM app WPF. Yesterday I was trying to understand PRISM and MVVM model. It's good but what I would like to know, how can I use MVVM in big application. I have one MainWindow, then 3 types of TabControls (separate UserControls - for each group of users different - Admin, EE, SPOC - with code behind and commands/methods). Should I create for each TabControl class library? What should I put into ViewModel and View? How can I call LoginDialog from MainWindow OnStartup - if I understand it correctly - code should not be added as code-behind in MainWindow/View?


LOB applications? It has been my field as well. I would recommend galasofts MVVM Light.

Sadly there is a lot of heresy out there regarding MVVM, even provided my Microsoft.

I've been working with WPF/SL for the last 4.5 years. Some times it can be OK to watch a video rather than googling around. When I learned proper MVVM I watched Jason Dolinger's video.

Outdated, but it's still pretty relevant(oooold), though if I recall correctly he is using DO's as viewmodels which is bad pie.

Your View (.xaml.cs) should always be empty, to be a fanatic ;)

But for your answer:

View - should only contain bindings, and the presentation layer. No codebehind!

ViewModel - should contain all relevant code, and be independent of your view. That way you may reuse your code for different views or themes.

Datamodel/Entity (there is so much confusion here) - Contains your data only and simple interfaces such as INotifyPropertyChanged, IErrorInfo etc..

And yes in big applications you should use mvvm.

for your login problem, I typically use a converter ( IValueConverter ) that displays a login screen if the user hasn't authorized him/her self, else the regular content is displayed. Typically bound to a "IsLoggedIn" property on the viewmodel with a BooleanToVisibilityConverter and an InvertedBooleanToVisibilityConverter :)

Hope it helps you some in the right direction, I'll provide a small crudely written example here for you.

XAML:

<Window x:Class="custtest.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:custtest="clr-namespace:custtest"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
            xmlns:command="http://www.galasoft.ch/mvvmlight"
            Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <custtest:ViewModelTest/>
    </Window.DataContext>
    <Window.Resources>
        <custtest:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
        <custtest:InvertedBooleanToVisibilityConverter x:Key="InvertedBooleanToVisibilityConverter"/>
    </Window.Resources>


    <Grid>
  <!-- Really simple login ui, should use passwordbox for pwd etc -->
        <Grid Visibility="{Binding Path=IsLoggedIn, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">

            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" MinWidth="100"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>

            <TextBlock Text="Login"></TextBlock>
            <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding UserName}"></TextBox>
            <TextBlock Grid.Row="1" Grid.Column="0" Text="Password"></TextBlock>
            <!-- Triggs command when user presses enter, should use pwdbox -->
            <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Password}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="KeyUp">
                        <command:EventToCommand Command="{Binding LoginCommand}" PassEventArgsToCommand="True"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </TextBox>

            <!-- Redundant button bad interaction design -->
            <Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" MaxWidth="200" MaxHeight="60"  Command="{Binding LoginClickCommand}" Content="Login"></Button>
        </Grid>


        <Grid Visibility="{Binding Path=IsLoggedIn, Converter={StaticResource BooleanToVisibilityConverter}}">
            <Button Content="This is your main content"></Button>
        </Grid>

    </Grid>
</Window>

VM:

public class ViewModelTest : INotifyPropertyChanged // Use a common baseclass
{
    private bool isLoggedIn;
    private string loginErrorText;
    private string password;
    private string userName;

    public ViewModelTest()
    {
        Initialize(); // Bleh
    }

    public bool IsLoggedIn
    {
        get { return isLoggedIn; }
        set
        {
            if (value.Equals(isLoggedIn)) return;
            isLoggedIn = value;
            OnPropertyChanged();
        }
    }
    public String LoginErrorText
    {
        get { return loginErrorText; }
        set
        {
            if (value == loginErrorText) return;
            loginErrorText = value;
            OnPropertyChanged();
        }
    }
    public String UserName
    {
        get { return userName; }
        set
        {
            if (value == userName) return;
            userName = value;
            OnPropertyChanged();
        }
    }
    public String Password
    {
        get { return password; }
        set
        {
            if (value == password) return;
            password = value;
            OnPropertyChanged();
        }
    }

    public ICommand LoginCommand { get; set; }
    public ICommand LoginClickCommand { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;

    protected void Initialize()
    {
        LoginCommand = new RelayCommand<KeyEventArgs>(IdentifyUser);
        LoginClickCommand = new RelayCommand(IdentifyUserClick);
    }

    private void IdentifyUserClick()
    {
        CheckUserCredentials();
    }

    private void CheckUserCredentials()
    {
        // Check your credentials here and change IsLoggedIn accordingly            
    }

    private void IdentifyUser(KeyEventArgs obj)
    {
        if (obj.Key == Key.Enter)
            CheckUserCredentials();
    }


    [NotifyPropertyChangedInvocator] // comment out if you dont have resharper
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Converters:

public class BooleanToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool && ((bool)value))
            return Visibility.Visible;
        else
            return Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}


public class InvertedBooleanToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool && ((bool)value))
            return Visibility.Collapsed;
        else
            return Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Personally I love using pages, and would use it in a situation like this. But it's just an example

Cheers,

Stian


Stay away from PRISM. Learn basic MVVM first. You do not need a class library.

Each of your three views should have a corresponding viewModel. All the logic (commands etc) should be in the VM. The view will generally just be a UserControl that contains XAML with bindings to various properties of the VM. It is just a thin "skin" over your VM.

Code behind is fine as long as it is specific the UI itself (eg driving animations etc). Generally you will have very little code behind since any display logic should be in the VM (eg "if this button is pressed then something else updates")

链接地址: http://www.djcxy.com/p/56178.html

上一篇: WPF数据绑定,MVVM和路由事件

下一篇: 正确创建MVVM WPF应用程序的方法