MarkupExtension как вычисляемое свойство в шаблоне - PullRequest
4 голосов
/ 23 марта 2009

Имея такое 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} вычисляется только один раз. Могу ли я создать вычисляемое свойство, которое будет оцениваться для каждого элемента?

Ответы [ 2 ]

5 голосов
/ 23 августа 2009

Попробуйте вернуть объект из ProvideValue вместо строки

Фил был на правильном пути ... на самом деле, вам нужно вернуть this из ProvideValue, если ваше расширение разметки вызывается из шаблона. Это приведет к оценке расширения разметки для каждого элемента управления, сгенерированного шаблоном. Чтобы определить, является ли вызов ProvideValue из шаблона, необходимо проверить целевой объект: в шаблоне он будет иметь тип System.Window.SharedDp. Я написал сообщение в блоге об этом.

2 голосов
/ 23 марта 2009

Затем вы делаете предположение, что каждый раз, когда создается новый элемент списка, определение шаблона элемента управления будет обрабатываться заново. По соображениям производительности это не так. Гораздо быстрее создать его в первый раз, а затем просто клонировать его каждый раз. Следовательно, вы не получаете желаемый результат. Результат вызова расширения кэшируется и используется повторно.

Чтобы обойти это, вам нужно вернуть что-то динамическое, а не статическое. Попробуйте вернуть объект из ProvideValue вместо строки. Возвращенный объект сам будет содержать счетчик и при вызове ToString для этого объекта он возвращает строковую версию счетчика.

...