有这样的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
所以{my:Extension1}仅评估一次。我可以创建一个将为每个项目评估的计算属性吗?
答案 0 :(得分:5)
尝试从ProvideValue而不是字符串
返回一个对象
菲尔走在正确的轨道上......实际上,如果从模板调用标记扩展名,则需要从this
返回ProvideValue
。这将导致为模板生成的每个控件评估标记扩展。要确定对ProvideValue
的调用是否来自模板,您需要检查目标对象:在模板中,它将是System.Window.SharedDp
类型。我写了一篇关于blog post的文章。
答案 1 :(得分:2)
然后,您假设每次创建新的列表框项时,控制项模板定义将重新处理。出于性能原因,情况并非如此。第一次创建它的速度要快得多,然后每次都要克隆它。因此,你没有得到你想要的结果。调用扩展的结果正在被缓存并重用。
要解决此问题,您需要返回动态而非静态的内容。尝试从ProvideValue而不是字符串返回一个对象。返回的对象本身将包含一个计数器,当在该对象上调用ToString时,它返回计数器的字符串版本。