我有几个UserControls(在不同的DLL中),我作为TabItems插入到我的主应用程序(EXE)的TabControl中。这是我用来加载它并将它添加到TabControl的XAML:
<TabControl x:Name="mainTabControl">
<TabItem Style="{StaticResource VertAlign}" Header="firstDll">
<view1:ControlOfTheFirstDll />
</TabItem>
<TabItem Style="{StaticResource VertAlign}" Header="secondDll">
<view2:ControlOfTheSecondDll />
</TabItem>
</TabControl>
现在,我更改了程序,以便动态加载每个DLL(Data1.dll
,Data2.dll
)。通过启动我的程序,可以创建以下类Plugin
的实例,并可以从我的ViewModel中访问。
class Plugin
{
[ImportMany]
public IEnumerable<IDataProvider> DataProvider { 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);
}
}
}
不知何故,我需要动态加载基于Data1.dll
和Data2.dll
的UserControls。类似的东西:
<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>
但是,我似乎无法对控件进行绑定。
答案 0 :(得分:1)
我刚刚创建了类似的东西,但它并不完全符合您的实现,因为我通过简单的反射(并且应用程序根本不是MVVM)。在这里,我希望你能找到有用的东西。
一个。所有的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
}
}
}
湾在我的主机应用程序中,扫描所有的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);
}
}
}
}
}
℃。然后只需加载控件
public void ShowPlugins()
{
foreach(IPlugin plugin in _LISTOFALLPLUGINS)
{
TabItem ti = new TabItem();
ti.Header = plugin.Name;
UserControl uc = app.PluginControl;
if (uc != null)
{
ti.Content = uc;
}
MYTAB.Items.Add(ti);
}
}
注意:这可能不是您正在寻找的,特别是关于使用xaml, 但我发现这是一个非常简单的插件式组件,易于实现。 除了UI之外,您还可以在插件dll中包含复杂的操作。 这是基于我多年前读过的东西。无法找到链接。
*如果不是你,那么我希望别人能发现它有用:)
答案 1 :(得分:1)
您可以尝试这样,因为您的用户控制在另一个DLL中。创建一个包含两个界面的新项目
public interface IMetaData
{
string Name
{
get;
}
}
public interface IView
{ }
并将此项目引用到您的Main应用程序,data1.dll将IView添加到您的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);
}
}
}
在object类型
的视图模型中创建一个属性private object _PlugIn;
public object PlugIn
{
get
{
return _PlugIn;
}
set
{
if (value != _PlugIn)
{
_PlugIn = value;
OnPropertyChanged("PlugIn");
}
}
}
将此绑定到ContentControl
<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");
}