UserControl ItemsControl Binding - PullRequest
       27

UserControl ItemsControl Binding

2 голосов
/ 14 февраля 2012

Я разрабатываю UserControl, который содержит ItemsControl TextBoxes. У меня есть класс титров, который используется для контроля местоположения / Текст TextBlock

В окне XAML

<local:UserControl1>
    <local:UserControl1.Captions>
        <local:Caption Foreground="Black" Size="10"  Text="{Binding Path=SomeText}" X="100" Y ="100"></local:Caption>
    </local:UserControl1.Captions>
</local:UserControl1>

ItemsControl - это холст, в котором dataTemplate представляет собой TextBox

<ItemsControl ItemsSource="{Binding Path=Captions}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Background="Beige" Width="{Binding Path=Width}" Height="{Binding Path=Height}"  />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=Text}" Foreground="{Binding Path=Foreground}" FontSize="{Binding Path=Size}" ></TextBlock>

        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Setter Property="Canvas.Top" Value="{Binding Path=Y,PresentationTraceSources.TraceLevel=High}" />
            <Setter Property="Canvas.Left" Value="{Binding Path=X,PresentationTraceSources.TraceLevel=High}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

В UserControl есть ObservableCollection "Caption", которая получена из элемента Framework

public class Caption :FrameworkElement
{
    /// <summary>
    /// The actual text to display
    /// </summary>
    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    /// <summary>
    /// The font size
    /// </summary>
    public int Size
    {
        get { return (int)GetValue(SizeProperty); }
        set { SetValue(SizeProperty, value); }
    }

    /// <summary>
    /// The text foreground color
    /// </summary>
    public Brush Foreground
    {
        get { return (Brush)GetValue(ForegroundProperty); }
        set { SetValue(ForegroundProperty, value); }
    }

    /// <summary>
    /// The Top location of the text
    /// </summary>
    public double Y
    {
        get { return (double)GetValue(YProperty); }
        set { SetValue(YProperty, value); }
    }

    /// <summary>
    /// The left location of the text
    /// </summary>
    public double X
    {
        get { return (double)GetValue(XProperty); }
        set { SetValue(XProperty, value); }
    }

    public override string ToString()
    {
        return string.Format("Caption:{0}//{1}.{2}", this.X, this.Y, this.Text);
    }

    private static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string),
                                                                                          typeof(Caption),
                                                                                          new PropertyMetadata(
                                                                                              OnPropertyChanged));

    private static readonly DependencyProperty SizeProperty = DependencyProperty.Register("Size", typeof(int),
                                                                                          typeof(Caption),
                                                                                          new PropertyMetadata(
                                                                                              OnPropertyChanged));

    private static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register("Foreground",
                                                                                                typeof(Brush),
                                                                                                typeof(Caption),
                                                                                                new PropertyMetadata
                                                                                                    (OnPropertyChanged));

    private static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double),
                                                                                       typeof(Caption),
                                                                                       new PropertyMetadata(
                                                                                           OnPropertyChanged));

    private static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double),
                                                                                       typeof(Caption),
                                                                                       new PropertyMetadata(
                                                                                           OnPropertyChanged));

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var caption = (Caption)d;
    }
}

Каждый раз, когда подпись добавляется в коллекцию, она добавляется в логическое дерево

void Captions_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    if(e.Action == NotifyCollectionChangedAction.Add)
    {
        foreach(Caption c in e.NewItems)
        {
            AddLogicalChild(c);
            c.DataContext = this.DataContext;

        }
    }
}

Проблема в том, что привязка для Canvas.Top и Canvas.Left не работает

Отладка выдает следующее

System.Windows.Data Предупреждение: 54: создано выражение привязки (хэш = 14626603) для привязки (хэш = 8360729)

System.Windows.Data Предупреждение: 56: Путь: 'X'

System.Windows.Data Предупреждение: 58: BindingExpression (хэш = 14626603): Режим по умолчанию разрешен в OneWay

System.Windows.Data Предупреждение: 59: BindingExpression (хэш = 14626603): Триггер обновления по умолчанию разрешен в PropertyChanged

System.Windows.Data Предупреждение: 60: BindingExpression (хэш = 14626603): Присоединить к WpfApplicationQuery.Caption.Left (hash = 33822626)

System.Windows.Data Предупреждение: 65: BindingExpression (хэш = 14626603): Разрешающий источник

System.Windows.Data Предупреждение: 68: BindingExpression (хэш = 14626603): Найденный элемент контекста данных: заголовок (хэш = 33822626) (ОК)

System.Windows.Data Предупреждение: 76: BindingExpression (хэш = 14626603): Активировать с помощью корневого элемента

System.Windows.Data Предупреждение: 104: BindingExpression (хэш = 14626603): Элемент на уровне 0 нулевой - нет доступа

System.Windows.Data Предупреждение: 78: BindingExpression (хэш = 14626603): TransferValue - получил необработанное значение {DependencyProperty.UnsetValue}

System.Windows.Data Предупреждение: 86: BindingExpression (хэш = 14626603): TransferValue - использование запасного значения / значения по умолчанию 'NaN'

System.Windows.Data Предупреждение: 87: BindingExpression (хэш = 14626603): TransferValue - использование окончательного значения 'NaN'

Ошибка System.Windows.Data: 26: ItemTemplate и ItemTemplateSelector игнорируются для элементов, уже имеющих тип контейнера ItemsControl; Тип = 'Заголовок'

Так что, похоже, он привязан неправильно, и я не знаю, что означает последняя ошибка

Кроме того, ранее у меня был Caption, полученный из DependencyObject, и все работало (т.е. все отображалось), кроме привязки данных. Отсюда переход к framworkElement, как описано где-то на stackoverflow (и в блоге, который я сейчас не могу найти)

Редактировать 2012-02-14 Изменен первый пример кода XAML

Редактировать 2012-02-14 Заголовок происходит от FrameworkElement, так что он может участвовать в привязке данных, как описано здесь http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/aff23943-5483-40b2-816b-4ce687bc6bf8/ и здесь http://kentb.blogspot.com/2008_10_01_archive.html

Если Caption реализует INotifyPropertyChanged

<local:UserControl1>
    <local:UserControl1.Captions>
        <local:Caption Foreground="Black" Size="10"  Text="Hello" X="100" Y ="100"></local:Caption>
        <local:Caption Foreground="Black" Size="10"  Text="{Binding Path=Title}" X="100" Y ="100"></local:Caption>
    </local:UserControl1.Captions>
</local:UserControl1>

Первая строка работает. Второе - нет, эта ошибка отслеживается.

Не удается найти управляющий FrameworkElement или FrameworkContentElement для целевого элемента

Однако, если Caption является производным от FrameworkElement, теперь он предоставляет собственный ItemTemplate. Таким образом, возникает ошибка привязки, относящаяся к ItemTemplate / Selector.

...