MarkupExtension作为Template中的计算属性

时间:2009-03-23 00:59:26

标签: wpf templates markup-extensions

有这样的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}仅评估一次。我可以创建一个将为每个项目评估的计算属性吗?

2 个答案:

答案 0 :(得分:5)

  

尝试从ProvideValue而不是字符串

返回一个对象

菲尔走在正确的轨道上......实际上,如果从模板调用标记扩展名,则需要从this返回ProvideValue。这将导致为模板生成的每个控件评估标记扩展。要确定对ProvideValue的调用是否来自模板,您需要检查目标对象:在模板中,它将是System.Window.SharedDp类型。我写了一篇关于blog post的文章。

答案 1 :(得分:2)

然后,您假设每次创建新的列表框项时,控制项模板定义将重新处理。出于性能原因,情况并非如此。第一次创建它的速度要快得多,然后每次都要克隆它。因此,你没有得到你想要的结果。调用扩展的结果正在被缓存并重用。

要解决此问题,您需要返回动态而非静态的内容。尝试从ProvideValue而不是字符串返回一个对象。返回的对象本身将包含一个计数器,当在该对象上调用ToString时,它返回计数器的字符串版本。

相关问题