tas*_*dew 5 c# wpf mvvm material-design-in-xaml
我正在尝试学习MVVM,并且遇到了奇怪的问题。我有一个带有抽屉控件的主菜单,出来并显示一个菜单:

在此抽屉所在的主窗口中,有一个ContentControl我用Binding设置其内容的位置。
<ContentControl x:Name="MainWindowContentControl" Content="{Binding Path=WindowContent}"/>
Run Code Online (Sandbox Code Playgroud)
该窗口的绑定设置为视图模型。
<Window.DataContext>
<viewmodels:MainWindowViewModel/>
</Window.DataContext>
Run Code Online (Sandbox Code Playgroud)
这是ViewModel:
MainWindowViewModel.cs
public class MainWindowViewModel: ViewModelBase
{
private object _content;
public object WindowContent
{
get { return _content; }
set
{
_content = value;
RaisePropertyChanged(nameof(WindowContent));
}
}
public ICommand SetWindowContent { get; set; }
public MainWindowViewModel()
{
SetWindowContent = new ChangeWindowContentCommand(this);
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切正常。因此,例如,如果单击“恢复操作”,则会得到以下信息:
在“ RecoveryOperationsView.xaml ”(这是一个UserControl)中,我也像这样从上方引用视图模型。
<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>
Run Code Online (Sandbox Code Playgroud)
并具有一个按钮来调用命令,以ContentControl从主窗口中更改的Content属性。
<Button Grid.Row="2" Content="Restore Database" Width="150" Style="{StaticResource MaterialDesignFlatButton}" Command="{Binding SetWindowContent}" CommandParameter="DatabaseRecovery" >
Run Code Online (Sandbox Code Playgroud)
在处理命令的类中,我使用switch语句根据传递的参数更改内容,如下所示:
ChangeWindowContentCommand.cs
public class ChangeWindowContentCommand : ICommand
{
private MainWindowViewModel viewModel;
public ChangeWindowContentCommand(MainWindowViewModel vm)
{
this.viewModel = vm;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
switch (parameter)
{
case "Home":
viewModel.WindowContent = new HomeView();
break;
case "RecoveryOps":
viewModel.WindowContent = new RecoveryOperationsView();
break;
case "DatabaseRecovery":
viewModel.WindowContent = new DatabaseRestoreView();
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这是我迷路的地方...如果我在此新窗口中单击某些内容,说“还原数据库”并使用断点进行检查,则可以看到该属性已更改,但实际的ContentControlContent属性并未更改为新的UserControlI制作...我可以在抽屉中的任何内容上更改内容,但是如果我尝试单击托管内容中的按钮,则ContentControl什么都不会更改。我想念什么?
如果没有您的项目进行测试,很难 100% 确定,但我相当有信心,至少问题之一是您UserControl和您MainWindow使用不同的MainWindowViewModel. 您不需要为用户控件实例化 VM,因为它将继承DataContext自MainWindow. 它在 WPF 中的工作方式是,如果任何给定UIElement没有显式分配DataContext,它将从逻辑树上第一个已分配的元素继承它。
所以,只要删除这段代码,它至少应该解决这个问题。
<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>
Run Code Online (Sandbox Code Playgroud)
由于您正在学习 WPF,我觉得有义务提供一些其他提示。即使您使用的是 ViewModel,您仍然可以通过创建非常具体的实现ICommand并通过 ViewModel 分配 UI 元素来混合 UI 和逻辑。这打破了 MVVM 模式。我知道 MVVM 需要一点时间来理解,但是一旦你理解了,它就非常容易使用和维护。
为了解决您的问题,我建议为每个用户控件创建视图模型。请参阅这个答案,我在其中详细介绍了实现。
要切换不同的视图,您有几个选项。您可以使用 a TabControl,或者如果您想使用命令,则可以对类型ContentControl为 的属性进行单个绑定。我们就这样称呼它吧。然后,当命令触发时,您将所需用户控件的视图模型分配给该绑定属性。您还需要利用隐式数据模板。基本思想是为每个用户控制 VM 类型创建一个模板,该模板仅包含视图的实例。当您将用户控件 VM 分配给该属性时,绑定将找到这些数据模板并呈现用户控件。例如:MainWindowViewModelViewModelBaseCurrentViewModelCurrentViewModel
<Window.Resources>
<DataTemplate DataType = "{x:Type viewmodels:RecoveryOperationsViewModel}">
<views:RecoveryOperationsView/>
</DataTemplate>
<!-- Now add a template for each of the views-->
</Window.Resources>
<ContentControl x:Name="MainWindowContentControl" Content="{Binding CurrentViewModel}"/>
Run Code Online (Sandbox Code Playgroud)
看看这种方法如何让 UI 和逻辑保持一定距离?
最后,考虑创建一个非常通用的实现以ICommand在所有 ViewModel 中使用,而不是许多特定的实现。我认为大多数 WPF 程序员或多或少都有这种精确的RelayCommand 实现。
| 归档时间: |
|
| 查看次数: |
184 次 |
| 最近记录: |