正确创建MVVM WPF应用程序的方法

我想问你如何创建适当的MVVM应用程序WPF。 昨天我试图了解PRISM和MVVM模型。 这很好,但我想知道,我如何在大型应用程序中使用MVVM。 我有一个MainWindow,然后是3种类型的TabControls(单独的UserControls - 对于每个用户组不同的 - Admin,EE,SPOC - 带有后面的代码和命令/方法)。 我应该为每个TabControl类库创建吗? 我应该把什么放入ViewModel和View? 如何从MainWindow OnStartup调用LoginDialog - 如果我理解正确 - 不应将代码添加为MainWindow / View中的代码隐藏?


LOB应用程序? 这也是我的领域。 我会推荐galasofts MVVM Light。

令人遗憾的是,在MVVM方面有很多异端,甚至提供了我的微软。

在过去的4.5年里,我一直在使用WPF / SL。 有时候可以观看视频而不是使用Google搜索。 当我学到适当的MVVM时,我看了Jason Dolinger的视频。

过时了,但它仍然非常相关(oooold),但如果我记得他正在使用DO作为视图模型,这是不好的馅饼。

您的视图(.xaml.cs)应始终为空,以成为一名狂热分子;)

但是对于你的回答:

视图 - 应该只包含绑定和表示层。 没有代码隐藏!

ViewModel - 应该包含所有相关的代码,并且独立于你的视图。 这样你可以重用你的代码来看不同的视图或主题。

Datamodel / Entity (这里有很多混淆) - 仅包含您的数据和简单的接口,如INotifyPropertyChanged,IErrorInfo等。

是的,在大型应用程序中,您应该使用mvvm。

对于您的登录问题,我通常使用转换器( IValueConverter ),如果用户未授权他/她自己,则会显示登录屏幕,否则会显示常规内容。 通常使用BooleanToVisibilityConverter和InvertedBooleanToVisibilityConverter绑定到视图模型上的“IsLoggedIn”属性:)

希望它能帮助你朝正确的方向发展,我将在这里为你提供一个简单的例子

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));
    }
}

转换器:

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();
    }
}

我个人喜欢使用页面,并会在这种情况下使用它。 但这仅仅是一个例子

干杯,

了Stian


远离PRISM。 先学习基本的MVVM。 你不需要一个类库。

你的三个视图都应该有一个相应的viewModel。 所有的逻辑(命令等)都应该在虚拟机中。 该视图通常只是一个包含XAML的UserControl,并绑定到VM的各种属性。 它只是虚拟机上的一块“皮肤”。

后面的代码是很好的,只要它是特定的UI本身(例如驾驶动画等)。 一般来说,你的代码很少,因为任何显示逻辑都应该在虚拟机中(例如“如果这个按钮被按下,那么其他的更新”)

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

上一篇: Proper approach while creating MVVM WPF App

下一篇: How to programmatically create/populate view respecting MVVM?