我知道有很多关于我的问题的文章,但我找不到解决方案。 我是WPF的新手 - MVVM,我尝试理解MVVM-Logic。 所以我做了一个小项目来理解这一点。 对于我以后的应用程序,我想动态地将UserControl加载到我的窗口。
在我的StartView中,我有一个绑定到StartViewModel。 (绑定在APP.xaml中)
StartView app = new StartView();
StartViewModel context = new StartViewModel();
StartView
<Window x:Class="test.Views.StartView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:test.ViewModel"
Title="Window1" Height="300" Width="516">
<Grid>
<Menu IsMainMenu="True" Margin="0,0,404,239">
<MenuItem Header="_Einstellungen">
<MenuItem Header="Server" />
</MenuItem>
</Menu>
<ContentControl Content="{Binding LoadedControl}" Margin="0,28,0,128" />
</Grid>
</Window>
StartViewModel
namespace test.ViewModel
{
public class StartViewModel : ViewModelBase
{
#region Fields
private UCStastistikViewModel _loadedControl;
#endregion
public StartViewModel()
{
LoadedControl = new UCStastistikViewModel();
}
#region Properties / Commands
public UCStastistikViewModel LoadedControl
{
get { return _loadedControl; }
set
{
if (value == _loadedControl)
return;
_loadedControl = value;
OnPropertyChanged("LoadedControl");
}
}
#endregion
#region Methods
#endregion
}
}
UCStatistikView
<UserControl x:Class="test.Views.UCStatistik"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:test.ViewModel"
mc:Ignorable="d"
d:DesignHeight="188" d:DesignWidth="508">
<UserControl.DataContext>
<vm:UCStastistikViewModel />
</UserControl.DataContext>
<Grid Background="red">
</Grid>
</UserControl>
UCStatistikViewModel
namespace test.ViewModel
{
public class UCStastistikViewModel : ViewModelBase
{
#region Fields
#endregion
public UCStastistikViewModel()
{
}
#region Properties / Commands
#endregion
#region Methods
#endregion
}
}
现在我想在我的StartView的ContentControl中加载我的UCStatistikView。 但是在Startview中只显示Path test.UCStatistikViewModel而不是整个UC 任何人都可以给我一些想法,我的问题在哪里/哪里出错?
再见
答案 0 :(得分:18)
您的ViewModel不应该关心UserControls。相反,让他们持有ViewModels,让WPF解决如何使用DataTemplate绘制ViewModel。
例如,
<Window x:Class="test.Views.StartView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:test.Views"
xmlns:viewmodels="clr-namespace:test.ViewModel"
Title="Window1" Height="300" Width="516">
<Window.Resources>
<DataTemplate DataType="{x:Type viewmodels:UCStastistikViewModel}">
<views:UCStastistikView />
</DataTemplate>
</Window.Resources>
<Grid>
<Menu IsMainMenu="True" Margin="0,0,404,239">
<MenuItem Header="_Einstellungen">
<MenuItem Header="Server" />
</MenuItem>
</Menu>
<ContentControl Content="{Binding LoadedControl}" Margin="0,28,0,128" />
</Grid>
</Window>
另外,摆脱UserControl中的<UserControl.DataContext>
。 DataContext
应该通过使用控件的任何内容传入,而不是在UserControl中定义:)
修改
根据您对之前关于通过切换ViewModel来切换StartPage内容的回答的评论,您可能有兴趣查看this post of mine。它的标题为Navigation with MVVM
,但同样的概念适用于切换视图或用户控件
基本上,您要创建LoadedControl
类型的属性ViewModelBase
,而不是对其类型进行硬编码,然后将其设置为您希望在ContentControl中显示的任何对象。 WPF的DataTemplates将负责连接ViewModel的正确视图。
答案 1 :(得分:2)
WPF不支持自动解析给定视图模型的视图。您问题的天真解决方案是直接将UCStatistikView添加到您的StartView并将VM绑定到它
<Window x:Class="test.Views.StartView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:test.ViewModel"
Title="Window1" Height="300" Width="516">
<Grid>
<Menu IsMainMenu="True" Margin="0,0,404,239">
<MenuItem Header="_Einstellungen">
<MenuItem Header="Server" />
</MenuItem>
</Menu>
<UCStatistikView DataContext="{Binding LoadedControl}" Margin="0,28,0,128" />
</Grid>
更详细的方法是实现ViewLocator(视图模型第一种方法)或ViewModelLocator(视图第一种方法)。定位器自动定位视图并将其绑定到视图模型。有一些MVVM框架/工具包可以实现这样的定位器。
使用Caliburn.Micro,你开始查看将会是这样的
<Window x:Class="test.Views.StartView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:test.ViewModel"
Title="Window1" Height="300" Width="516">
<Grid>
<Menu IsMainMenu="True" Margin="0,0,404,239">
<MenuItem Header="_Einstellungen">
<MenuItem Header="Server" />
</MenuItem>
</Menu>
<ContentControl cm:View.Model="{Binding LoadedControl}" Margin="0,28,0,128" />
</Grid>
cm:View.Model="{Binding LoadedControl}"
附加属性告诉caliburn找到绑定的视图模型的视图,并将ContentControl的Content
属性设置为它。
答案 2 :(得分:1)
这是你应该做的:
StartView:
<Window x:Class="test.Views.StartView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:test.ViewModel"
Title="Window1" Height="300" Width="516">
<Grid>
<Menu IsMainMenu="True" Margin="0,0,404,239">
<MenuItem Header="_Einstellungen">
<MenuItem Header="Server" />
</MenuItem>
</Menu>
<UCStatistikView x:Name="myUCStatistikView" Margin="0,28,0,128" />
</Grid>
</Window>
StartViewModel:
namespace test.ViewModel
{
public class StartViewModel : ViewModelBase
{
private UCStastistikViewModel _myControlViewModel;
public StartViewModel()
{
_myControlViewModel = new UCStastistikViewModel();
}
public UCStastistikViewModel MyControlViewModel
{
get { return _myControlViewModel; }
set
{
if (value == _myControlViewModel)
return;
_myControlViewModel = value;
OnPropertyChanged("MyControlViewModel");
}
}
}
}
UCStatistikView:
<UserControl x:Class="test.Views.UCStatistik"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:test.ViewModel"
mc:Ignorable="d"
d:DesignHeight="188" d:DesignWidth="508">
<Grid Background="red">
</Grid>
</UserControl>
StartView的代码:
this.myUCStatistikView.DataContext = ((StartViewModel)this.DataContext).MyControlViewModel;
在测试了不同的方法之后,我的结论是,如果你有userControls,那么datacontext绑定的最佳方法是父视图的代码隐藏。
编辑:ViewModel定位器适用于简单的示例,但如果您的ViewModel必须动态实例化(大多数情况下它的构造函数需要参数),您就无法使用它。 我个人因此而停止使用定位器。
答案 3 :(得分:-1)
评论: - http://patelrocky1608.wordpress.com/2013/12/26/how-to-add-custom-control-dynamically-in-wpf/
其中包含用于动态理解UserControl的整个代码..