如何在单个Combobox中分配Datacontext和静态值

时间:2013-01-18 18:34:40

标签: c# wpf

我想在一个datacontext中分配Combobox和静态值。我试过这个,

this.courseList.DataContext = ldc.Courses.OrderBy(x => x.CourseID);
this.courseList.Items.Add("All");
this.courseList.Items.Add("Others");

但是,它会InvalidOperationException was Unhandeled显示Items collection must be empty before using ItemsSource.

然后我尝试了这样,

this.courseList.Items.Add("All");       
foreach (var items in ldc.Courses.OrderBy(x => x.CourseID))
 {
   this.courseList.Items.Add(items);
 }
this.courseList.Items.Add("Others");       

它就像这个图像 enter image description here 由于我在此Combobox的XAML设计中使用了ItemTemplate,因此它不会完全按照我的方式显示这两个值AllOthers

以下是ItemTemplate

    <DataTemplate x:Key="CourseTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=CourseID}"/>
            <TextBlock Text=" : "/>
            <TextBlock Text="{Binding Path=CourseName}"/>
        </StackPanel>
    </DataTemplate>

...
 <ComboBox Name="courseList" VerticalAlignment="Top" SelectionChanged="courseList_SelectionChanged" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}" ItemTemplate="{StaticResource CourseTemplate}"/>

我希望它根据DataTemplate查看数据库条目,并分别查看AllOthers的简单字符串AllOthers,如下图所示。 enter image description here

任何建议。谢谢。

3 个答案:

答案 0 :(得分:2)

如错误所示,您只能直接使用ItemsSource或Items,而不能混合使用这两者。由于您实际上有两种不同类型的数据要以不同方式显示,因此您可以将它们全部添加到单个绑定集合中,然后让模板以不同方式呈现它们。第1步是构建单个集合:

this.courseList.ItemsSource = new object[] { "All" }.Concat(ldc.Courses.OrderBy(x => x.CourseID)).Concat(new[] { "Others" });

您现在在集合中有两种类型的数据:字符串和您认为是对象的对象。字符串将根据需要显示,无需任何额外工作,但您只需将DataTemplate应用于Course对象。最简单的方法就是用数据类型替换x:Key:

<DataTemplate DataType="{x:Type data:Course}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Path=CourseID}"/>
        <TextBlock Text=" : "/>
        <TextBlock Text="{Binding Path=CourseName}"/>
    </StackPanel>
</DataTemplate>

其中数据xmlns对应于Course对象的命名空间。

接下来只需从ComboBox中删除ItemTemplate属性,就可以获得所需的内容。

如果您在同一范围内的其他位置也绑定了Course对象但希望它们以不同方式显示,则可以在本地范围内更多地定位DataType模板(即Grid.Resources)或在ComboBox上使用DataTemplateSelector。

答案 1 :(得分:1)

由于ldc.Courses设置为DataContext,并且您有ItemsSource="{Binding}",这意味着组合框直接绑定到您的集合。当您尝试添加字符串时,这会产生问题,因为现在集合同时包含字符串和课程对象。

我认为这可能是最容易理解的解决方案。从第二种方法开始:

this.courseList.Items.Add("All");       
foreach (var items in ldc.Courses.OrderBy(x => x.CourseID))
 {
   this.courseList.Items.Add(items.CourseID.ToString() + " : " + items.CourseName);
 }
this.courseList.Items.Add("Others"); 

这会使你的组合框绑定到一个简单的字符串列表而不是对象,所以只要你在后台不需要其他信息,这将更容易消化,如果没有尝试混合的其他答案之一字符串和对象进入同一个集合。这也意味着您无需设置DataContextItemsSourceDataTemplate,因此请将其全部删除。

如果您希望保持模板添加更多控件,您可能还想查看其他一些答案。另一种方法是在您的课程对象上创建一个父类,它也可以采用更一般的ALLOTHER个案例,并在它们周围创建实际对象可能是最灵活的。这样,您就不会以字符串和对象的集合结束,这将导致您在操作集合时必须创建特殊的代码集。

答案 2 :(得分:1)

您可以使用ItemTemplate与转换器结合使用来解决此问题。

模板:

<ComboBox.ItemTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding Converter={StaticResource ComboBoxItemConverter}}" /> 
    </DataTemplate>
</ComboBox.ItemTemplate>

转换器:

public class ComboBoxItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is Courses)
        {
            var course = value as Courses;
            return course.CourseID + " : " + course.CourseName;
        }
        else
        {
            return value.ToString();
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}