C# 如何管理从实用程序类加载动态视图
我正在开发一个wpf dll,其中包含许多视图以及附带的视图模型,以满足MVVM的要求 在我的项目中,我有一个类,它充当我的“视图管理器”,负责将每个视图绑定到它们正确的视图模型C# 如何管理从实用程序类加载动态视图,c#,wpf,C#,Wpf,我正在开发一个wpf dll,其中包含许多视图以及附带的视图模型,以满足MVVM的要求 在我的项目中,我有一个类,它充当我的“视图管理器”,负责将每个视图绑定到它们正确的视图模型 namespace ControlsAndResources { public class View { private static readonly ViewModelLocator s_viewModelLocator = new ViewModelLocator();
namespace ControlsAndResources
{
public class View
{
private static readonly ViewModelLocator s_viewModelLocator = new ViewModelLocator();
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.RegisterAttached("ViewModel", typeof(string),
typeof(ViewModelLocator), new PropertyMetadata(new PropertyChangedCallback(OnChanged)));
public static void SetViewModel(UserControl view, string value) => view.SetValue(ViewModelProperty, value);
public static string GetViewModel(UserControl view) => (string)view.GetValue(ViewModelProperty);
private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UserControl view = (UserControl)d;
string viewModel = e.NewValue as string;
switch (viewModel)
{
case "TestViewModel":
view.DataContext = s_viewModelLocator.TestViewModel;
break;
case "FooViewModel":
view.DataContext = s_viewModelLocator.FooViewModel;
break;
default:
view.DataContext = null;
break;
}
}
}
}
然后对每个xaml声明进行绑定(这里是一个示例)
...
...
这是完美的。但现在我想做的是,在MainView.xaml中,包含ContentControl或ItemControl,并使用绑定从视图类更新视图。我该怎么做呢?下面是我要做的:我将编写一个实现INotifyPropertyChanged的
MainViewModel
。我会给它一个SelectedChild属性。我将对您得到的INotifyPropertyChanged实现进行一些假设。如果这些假设是错误的,请告诉我,我们可以让它与你所拥有的一起工作
MainViewModel.cs
private Object _selectedChild;
public Object SelectedChild
{
get => _selectedChild;
set => SetProperty(ref _selectedChild, value);
}
MainViewModel将是我们的主视图的DataContext,可能是MainWindow
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
// More about this guy later
DynamicDataTemplateCreator creator = this.FindResource("DynamicDataTemplateCreator")
as DynamicDataTemplateCreator;
// This gibberish is a stand in for whatever information the template creator
// may need to figure out what type of view belongs to what type of viewmodel.
creator.ViewLookupInformation =
"My expatriate aunt Sally ate nine autumnal polar bears in Zanzibar.";
DataContext = new MainViewModel();
}
在MainWindow的XAML中,我们将把ContentControl绑定到SelectedChild,并创建一个模板选择器实例(见下文),用于创建显示SelectedChild的模板:
MainWindow.xaml
<Window.Resources>
<local:DynamicDataTemplateCreator x:Key="DynamicDataTemplateCreator" />
</Window.Resources>
<Grid>
<ContentControl
Content="{Binding SelectedChild}"
ContentTemplateSelector="{StaticResource DynamicDataTemplateCreator}"
/>
您应该有一个主viewmodel,其子viewmodel属性
公共对象SelectedChild{/*INPC stuff*/}
。主视图模型应该是主视图的DataContext。将SelectedChild绑定到主视图中ContentControl的Content属性。为每个viewmodel类型编写一个。隐式datatemplate只创建适当的视图。您的viewmodel定位器类不是必需的。啊,您似乎正在从某些外部源加载视图。在这种情况下,您可以编写一个只包含所需视图实例的新DataTemplate,而不是编写隐式datatemplates。您可以将其与上面的ContentControl一起使用。您希望尽可能少地重新发明我第一次评论中描述的轮子。@EdPlunkett好的,我将尝试这种方法。谢谢。我也看不出这一票有什么意义。不过,抱怨是没有意义的。你应该对这里的落选保持坚忍。不管怎么说,当时没有留下评论的人现在留下评论的可能性几乎为零。否决权似乎有点苛刻。也许上下文可以解释得更清楚一点。耸肩请投我一票,非常感谢。我喜欢的是,我可以告别ViewModelLocator。我只是觉得没什么意义。
<Window.Resources>
<local:DynamicDataTemplateCreator x:Key="DynamicDataTemplateCreator" />
</Window.Resources>
<Grid>
<ContentControl
Content="{Binding SelectedChild}"
ContentTemplateSelector="{StaticResource DynamicDataTemplateCreator}"
/>
public class DynamicDataTemplateCreator : DataTemplateSelector
{
// If mainwindow or the main viewmodel has information that we need about the
// dynamically loaded views, pass that information via this property. It can be any
// type you want, preferably the exact type of the information you are passing.
public object ViewLookupInformation { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
// item is the viewmodel.
Type viewType = null;
// A quickie UserControl I wrote for testing.
//viewType = typeof(VMView);
/*
* logic here to determine the type of view we want. Assign that Type to viewType
* If you need extra information from the main program, smuggle it in to here via
* ViewLookupInformation
*/
return new DataTemplate
{
VisualTree = new FrameworkElementFactory(viewType)
};
}
}