挂钩到 wpf xmlns 命名空间导入
Hook into wpf xmlns namespace import
是否可以在 WPF 中定义自定义区域,从中加载 xmlns 包(命名空间)。我的目标是定义如下内容:
xmlns:customUI="db-ui:IronPythonControl"
这样我就可以从数据库加载我的控件并在 xaml 中使用它,如下所示:
<IronPythonControl x:Name="..." ... />
谢谢!
我相信你可以使用 MarkupExtension.
很好地解决这个问题
我根据 this guide.
生成了以下伪代码
最终目标将是这样的。
<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>
这些示例中的任何一个都应该提供一个很好的解决方案,它将在 UI 加载时间加载 XAML 控件。
请注意,基于 Ctor 的方法和 MarkupExtension 不是动态的,如果您不希望控件在 运行 时间更改,这很好。
理论上,PropertyChanged 方法将允许您更改控件名称并根据新名称动态重新加载新内容。如果将 ControlName 绑定到 TextBox 并将其绑定 UpdateSourceTrigger 设置为 PropertyChanged,这很容易失控。
是否可以在 WPF 中定义自定义区域,从中加载 xmlns 包(命名空间)。我的目标是定义如下内容:
xmlns:customUI="db-ui:IronPythonControl"
这样我就可以从数据库加载我的控件并在 xaml 中使用它,如下所示:
<IronPythonControl x:Name="..." ... />
谢谢!
我相信你可以使用 MarkupExtension.
很好地解决这个问题我根据 this guide.
生成了以下伪代码最终目标将是这样的。
<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>
这些示例中的任何一个都应该提供一个很好的解决方案,它将在 UI 加载时间加载 XAML 控件。
请注意,基于 Ctor 的方法和 MarkupExtension 不是动态的,如果您不希望控件在 运行 时间更改,这很好。
理论上,PropertyChanged 方法将允许您更改控件名称并根据新名称动态重新加载新内容。如果将 ControlName 绑定到 TextBox 并将其绑定 UpdateSourceTrigger 设置为 PropertyChanged,这很容易失控。