2015-05-19 110 views
0

是否可以在WPF中从xmlns-packages(命名空间)的加载位置定义一个自定义区域。我的目标是定义喜欢的东西:钩入wpf xmlns命名空间导入

xmlns:customUI="db-ui:IronPythonControl" 

,这样我可以从数据库中加载我的控制,并用它在XAML这样的:

<IronPythonControl x:Name="..." ... /> 

谢谢!

+0

您的目标是动态加载并显示XAML代码? –

+0

我已经动态加载并显示带有Ironpython的XAML代码。现在我想加载其他动态控件的动态控件。例如,我使用XAML和IronPython创建了一个自定义文本框,并希望将它用于带有XAML和ironPython的自定义窗口中。 – BendEg

回答

3

我相信你可以用MarkupExtension很好地解决这个问题。

我根据this guide生成了以下psueocode。

最终目标是这样的。

<ContentControl Content="{ipc:IronPythonControl IronTextBox}"/> 

我们定义标记扩展为这样:

namespace IronPythonControlsExample { 
    public class IronPythonControl : MarkupExtension 
    { 
     public string Name { get; private set;} 
     public IronPythonControl(string name) 
     { 
      Name = name; 
     } 

     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      if (!string.IsNullOrEmpty(Name)) 
      { 
       return LoadControl(Name); 
      } 
     } 

     public FrameworkElement LoadControl(string name){/*Load XAML Control from database here*/} 

    } 
} 

关键零部件这里是我们扩展的MarkupExtension,并覆盖ProvideValue。在ProvideValue中,我们验证我们的状态信息并加载控件。

在LoadControl中,您将放置代码以从数据库加载XAML,将其从Xaml转换为对象,然后将RootObject作为结果返回。

您最终可能会使用比FrameworkElement更高或更低级别的控件。

现在我们已经定义了装载机的扩展,我们可以在我们的项目

<Window x:Class="IronPythonControlsExample.IronPythonWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:ipc="clr-namespace:IronPythonControlsExample" 
    Title="IronWindow" Height="300" Width="300"> 

    <ContentControl Content="{ipc:IronPythonControl IronTextBox}"/> 

</Window> 

使用它虽然这是不挂钩到命名空间声明,它将允许你动态地加载和注入数据驱动的控制。

一个非常相似,但另一种方法是定义一个CustomControl和基它关闭ContentControl中的,在这个例子中,我们将使用.NET 4.0 x:Arguments directive以简化代码:

public class IronPythonControl : ContentControl 
{ 
    public IronPythonControl(string name) 
    { 
     Debug.Assert(!string.IsNullOrEmpty(name), "No name provided for control"); 
     Content = LoadControl(name); 
    } 

    public FrameworkElement LoadControl(string name){/*Load XAML Control from database here*/} 
} 

在使用我们的结果会是这样的:

<Window x:Class="IronPythonControlsExample.IronPythonWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:ipc="clr-namespace:IronPythonControlsExample" 
    Title="IronWindow" Height="300" Width="300"> 

    <ipc:IronPythonControl> 
     <x:Arguments> 
      <x:String>IronTextBox</x:String> 
     </x:Arguments> 
    </ipc:IronPythonControl> 

</Window> 

另一个好方法是非常相似,这CustomControl。然而,不要在构造函数中使用参数,我们可以定义一个PropertyChangedCallback。

public class IronPythonControl : ContentControl 
{ 
    public static readonly DependencyProperty ControlNameProperty = 
          DependencyProperty.Register("ControlName", typeof(string), typeof(IronPythonControl), new FrameworkPropertyMetadata("IronTextBlock", ControlNameChangedCallback)); 

    private static void ControlNameChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args) 
    { 
     Content = LoadControl(ControlName); 
    } 

    public string ControlName 
    { 
     get { return (string)GetValue(ControlNameProperty); } 
     set { SetValue(ControlNameProperty, value); } 
    } 

    public FrameworkElement LoadControl(string name){/*Load XAML Control from database here*/} 
} 

而对于这种情况下一个XAML例如:

<ipc:IronPythonControl ControlName="IronTextBox"/> 

</Window> 

这些例子应该提供一个良好的解决方案,将加载XAML在UI加载时间,可以控制任何一个。
请注意,基于Ctor的方法和MarkupExtension不是动态的,如果您不希望控件在运行时更改,那么这很好。

理论上,PropertyChanged方法将允许您更改控件名称并根据新名称动态地重新载入新内容。如果将ControlName绑定到TextBox并将其绑定UpdateSourceTrigger设置为PropertyChanged,则可能很容易失控。

+0

你也可以参考这些SO文章的更多细节: http://stackoverflow.com/questions/910814/loading-xaml-at-runtime –

+0

我认为你最后的解决方案符合我的概念。我会尝试。非常感谢您的详细解答! – BendEg