views:

43

answers:

1

I'm not sure how to go about this exactly. I have a static ObservableCollection in the NameField.cs class. I just have no idea how to bind it to the listbox.

  • Should I not be using a ListBox?
  • Should I be using a DependencyProperty?
  • Should I be exposing the ObservableCollection through a property or by public?

I'm not sure what to do here...

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>
+1  A: 

Now, I'm not sure what you're doing as your class extends Control, so I'm assuming you're creating a custom control, so my answer is based off that. I'm also assuming that NamePrefixes never changes, which is why you're using a static for it.

I'd skip the statics and do this:

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>

You bind the ItemsSource to the root of the custom control (can't tell from your code what it is). You might be able to apply a name to your root and then just use ElementName=, IIRC it works sometimes.

If you ABSOLUTELY need to make it static because ALL controls must be updated when any one of them is updated, then you can make the observable collection static and bind ItemsSource to {x:Static local:NameField.NamesPrefix}. Just realize you can only bind to public properties, not to fields or methods (without using an object data source or something).

Will