Пользовательский элемент управления WPF. Как привязать список из статического ObservableCollection?

Я не уверен, как это сделать. У меня есть статическая коллекция ObservableCollection в классе NameField.cs. Я просто понятия не имею, как привязать его к списку.

  • Должен ли я не использовать ListBox?
  • Должен ли я использовать DependencyProperty?
  • Должен ли я раскрывать ObservableCollection через свойство или публично?

Я не уверен, что здесь делать...

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MyWPF
{

    [TemplatePart(Name = NameField.ElementPrefixBox, Type = typeof(ListBox))]
    public class NameField : Control
    {
        private const String ElementPrefixBox        = "PART_PrefixBox";

        private static ObservableCollection<NamePrefix> _namePrefixes;

        static NameField()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(NameField), new FrameworkPropertyMetadata(typeof(NameField)));

            _namePrefixes = new ObservableCollection<NamePrefix>();
        }

        public static void AddNamePrefix(NamePrefix namePrefix)
        {
            lock (_namePrefixes)
            {
                _namePrefixes.Add(namePrefix);
            }
        }

        public static IEnumerator<NamePrefix> GetNamePrefixes()
        {
            return _namePrefixes.GetEnumerator();
        }

    }

    /// <summary>
    /// A Key/Value structure containing a Name Prefix ID and String value.
    /// </summary>
    public struct NamePrefix
    {
        public NamePrefix(Int32 id, String prefix)
            : this()
        {
            ID = id;
            Prefix = prefix;
        }

        public Int32 ID { get; set; }
        public String Prefix { get; set; }
    }

}

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyWPF"
    xmlns:con="clr-namespace:MyWPF.Converters"
    >

    <Style TargetType="{x:Type local:NameField}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:NameField}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock TextWrapping="NoWrap" Text="Name:" VerticalAlignment="Center" Margin="3" />
                        <ListBox x:Name="PART_PrefixBox" VerticalAlignment="Center" Margin="3" >
                            <ListBox.ItemBindingGroup>
                                <BindingGroup Name="NamePrefixes"/>
                            </ListBox.ItemBindingGroup>
                        </ListBox>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

person myermian    schedule 28.06.2010    source источник


Ответы (1)


Теперь я не уверен, что вы делаете, поскольку ваш класс расширяет Control, поэтому я предполагаю, что вы создаете собственный элемент управления, поэтому мой ответ основан на этом. Я также предполагаю, что NamePrefixes никогда не меняется, поэтому вы используете для него static.

Я бы пропустил статику и сделал бы так:

public class NameField : Control
{
    private const String ElementPrefixBox        = "PART_PrefixBox";

    public ObservableCollection<NamePrefix> NamePrefixes {get;private set;}
    public NameField()
    {
        NamePrefixes = new ObservableCollection<NamePrefix>();
    }
}

<Style TargetType="{x:Type local:NameField}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:NameField}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock TextWrapping="NoWrap" Text="Name:" VerticalAlignment="Center" Margin="3" />
                    <ListBox x:Name="PART_PrefixBox" 
                        VerticalAlignment="Center" 
                        Margin="3" 
                        ItemsSource="{Binding NamesPrefix, RelativeSource={RelativeSource FindAncestor, Ancestortype=Whatever}}" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Вы привязываете ItemsSource к корню пользовательского элемента управления (не можете сказать из вашего кода, что это такое). Возможно, вы сможете применить имя к своему корню, а затем просто использовать ElementName=, IIRC иногда работает.

Если вам АБСОЛЮТНО нужно сделать его статическим, потому что ВСЕ элементы управления должны обновляться при обновлении любого из них, вы можете сделать наблюдаемую коллекцию статической и привязать ItemsSource к {x:Static local:NameField.NamesPrefix}. Просто поймите, что вы можете привязываться только к общедоступным свойствам, а не к полям или методам (без использования источника данных объекта или чего-то еще).

person Community    schedule 28.06.2010