4

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

4

2 回答 2

5

尝试从 ProvideValue 返回一个对象而不是字符串

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

于 2009-08-23T02:33:29.197 回答
2

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

为了解决这个问题,您需要返回动态而不是静态的东西。尝试从 ProvideValue 返回一个对象而不是一个字符串。返回的对象本身将包含一个计数器,当对该对象调用 ToString 时,它会返回计数器的字符串版本。

于 2009-03-23T03:03:28.203 回答