MarkupExtension 作为模板中的计算属性
有了这样的 MarkupExtension
public class Extension1 : MarkupExtension
{
private static int _counter = 0;
public override object ProvideValue(IServiceProvider serviceProvider)
{
return string.Format("Item {0}", _counter++);
}
}
和这个 XAML,
<ListBox>
<ListBoxItem Content="{my:Extension1}"></ListBoxItem>
<ListBoxItem Content="{my:Extension1}"></ListBoxItem>
<ListBoxItem Content="{my:Extension1}"></ListBoxItem>
</ListBox>
我得到了这样的列表:
Item 1
Item 2
Item 3
现在我尝试使用这个 Style 生成相同的列表
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<TextBox Text="{my:Extension1}"></TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
,并且使用这样的 XAML,
<ListBox ItemsSource="{StaticResource data}"></ListBox>
我得到
Item 0
Item 0
Item 0
So {my:Extension1} 仅评估一次。 我可以创建一个将为每个项目进行评估的计算属性吗?
Having such MarkupExtension
public class Extension1 : MarkupExtension
{
private static int _counter = 0;
public override object ProvideValue(IServiceProvider serviceProvider)
{
return string.Format("Item {0}", _counter++);
}
}
and this XAML
<ListBox>
<ListBoxItem Content="{my:Extension1}"></ListBoxItem>
<ListBoxItem Content="{my:Extension1}"></ListBoxItem>
<ListBoxItem Content="{my:Extension1}"></ListBoxItem>
</ListBox>
I get such list:
Item 1
Item 2
Item 3
Now I try to generate the same list using this Style
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<TextBox Text="{my:Extension1}"></TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And with such XAML
<ListBox ItemsSource="{StaticResource data}"></ListBox>
I get
Item 0
Item 0
Item 0
So {my:Extension1} evaluated only once. Can I create a computed property that will be evaluated for every item?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Phil 是在正确的轨道上...实际上,如果您的标记扩展是从模板。 这将导致针对模板生成的每个控件评估标记扩展。 要确定对
ProvideValue
的调用是否来自模板,您需要检查目标对象:在模板中,它将是System.Window.SharedDp
类型。 我写了一篇关于此的博客文章 。Phil was on the right track... actually, you need to return
this
fromProvideValue
if your markup extension is called from a template. This will cause the markup extension to be evaluated for each control generated by the template. To determine if the call toProvideValue
is from a template, you need to check the target object : in a template, it will be of typeSystem.Window.SharedDp
. I wrote a blog post about that.然后,您假设每次创建新的列表框项时,都将重新处理控制项模板定义。 出于性能原因,情况并非如此。 第一次创建它要快得多,然后每次都克隆它。 因此你没有得到你想要的结果。 调用扩展的结果被缓存和重用。
为了解决这个问题,您需要返回动态而不是静态的内容。 尝试从 ProvideValue 返回一个对象而不是字符串。 返回的对象本身将包含一个计数器,当对该对象调用 ToString 时,它将返回计数器的字符串版本。
You are then making the assumption that every time a new list box item is created the control item template definition is going to be processsed afresh. For performance reasons this is not the case. Much quicker to create it the first time around and then just clone it each subsequent time. Hence your not getting the result you wanted. The result of calling the extension is being cached and reused.
To get around this you need to return something dynamic instead of static. Try returning an object from ProvideValue instead of a string. The returned object will itself contain a counter and when ToString is called on that object it returns the string version of the counter.