如何从代码中设置自定义MarkupExtension
?
您可以轻松地从Xaml设置。 Binding
和DynamicResource
也是如此。
<TextBox FontSize="{Binding MyFontSize}"
Style="{DynamicResource MyStyle}"
Text="{markup:CustomMarkup}"/>
通过代码设置相同的值需要一些不同的方法
绑定:使用textBox.SetBinding或BindingOperations.SetBinding
Binding binding = new Binding("MyFontSize");
BindingOperations.SetBinding(textBox, TextBox.FontSizeProperty, binding);
DynamicResource:使用SetResourceReference
textBox.SetResourceReference(TextBox.StyleProperty, "MyStyle");
CustomMarkup :如何从代码中设置自定义MarkupExtension
?我是否应该致电ProvideValue
,如果是这样,我如何获得IServiceProvider
?*
CustomMarkupExtension customExtension = new CustomMarkupExtension();
textBox.Text = customExtension.ProvideValue(??);
我在这个问题上发现了很少,所以可以做到吗?
H.B。已回答了这个问题。只是在这里添加一些细节,为什么我想这样做。我试图为以下问题创建一个解决方法。
问题在于,由于密封,您无法从Binding
派生并覆盖ProvideValue
。你必须做这样的事情:A base class for custom WPF binding markup extensions。但问题是,当您将Binding
返回到Setter
时会出现异常,但在Style
之外,它会正常工作。
我已经在几个地方读到,如果MarkupExtension
是TargetObject
,则应该返回Setter
本身,以便在将其应用于实际FrameworkElement
后重新提交TargetProperty
1}}这是有道理的。
但是,仅当object
的类型为BindingBase
时才有效,否则异常就会返回。如果您查看{{1}}的源代码,您可以看到它确实如此,但看起来框架中有一些秘密因素可以使它工作。
答案 0 :(得分:6)
我认为没有代码等价,服务只能通过XAML获得。来自MSDN:
MarkupExtension只有一个虚拟方法ProvideValue。输入serviceProvider参数是在XAML处理器调用标记扩展时将服务传递给实现的方式。
答案 1 :(得分:5)
作为替代方案,它是在代码中生成的,但不一定像XAML那样优雅:
var markup = new CustomMarkup();
markup.ProvideValue(new Target(textBox, TextBox.TextProperty));
Target的实施很简单:
public struct Target : IServiceProvider, IProvideValueTarget
{
private readonly DependencyObject _targetObject;
private readonly DependencyProperty _targetProperty;
public Target(DependencyObject targetObject, DependencyProperty targetProperty)
{
_targetObject = targetObject;
_targetProperty = targetProperty;
}
public object GetService(Type serviceType)
{
if (serviceType == typeof(IProvideValueTarget))
return this;
return null;
}
object IProvideValueTarget.TargetObject { get { return _targetObject; } }
object IProvideValueTarget.TargetProperty { get { return _targetProperty; } }
}
唯一剩下的就是能够从XAML对象模型获取引用回“CustomMarkup”。有了上述内容,您需要依赖它来引用它。
答案 2 :(得分:3)
如果您的标记扩展非常简单并创建了一个绑定并从ProvideValue()返回结果,那么您可以添加一个简单的帮助方法:
public class CommandExtension : MarkupExtension
{
public CommandExtension(string name)
{
this.Name = name;
}
public string Name { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
return GetBinding(this.Name).ProvideValue(serviceProvider);
}
static Binding GetBinding(string name)
{
return new Binding("Commands[" + name + "]") { Mode = BindingMode.OneWay };
}
public static void SetBinding(DependencyObject target, DependencyProperty dp, string commandName)
{
BindingOperations.SetBinding(target, dp, GetBinding(commandName));
}
}
然后在代码中,您可以调用CommandExtension.SetBinding()而不是BindingOperations.SetBinding()。
显然,如果你做的事情比这更复杂,那么这个解决方案可能不合适。
答案 3 :(得分:2)
This Silverlight TV show可能会对这个问题有所了解。我记得他们展示了一些可能有用的代码示例。
答案 4 :(得分:1)
H.B.指出,MarkupExtension
仅用于XAML。
Binding
的独特之处在于它实际上源自MarkupExtension
,因此可以使用扩展语法{Binding ...}
或完整标记<Binding>...</Binding>
并使用它在代码中。
但是,您始终可以尝试创建一个中间对象(类似于BindingOperations
),该对象知道如何使用自定义标记扩展并将其应用于目标DependencyObject
。
为此,我相信您需要使用XamlSetMarkupExtensionAttribute
(针对.NET 4)或IReceiveMarkupExtension
界面(针对.NET 3.x)。我不完全确定如何使用属性和/或界面,但它可能会指向正确的方向。
答案 5 :(得分:0)
如何从代码中设置自定义 MarkupExtension?
如果你可以修改它,那么只需将逻辑提取到单独的SomeMethod
中,可以单独调用和/或从ProvideValue
调用。
然后代替
textBox.Text = customExtension.ProvideValue(??);
你打电话给它
customExtension.SomeMethod(textBox, TextBox.TextProperty);
我们经常创建自定义属性扩展(在xaml中使用如此):
<TextBox Text="{local:SomeExtension ...}" />
这可以这样写:
public class SomeExtension : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
var provider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
var target = provider.TargetObject as DependencyObject;
var property = provider.TargetProperty as DependencyProperty;
// defer execution if target is data template
if (target == null)
return this;
return SomeMethod(target, property);
}
public object SomeMethod(DependencyObject target, DependencyProperty property)
{
... // do something
}
}
由于我意识到有时需要使用代码中的标记扩展,我总是试图以这种方式编写它们。