C# 从代码中设置自定义标记扩展名
如何从代码设置自定义C# 从代码中设置自定义标记扩展名,c#,wpf,xaml,markup,markup-extensions,C#,Wpf,Xaml,Markup,Markup Extensions,如何从代码设置自定义标记扩展名 您可以从Xaml轻松设置if。绑定和动态资源也是如此 <TextBox FontSize="{Binding MyFontSize}" Style="{DynamicResource MyStyle}" Text="{markup:CustomMarkup}"/> 动态资源:使用SetResourceReference textBox.SetResourceReference(TextBox.StylePrope
标记扩展名
您可以从Xaml轻松设置if。绑定
和动态资源
也是如此
<TextBox FontSize="{Binding MyFontSize}"
Style="{DynamicResource MyStyle}"
Text="{markup:CustomMarkup}"/>
textBox.SetResourceReference(TextBox.StyleProperty, "MyStyle");
MarkupExtension
?我是否应该调用ProvideValue
,在这种情况下,我如何获得IServiceProvider
*
CustomMarkupExtension customExtension = new CustomMarkupExtension();
textBox.Text = customExtension.ProvideValue(??);
H.B.回答了这个问题。只是在这里添加一些细节来说明我为什么要这么做。我试图为以下问题创建一个解决方案 问题是您无法从
绑定中派生并重写ProvideValue
,因为它是密封的。您必须执行类似的操作:。但问题是,当您将绑定
返回给设置程序
时,会得到一个异常,但在样式
之外,它工作正常
我在几个地方读到过,如果TargetObject
是一个Setter
,您应该返回MarkupExtension
本身,以允许它在应用于实际的框架元素后重新评估,这是有意义的
- (在评论中)
但是,这仅在TargetProperty
类型为对象时有效,否则将返回异常。如果您查看BindingBase
的源代码,您会发现它确实做到了这一点,但框架似乎有一些秘密成分使其工作。我认为没有代码等价物,这些服务只能通过XAML提供。发件人:
MarkupExtension只有一个虚拟方法ProvideValue。InputServiceProvider参数是当XAML处理器调用标记扩展时,服务如何与实现通信
可能会对这个问题有所帮助。我记得他们展示了一些可能有用的代码示例。正如H.B.所指出的,MarkupExtension
仅用于XAML中
Binding
的独特之处在于它实际上源自MarkupExtension
,这使得可以使用扩展语法{Binding…}
或完整标记..
并在代码中使用它
但是,您始终可以尝试创建一个中间对象(类似于BindingOperations
),该对象知道如何使用自定义标记扩展并将其应用于目标DependencyObject
为此,我相信您需要使用(对于.NET4)或接口(对于.NET3.x)。我不完全确定如何使用属性和/或接口,但它可能会为您指明正确的方向。作为替代方案,它是在代码中生成的,但不一定像XAML那样优雅:
var markup = new CustomMarkup();
markup.ProvideValue(new Target(textBox, TextBox.TextProperty));
目标的实施简单地说是:
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”的引用。有了以上内容,您需要保留对它的引用。如果您的标记扩展相当简单,并且创建了一个绑定并从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()
显然,如果您正在做比这更复杂的事情,那么这个解决方案可能不合适
如何从代码中设置自定义标记扩展名
如果可以修改它,那么只需将逻辑提取到单独的SomeMethod
,可以单独调用和/或从ProvideValue
调用
而不是
textBox.Text = customExtension.ProvideValue(??);
你管它叫什么
customExtension.SomeMethod(textBox, TextBox.TextProperty);
我们通常会创建自定义属性扩展(在xaml中这样使用):
因为我意识到有时有必要使用代码中的标记扩展,所以我一直在尝试以这种方式编写它们。嘿,H.B.是的,我也读过这篇文章,但我希望仍然有一种方法。这是一个非常坏的消息,而定制MarkupExtensions
似乎是一个半实用的概念。如果TargetProperty不是object
类型,则它们不能用于样式
Setter
,因此我希望通过在附加的行为中应用它来解决此问题,但计划已经完成。不管怎样,谢谢你的帮助answer@Meleak:好的,正如名称所说的MarkupExtensions扩展了标记,它们并不是真正用于代码中。顺便说一句,我无法重现在Setter中使用MarkupExtensions的任何问题。我同意,这不仅仅是名称所暗示的,只是仍然希望有一种方法:)我在评论中不是很清楚,问题是当您向Setter
提供绑定
值时。你已经回答了这个问题,我接受你的回答。在我的问题中添加了一些细节,说明了我为什么要这样做。在这个特定主题上,我没有找到任何东西,但是+1是一个有趣的链接:)我不确定你所说的“使绑定独一无二”是什么意思,它源自MarkupExtension
,我的自定义MarkupExtension
,我看不出区别。对于你答案的第二部分,你似乎在正确的轨道上,很高兴知道+1我试图传达的是,绑定
没有遵循创建MyClass
并附带MyClassExtension
的常规,后者通常会在标记中提供类型为MyClass
的值。我仍然不确定是否遵循,但任何标记扩展
都可以像{markup:Custom}那样设置
和
。不管怎样,没关系。我通过使用多重绑定解决了我的问题。是的,我认识这个人
customExtension.SomeMethod(textBox, TextBox.TextProperty);
<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
}
}