WPF自定义控件 - 如何从静态ObservableCollection绑定列表框?

时间:2010-06-28 17:45:37

标签: c# wpf binding listbox observablecollection

我不确定如何准确地解决这个问题。我在NameField.cs类中有一个静态的ObservableCollection。我根本不知道如何将它绑定到列表框。

  • 我不应该使用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>

1 个答案:

答案 0 :(得分:3)

现在,我不确定你正在做什么,因为你的类扩展了Control,所以我假设你正在创建一个自定义控件,所以我的回答是基于这个。我也假设NamePrefixes永远不会改变,这就是你为它使用静态的原因。

我会跳过静态并执行此操作:

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它有时会起作用。

如果您绝对需要将其设置为静态,因为必须在更新其中任何一个控件时更新所有控件,那么您可以使observable collection静态并将ItemsSource绑定到{x:Static local:NameField.NamesPrefix}。只是意识到你只能绑定到公共属性,而不能绑定到字段或方法(不使用对象数据源或其他东西)。