Wpf 是否可以使用绑定按名称加载控件?
在我的应用程序中,我需要不同I/O设备的集合,例如串行、OPC、USB设备等。我使用MEF框架提供了一种处理集合并允许添加新设备的方法 我的项目看起来像这样:Wpf 是否可以使用绑定按名称加载控件?,wpf,binding,controls,Wpf,Binding,Controls,在我的应用程序中,我需要不同I/O设备的集合,例如串行、OPC、USB设备等。我使用MEF框架提供了一种处理集合并允许添加新设备的方法 我的项目看起来像这样: Atf.Model 'contains the model Atf.Gui 'the views and view-models Atf.Devices 'contains implementations of IDevice and exports them 许多设备都需要配置,因此设备接口公开了自定义控件的路
Atf.Model 'contains the model
Atf.Gui 'the views and view-models
Atf.Devices 'contains implementations of IDevice and exports them
许多设备都需要配置,因此设备接口公开了自定义控件的路径和相应的视图模型,这些控件和视图模型处理设备配置的编辑。我试图坚持MVVM模式,并希望尽可能地分离视图和模型。同时,我希望保持与设备集合的耦合尽可能松
在Atf.Gui
中,我有一个控件,显示所有发现的设备和激活的设备。选择激活的设备时,我希望动态显示其“编辑器”
我该怎么做?以下是一些(疯狂的)想法:
Idea-1只需使用设备对象中的路径在我的视图模型中加载一个UserControl
。这将打破MVVM分离,并使该部分“不稳定”
public System.Windows.Controls.UserControl ConfigureControl
{
get
{
// code to load the UserControl using the path property
}
}
Idea-2让设备仅公开视图模型,并使用映射(在设备存储库中定义)拾取视图。我不知道该怎么做
<myeditorcontainer>
<ContainerControl Content="{Binding CurrentlySelectedDeviceViewModel}"/>
</myeditorcontainer>
Idea-3在我看来,使用绑定加载控件。不确定这是否可能
<myeditorcontainer>
<UserControl Path="{Binding CurrentlySelectedDeviceViewPath}"
DataContext="{Binding CurrentlySelectedDeviceViewModel}"/>
</myeditorcontainer>
我认为想法2是一个不错的选择 假设
ContainerControl
源自ContentControl
,您应该能够为要显示的每种类型的视图模型指定DataTemplate
,然后根据视图模型的类型呈现正确的UI。例如:
<myeditorcontainer>
<ContainerControl Content="{Binding CurrentlySelectedDeviceViewModel}">
<ContainerControl.Resources>
<DataTemplate DataType="{x:Type ViewModel1Type}">
<!-- controls for ViewModel1's UI -->
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel2Type}">
<!-- controls for ViewModel2's UI -->
</DataTemplate>
</ContainerControl.Resources>
</ContainerControl>
</myeditorcontainer>
如果您需要比视图模型的类型更大的灵活性来决定使用哪个样板,则可以指定一个。它将根据您想要的任何标准返回正确的模板以供使用。这就是我最后所做的,它似乎工作正常。关键特性是视图模型与视图具有相同的名称,但附加了“model”,并且视图模型派生自特定的类-DeviceSettingsBase XAML:
<ContentControl Content="{Binding ConfigControl}"/>
private RequiredDeviceViewModel rdvm;
public ContentControl ConfigControl
{
get
{
// get assembly which contains this object
Assembly assy = Assembly.GetAssembly(rdvm.Device.GetType());
// get View-Type using the name defined in the Device
Type viewType = assy.GetType(rdvm.Device.ConfigureControlResourceName, true);
// get ViewModel-Type using the viewname + Model (may be null)
Type viewModelType = assy.GetType(rdvm.Device.ConfigureControlResourceName + "Model", false);
// instantiate the view control
ContentControl view = (ContentControl)Activator.CreateInstance(viewType);
// instantiate viewModel - if type not null
if (viewModelType != null)
{
object viewModel = (object)Activator.CreateInstance(viewModelType, new object[] { rdvm.RequiredDevice.Config.ConfigString });
view.DataContext = viewModel;
// all device viewModels must derive from DeviceSettingsBase
CurrentConfigViewModel = viewModel as DeviceSettingsBase;
if (CurrentConfigViewModel != null)
{
CurrentConfigViewModel.IsEditable = IsEditable;
CurrentConfigViewModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(vmb_PropertyChanged);
CurrentConfigViewModel.SettingsChanged += new SettingsChangedHandler(vmb_SettingsChanged);
}
}
return view;
}
}