【发布时间】:2020-07-27 17:49:39
【问题描述】:
互联网上有大量关于这个主题的文章,但我就是无法理解它。大多数文章都使用后面的代码,但我想坚持使用“纯”MVVM,因为我尝试学习它。另外,我明确不想使用任何其他框架(MVVMlight、Ninject ...)。我只想坚持 WPF 提供的功能。我知道这被问了很多,但我发现要么不是 mvvm,要么不够具体。
我的任务很简单:我想看看最简单的打开模式对话框的解决方案,向它发送一个字符串,然后在关闭它时从对话框中获取一个字符串。
因此,我在 MainWindow.xaml 中设置了一个文本输入字段 (TextBox)、一个按钮(应该打开模式对话框)和一个显示我打算从对话框接收的消息的文本块。
对话框有一个 TextBlock,显示来自 MainWindow.xaml 的用户输入,以及一个用于输入一些文本的 TextBox,以及一个按钮。您猜对了:您按下按钮,我在文本字段中键入的消息将返回到 MainWindow.xaml。另请参阅我包含的图片 - 我认为这很不言自明。
MainWindow.xaml
<Window x:Class="Dialogs.MainWindow"
...
Title="First View (Main Window)" Height="240" Width="630">
<Grid>
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="Main View sayz: "/>
<TextBox Width="360" Margin="10,0,0,30"/>
</StackPanel>
<Button Content="Send to Second View" Command="{Binding SendToSecondViewCommand}" Width="200"/>
<StackPanel Orientation="Horizontal" Margin="10,30,10,10">
<TextBlock Text="Second View replies: "/>
<TextBlock Width="360"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
SecondView.xaml
<UserControl x:Class="Dialogs.SecondView"
...
d:DesignHeight="240" d:DesignWidth="630" Background="BlanchedAlmond">
<Grid>
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="This is what First View sayz: "/>
<TextBlock Width="360"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="Second View replies: "/>
<TextBox Width="360" Margin="10,0,0,30"/>
</StackPanel>
<Button Content="Reply to First View" Command="{Binding ReplyToFirstViewCommand}" Width="200"/>
</StackPanel>
</Grid>
</UserControl>
这是我实现 INotifyPropertyChanged 的方式(它实际上是一个名为 BaseClasses 的 .cs 文件;我知道它没有正确命名...)
public abstract class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged<T>(ref T variable, T value,
[CallerMemberName] string propertyName = null)
{
variable = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
这里是中继命令的基类:
public class CommandDelegateBase : ICommand
{
public delegate void ExecuteDelegate(object parameter);
public delegate bool CanExecuteDelegate(object paramerter);
private ExecuteDelegate execute;
private CanExecuteDelegate canExecute;
public CommandDelegateBase(ExecuteDelegate _execute, CanExecuteDelegate _canExecute = null)
{
execute = _execute;
canExecute = _canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return canExecute?.Invoke(parameter) ?? true;
}
public void Execute(object parameter)
{
execute.Invoke(parameter);
}
}
最后是我的 ViewModel: 第一视图模型:
public class FirstViewViewModel: NotifyPropertyChangedBase
{
private string _sendText;
public string SendText
{
get { return _sendText; }
set
{
_sendText = value;
OnPropertyChanged(ref _sendText, value);
}
}
public ICommand SendToSecondViewCommand { get; set; }
public FirstViewViewModel()
{
SendToSecondViewCommand = new CommandDelegateBase(SendExecuteCommand, SendCanExecuteCommand);
}
private bool SendCanExecuteCommand(object paramerter)
{
return true;
}
private void SendExecuteCommand(object parameter)
{
//Do stuff to :
// a) show the second view as modal dialog
// b) submit what I just wrote (SendText)
}
}
第二视图模型:
public class SecondViewViewModel : NotifyPropertyChangedBase
{
private string _replyText;
public string ReplyText
{
get { return _replyText; }
set
{
_replyText = value;
OnPropertyChanged(ref _replyText, value);
}
}
public ICommand ReplyToFirstViewCommand { get; set; }
public SecondViewViewModel()
{
ReplyToFirstViewCommand = new CommandDelegateBase(ReplyExecuteCommand, ReplyCanExecuteCommand);
}
private bool ReplyCanExecuteCommand(object paramerter)
{
return true;
}
private void ReplyExecuteCommand(object parameter)
{
//Do stuff to :
// a) close the second view
// b) reply what I just wrote (ReplyText) back to First View.
}
}
我的解决方案中有一个名为“Models”的文件夹,但为了简单起见,它是空的。
我知道有一些带有帮助类或服务的解决方案——任何与 mvvm 相关的东西都可以。我也知道,像我想要的那样简单的任务这样做是安静的“矫枉过正”,并且附带的编写代码比为此目的合理的要多得多。但再说一遍:我想了解这一点,并了解我在做什么。
非常感谢您!
【问题讨论】:
-
你可以看看我的CleanArchitecture project 我刚刚添加了对话框功能
-
感谢您的链接 - 菜鸟问题:有什么文件夹我应该特别注意吗?像“Desktop.WpfApp”还是 Desktop.Application?按照我的理解,这些文件夹代表了在 Visual Studio 中打开的完整 wpf 解决方案?
-
它是一个单独的 WPF 应用程序,具有独立的项目层(应用程序、基础结构、演示和 WPF 平台)。
-
DialogService 的定义:github.com/SirRufo/CleanArchitecture/tree/master/Desktop/…