通过DataTemplate为WPF-ComboBoxItem设置TextSearch.Text

时间:2009-07-10 15:54:24

标签: c# wpf data-binding combobox datatemplate

我使用datatemplate来可视化ComboBox中的一些项目, ItemsSource绑定到ObservableCollection。 为了简单起见,假设我将人员纳入ObservableCollection:

public class Person {
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

我的DataTemplate看起来像这样:

<DataTemplate TargetType="{x:Type Person}">
  <StackPanel Orientation="Horizontal">
    <TextSearch.Text>
      <MultiBinding StringFormat="{} {0} {1}">
        <Binding Path="FirstName"/>
        <Binding Path="LastName"/>
      </MultiBinding>
    </TextSearch.Text>
    <TextBlock Text="{Binding FirstName}" Margin="2,0" />
    <TextBlock Text="{Binding LastName}"/>
  </StackPanel>
</DataTemplate>

现在我想在ComboBox中为全名启用自动完成功能,而不在我的person类上引入第三个属性。因此我不想在ComboBox上使用TextSearch.TextPath属性,而是想在DataTemplate中绑定每个ComboBoxItem的TextSearch.Text-Property。 不幸的是,当我这样做(使用MultiBinding和StringFormat,使用Snoop测试)时,绑定值仅为我的StackPanel注册,但是使用Snoop(很棒的工具)我发现这个stackpanel就像其他一些ComboBoxItemTemplate的内容一样,它放置另一个边框等,最后一个ComboBoxItem标签围绕我的外部StackPanel。因此,TextSearch.Text设置无效,因为它必须在创建的ComboBoxItem中设置,而不是在其中的某个位置。

现在问题:如何使用XAML-Styles和-Control-Templates将我的DataTemplate中的TextSearch.Text-Property传播到周围的ComboBoxItem? 该解决方案可能会修改ComboBox和ComboBoxItem的默认ControlTemplates以及我的自定义(Item-)DataTemplate,但不会使用任何Code-Behind,或者至少不会太多。也许附加的行为也可以。但我几乎肯定必须有一种方法可以使它无需工作,TemplateBinding或RelativeSource-stuff ... 当然,解决方案必须使我的键盘选择和文本完成工作,s。如果名单中包含汉斯约瑟夫和汉斯彼得,那么进入'汉斯'应该自动提出汉斯约瑟夫,而快速进入'汉斯P'应该自动提出汉斯彼得。

任何解决方案?

2 个答案:

答案 0 :(得分:8)

简短回答:您想要做的事情不能直接在XAML中完成,但还有其他方法可以做到。

答案很长:ComboBox直接在Items或ItemsSource集合中存储的数据项中查找TextSearch.Text属性。因此,您无法在数据模板或样式中设置属性,因为它们适用于用于显示数据项的对象,而不适用于数据项本身。

特别是,如果查看TextSearch class页面上的示例,您将看到它们将TextSearch.Text属性附加到进入ComboBox.Items集合的Image对象。您可以通过使Person成为DependencyObject在您的程序中执行此操作,但我认为您不希望在每个对象上设置该属性。

这里有几个选项:

如果可以修改Person类,则可以定义ToString()方法以将文本返回到自动完成,或者定义像Fullname这样的任意属性,并在ComboBox上设置Textsearch.TextPath。例如:

public class Person
{
     string FirstName { get; set; }
     string LastName {get; set; }
     string FullName { get { return String.Format("{0} {1}", FirstName, LastName); } }
}

<ComboBox TextSearch.TextPath="FullName" ItemsSource="collectionOfPersons"/>

另外,如果您不想触摸Person,可以创建一个公开这些属性的包装类。

答案 1 :(得分:1)

面板周围的东西是默认容器。您需要将TextSearch.Text属性应用于容器。您应该可以通过ItemContainerStyle设置属性,如下所示:

<ComboBox.ItemContainerStyle>
    <Style TargetType="{x:Type ComboBoxItem}">
        <Setter Property="TextSearch.Text">
            <Setter.Value>
                <MultiBinding StringFormat="{} {0} {1}">
                    <Binding Path="FirstName"/>
                    <Binding Path="LastName"/>
                </MultiBinding>
            </Setter.Value>
        </Setter>
    </Style>
</ComboBox.ItemContainerStyle>