2015-05-19 139 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