C# 如何将UserControls动态加载到TabControl
我有几个UserControls(在不同的DLL中)作为TabItems插入到我的主应用程序(EXE)的TabControl中。这是我用来加载它并将其添加到TabControl的XAML:C# 如何将UserControls动态加载到TabControl,c#,wpf,binding,C#,Wpf,Binding,我有几个UserControls(在不同的DLL中)作为TabItems插入到我的主应用程序(EXE)的TabControl中。这是我用来加载它并将其添加到TabControl的XAML: <TabControl x:Name="mainTabControl"> <TabItem Style="{StaticResource VertAlign}" Header="firstDll"> <view1:ControlOfTheFirstDll
<TabControl x:Name="mainTabControl">
<TabItem Style="{StaticResource VertAlign}" Header="firstDll">
<view1:ControlOfTheFirstDll />
</TabItem>
<TabItem Style="{StaticResource VertAlign}" Header="secondDll">
<view2:ControlOfTheSecondDll />
</TabItem>
</TabControl>
不知何故,我需要动态加载UserControls,它们基于Data1.dll
和Data2.dll
。比如:
<TabControl x:Name="mainTabControl">
<TabItem Style="{StaticResource VertAlign}" Header="firstDll">
<ContentControl Content="{Binding PluginInstance.Control.???}" />
</TabItem>
<TabItem Style="{StaticResource VertAlign}" Header="secondDll">
<ContentControl Content="{Binding PluginInstance.Control.???}" />
</TabItem>
</TabControl>
但是,我似乎无法使控件上的绑定正常工作。我最近刚刚创建了类似的东西,但它与您的实现并不完全匹配,因为我正在通过简单的反射来实现它(而且该应用程序根本不是MVVM)。给你,我希望你能找到一些有用的东西 a。所有DLL都有一个实现IPlugin接口的类
public interface IPlugin
{
string Name { get; }
UserControl PluginControl { get; } //or a tab item
}
//a sample dll would have
public class SamplePlugin : IPlugin
{
public string Name { get { return "sample"; } }
public PluginControl
{
get {
return AnInstanceOfControlHere; //create this somewhere
}
}
}
b。在我的主机应用程序中,扫描所有DLL并反映所有类
实现IPlugin,然后实例化
List<IPlugin> _LISTOFALLPLUGINS = new List<IPlugin>();
public void LoadPlugins()
{
if (Directory.Exists(YOURFOLDERPATH_HERE))
{
string[] pluginfiles = Directory.GetFiles(YOURFOLDERPATH_HERE, "*.dll", SearchOption.AllDirectories);
var pluginbasetype = typeof(IPlugin);
foreach (string pluginpath in pluginfiles)
{
Assembly assembly = Assembly.LoadFile(pluginpath);
List<Type> plugins = assembly.GetTypes().Where(t => pluginbasetype.IsAssignableFrom(t)).ToList();
foreach (Type plugintype in plugins)
{
if (!plugintype.IsAbstract)
{
IPlugin plugin = assembly.CreateInstance(plugintype.FullName) as IPlugin;
_LISTOFALLPLUGINS.Add(plugin);
}
}
}
}
}
注意:这可能不是您想要的,特别是关于仅使用xaml,
但我发现这是一个非常简单的插件式组件,很容易实现。
除了UI,您还可以在插件dll中合并复杂的操作。
不过,这是基于我多年前读到的东西。找不到链接
*如果不是你,那么我真的希望其他人能发现它有用:)你可以这样尝试,因为你的用户控件在另一个dll中。创建一个包含两个接口的新项目
public interface IMetaData
{
string Name
{
get;
}
}
public interface IView
{ }
然后将此项目引用到主应用程序,并将data1.dll添加到usercontrol,如下所示
[Export(typeof(IView)), PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.Any)]
[ExportMetadata("Name", "uc1")]
public partial class myusercontrol : UserControl,IView
{
public ServiceContractList()
{
InitializeComponent();
}
}
在您的视图模型中
class Plugin
{
[ImportMany]
public IEnumerable<IDataProvider> DataProvider { get; set; }
//add this
[ImportMany(typeof(IView), AllowRecomposition = true)]
public IEnumerable<Lazy<IView,IMetaData>> Plugins
{
get;
set;
}
public Plugin()
{
try
{
AggregateCatalog aggregatecatalogue = new AggregateCatalog();
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(Assembly.LoadFile("...\\Data1.dll")));
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(Assembly.LoadFile("...\\Data2.dll")));
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(Assembly.GetAssembly(typeof(IDataProvider))));
CompositionContainer container = new CompositionContainer(aggregatecatalogue);
container.ComposeParts(this);
}
catch (FileNotFoundException fnfex)
{
Console.WriteLine(fnfex.Message);
}
catch (CompositionException cex)
{
Console.WriteLine(cex.Message);
}
}
将此绑定到ContentControl
<TabControl x:Name="mainTabControl">
<TabItem Style="{StaticResource VertAlign}" Header="firstDll">
<ContentControl Content="{Binding PlugIn}" />
</TabItem>
:我正在做一些与您的解决方案类似的事情,但有一个问题,即如果我想在同一窗口中显示两个相同类型的控件,我只会得到一个实例。是否有可能创建同一控件的两个实例?
class Plugin
{
[ImportMany]
public IEnumerable<IDataProvider> DataProvider { get; set; }
//add this
[ImportMany(typeof(IView), AllowRecomposition = true)]
public IEnumerable<Lazy<IView,IMetaData>> Plugins
{
get;
set;
}
public Plugin()
{
try
{
AggregateCatalog aggregatecatalogue = new AggregateCatalog();
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(Assembly.LoadFile("...\\Data1.dll")));
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(Assembly.LoadFile("...\\Data2.dll")));
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(Assembly.GetAssembly(typeof(IDataProvider))));
CompositionContainer container = new CompositionContainer(aggregatecatalogue);
container.ComposeParts(this);
}
catch (FileNotFoundException fnfex)
{
Console.WriteLine(fnfex.Message);
}
catch (CompositionException cex)
{
Console.WriteLine(cex.Message);
}
}
private object _PlugIn;
public object PlugIn
{
get
{
return _PlugIn;
}
set
{
if (value != _PlugIn)
{
_PlugIn = value;
OnPropertyChanged("PlugIn");
}
}
}
<TabControl x:Name="mainTabControl">
<TabItem Style="{StaticResource VertAlign}" Header="firstDll">
<ContentControl Content="{Binding PlugIn}" />
</TabItem>
var pluginContainer = Plugins.First(x => x.Metadata.Name == "uc1");
if (pluginContainer != null)
{
PlugIn=pluginContainer.Value;
OnPropertyChanged("PlugIn");
}