正确创建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?