从代码设置自定义 MarkupExtension
如何从代码中设置自定义 MarkupExtension
?
您可以轻松地从 Xaml 设置 if。 Binding
和 DynamicResource
也是如此。
<TextBox FontSize="{Binding MyFontSize}"
Style="{DynamicResource MyStyle}"
Text="{markup:CustomMarkup}"/>
通过代码隐藏设置相同的值需要稍微不同的方法
绑定:使用textBox.SetBinding或BindingOperations.SetBinding
绑定绑定 = new Binding("MyFontSize"); BindingOperations.SetBinding(textBox, TextBox.FontSizeProperty, 绑定);
DynamicResource:使用SetResourceReference
textBox.SetResourceReference(TextBox.StyleProperty, "MyStyle");
CustomMarkup: 如何从代码设置自定义
MarkupExtension
?我应该调用ProvideValue
吗?在这种情况下,我如何获取IServiceProvider
?*CustomMarkupExtension customExtension = new CustomMarkupExtension(); textBox.Text = customExtension.ProvideValue(??);
我在这个主题上发现的内容出人意料的少,所以可以做到吗?
HB已回答问题。只是在这里添加一些细节来说明我为什么要这样做。我尝试为以下问题创建解决方法。
问题是您无法从 Binding
派生并覆盖 ProvideValue
,因为它是密封的。你必须做这样的事情: 自定义的基类WPF 绑定标记扩展。但问题是,当您将 Binding
返回到 Setter
时,您会遇到异常,但在 Style
之外它工作正常。
我在几个地方读到,如果 TargetObject
是 Setter
,则应该返回 MarkupExtension
本身,以允许它在被执行后重新评估。应用于实际的FrameworkElement
,这是有道理的。
但是,只有当 TargetProperty
的类型为 object
时才有效,否则异常会再次出现。如果您查看 BindingBase
的源代码,您会发现它正是这样做的,但似乎该框架有一些秘密成分可以使其工作。
How do you set a custom MarkupExtension
from code?
You can easily set if from Xaml. The same goes for Binding
and DynamicResource
.
<TextBox FontSize="{Binding MyFontSize}"
Style="{DynamicResource MyStyle}"
Text="{markup:CustomMarkup}"/>
Setting the same values through code behind requires a little different approach
Binding: Use textBox.SetBinding or BindingOperations.SetBinding
Binding binding = new Binding("MyFontSize"); BindingOperations.SetBinding(textBox, TextBox.FontSizeProperty, binding);
DynamicResource: Use SetResourceReference
textBox.SetResourceReference(TextBox.StyleProperty, "MyStyle");
CustomMarkup: How do I set a custom
MarkupExtension
from code? Should I callProvideValue
and it that case, how do I get a hold of aIServiceProvider
?*CustomMarkupExtension customExtension = new CustomMarkupExtension(); textBox.Text = customExtension.ProvideValue(??);
I found surprisingly little on the subject so, can it be done?
H.B. has answered the question. Just adding some details here to why I wanted to do this. I tried to create a workaround for the following problem.
The problem is that you can't derive from Binding
and override ProvideValue
since it is sealed. You'll have to do something like this instead: A base class for custom WPF binding markup extensions. But then the problem is that when you return a Binding
to a Setter
you get an exception, but outside of the Style
it works fine.
I've read in several places that you should return the MarkupExtension
itself if the TargetObject
is a Setter
to allow it to reeavaluate once it is being applied to an actual FrameworkElement
and this makes sense.
- Markup Extension in Data Trigger
- Huge limitation of a MarkupExtension
- A base class for custom WPF binding markup extensions (in the comments)
However, that only works when the TargetProperty
is of type object
, otherwise the exception is back. If you look at the source code for BindingBase
you can see that it does exactly this but it appears the framework has some secret ingredient that makes it work.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我认为没有等效的代码,这些服务只能通过 XAML 提供。来自 MSDN:
I think there is no code-equivalent, the services are only available via XAML. From MSDN:
作为替代方案,它是在代码中生成的,但不一定像 XAML 那样优雅:
Target 的实现很简单:
唯一剩下的就是能够从 XAML 对象模型获取对“CustomMarkup”的引用。有了上面的内容,您就需要保留对它的引用。
What about this as an alternative, it is generated in code but not necessarily as elegant as XAML:
The implementation for Target is simply:
The only thing that remains is the ability to get a reference back to 'CustomMarkup' from the XAML object model. With the above you need to hang-on to a reference to it.
如果您的标记扩展相当简单并创建一个绑定并从 ProvideValue() 返回结果,那么您可以添加一个简单的帮助器方法:
然后在代码中,您可以只调用 CommandExtension.SetBinding() 而不是 BindingOperations.SetBinding()。
显然,如果您正在做比这更复杂的事情,那么这个解决方案可能不合适。
If your markup extension is fairly simple and creates a binding and returns the result from ProvideValue() then you can add a simple helper method:
And then in code, you can just call CommandExtension.SetBinding() instead of BindingOperations.SetBinding().
Obviously, if you are doing anything more complex than this then this solution may not be appropriate.
此 Silverlight 电视节目可能会提供一些线索这个问题。我记得他们展示了一些可能有用的代码示例。
This Silverlight TV show might shed some light on this issue. I recall them showing some code samples that might be helpful.
正如 HB 所指出的,
MarkupExtension
只能在 XAML 中使用。Binding
的独特之处在于它实际上源自MarkupExtension
,这使得可以使用扩展语法{Binding ...}
或完整标记...
并在代码中使用它。不过,您始终可以尝试创建一个中间对象(类似于
BindingOperations
),该对象知道如何使用自定义标记扩展并将其应用到目标DependencyObject
。为此,我相信您需要使用
XamlSetMarkupExtensionAttribute
(对于 .NET 4)或IReceiveMarkupExtension
接口(用于.NET 3.x)。我不完全确定如何使用属性和/或接口,但它可能会为您指明正确的方向。As H.B. pointed out, a
MarkupExtension
is only intended to be used within XAML.What makes
Binding
unique is that it actually derives fromMarkupExtension
which is what makes it possible to use the extension syntax{Binding ...}
or the full markup<Binding>...</Binding>
and use it in code.However, you can always try creating an intermediary object (something akin to
BindingOperations
) that knows how to use your custom markup extension and apply it to a targetDependencyObject
.To do this, I believe you would need to make use of the
XamlSetMarkupExtensionAttribute
(for .NET 4) or theIReceiveMarkupExtension
interface (for .NET 3.x). I am not entirely sure how to make use of the attribute and/or interface, but it might point you in the right direction.如果您可以修改它,则只需将逻辑提取到单独的
SomeMethod
中即可单独调用和/或从ProvideValue
调用。然后,而不是
您直接调用它
通常我们正在创建自定义属性扩展(在xaml中像这样使用):
这可以这样写:
因为我意识到有时有必要使用代码中的标记扩展我一直试图以这样的方式来写它们。
If you can modify it, then simply extract the logic into separate
SomeMethod
which can be called alone and/or fromProvideValue
.Then instead of
you just call it
Often we are creating custom property extensions (used like this in xaml):
This can be written like this:
Since I realized there is sometimes a necessity to use markup extensions from code I am always trying to write them in such a way.