如何将附加属性绑定到ComboBox的DisplayMemberPath?

时间:2013-10-30 20:41:12

标签: c# wpf binding

我似乎找不到正确的语法来允许附加属性用作ComboBox的DisplayMemberPath。

该属性为SelectorSwitchedControl.NameForSelector
它位于命名空间“LocalTest”中,映射到XAML前缀“local”。

这是代码......

<UserControl x:Class="Playground.SelectorSwitchedControlTest.SelectorSwitchedControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:glc="clr-namespace:Playground.CommonControls"
    xmlns:local="clr-namespace:Playground.SelectorSwitchedControlTest"
    Background="Transparent">

    <Border x:Name="MainBorder"
        BorderBrush="Gray" BorderThickness="1">

        <DockPanel>

            <glc:FixedToolBar DockPanel.Dock="Top">

                <ComboBox x:Name="MainSelector"
                    ItemsSource="{Binding Children, ElementName=MainPanel}"
                    DisplayMemberPath="(local:SelectorSwitchedControl.NameForSelector)" />

            </glc:FixedToolBar>

            <local:SelectorSwitchedControlPanel x:Name="MainPanel" />

        </DockPanel>

    </Border>

</UserControl>

...由于某种原因,我发现异常'前缀'本地'不会映射到命名空间。我不知道为什么它会说,就好像我删除'DisplayMemberPath'一行,''标签渲染就像它应该证明命名空间是映射的。

我也尝试了以下所有......

  • 的DisplayMemberPath = “本地:SelectorSwitchedControl.NameForSelector”
  • 的DisplayMemberPath = “(当地:SelectorSwitchedControl.NameForSelector)”
  • 的DisplayMemberPath = “SelectorSwitchedControl.NameForSelector”
  • 的DisplayMemberPath = “(SelectorSwitchedControl.NameForSelector)”
  • 的DisplayMemberPath = “LocalTest.SelectorSwitchedControl.NameForSelector”
  • 的DisplayMemberPath = “(LocalTest.SelectorSwitchedControl.NameForSelector)”

我知道这只是我心灵不工作的那一天,我错过了一些简单的事情,但这让我发疯了!那么正确的语法是什么?

3 个答案:

答案 0 :(得分:2)

DisplayMemberPath - 每个项目的显示字符串属性的路径。将其设置为“NameForSelector”,而不是“{Binding NameForSelector}”。

 <DockPanel>
    <ComboBox x:Name="MainSelector" ItemsSource="{Binding Children}" DisplayMemberPath="NameForSelector" />
 </DockPanel>

 public class SelectorSwitchedControl
    {
        public string Name { get; set; }
        public string NameForSelector{ get; set; }
    }

答案 1 :(得分:1)

我认为在DisplayMemberPath中使用常规控件的附加属性是不可能的。原因是您使用的属性路径是指在XAML中声明的XML命名空间。通常,当您使用附加属性语法时,在XAML / BAML阅读器创建对象时,可以使用解析器上下文,并且此上下文提供名称空间信息。但是DisplayMemberPath只是一个字符串,并不捕获此上下文,因此在您的属性路径实际用于创建绑定的位置,此上下文不可用于提供命名空间信息。通过阅读PresentationFramework.dll中的代码,您可能能够通过目标对象(您的属性所附加的对象)提供上下文,方法是实现IServiceProvider并返回合适的IXamlTypeResolver(相关代码从PropertyPath.GetTypeFromName开始)。

作为更便宜的替代方案,请考虑使用模板或模板选择器而不是DisplayMemberPath。如果您想使用默认查找机制,请尝试

<ItemTemplate>
  <DataTemplate>
    <ContextPresenter 
      Content="{Binding (local:SelectorSwitchedControl.NameForSelector)}"/>
  </DataTemplate>
</ItemTemplate>

答案 2 :(得分:0)

正确的值是

DisplayMemberPath="(local:SelectorSwitchedControl.NameForSelector)"

如果这不起作用,那么我会使用Snoop(http://snoopwpf.codeplex.com/)来确保正确设置该值。

这是最简单的工作示例

的Xaml:

<Window x:Class="WPFTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFTest"
    Title="MainWindow" Height="350" Width="525" Loaded="MainWindow_Loaded">
<Grid>
    <ComboBox Name="cb" DisplayMemberPath="(local:MainWindow.TestValue)" />
</Grid>

代码:

public static string GetTestValue(DependencyObject element)
    {
        return (string)element.GetValue(TestValueProperty);
    }

    public static void SetTestValue(DependencyObject element, string value)
    {
        element.SetValue(TestValueProperty, value);
    }

    public static readonly DependencyProperty TestValueProperty = DependencyProperty.RegisterAttached("TestValue", typeof(string), typeof(MainWindow), new FrameworkPropertyMetadata(null));

    private void MainWindow_Loaded(object sender, System.Windows.RoutedEventArgs e)
    {
        TextBlock tb = default(TextBlock);


        for (int i = 10; i <= 15; i++)
        {
            tb = new TextBlock();
            tb.Text = "Text for " + i;
            tb.SetValue(TestValueProperty, "Property For " + i);
            this.cb.Items.Add(tb);
        }
    }