从列表中向组合框添加元素

时间:2013-04-02 16:16:29

标签: c# xaml combobox itemssource

我的问题: 我有一个包含狗主人的列表框,我有一个带狗的列表框。我想修改狗列表框itemtemplate如下:DogName(文本块)+ DogKind(文本块)+所有者(组合框)。前两个是成功的,但我不能将现有的所有者添加到组合框。如果我给我的组合框命名如下:

<ComboBox x:Name="mycombo" />

我无法在c#代码中看到mycombo变量。 XAML:

<Window x:Class="CodeFirst.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sajat="clr-namespace:CodeFirst"
        Title="MainWindow" Height="557.638" Width="721.294"
        >
<Grid x:Name="grid1"> 
<ListBox x:Name="listbox2" HorizontalAlignment="Left" Height="313" Margin="338,10,0,0" VerticalAlignment="Top" Width="250">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">                        
                        <TextBlock Text="{Binding Path=Name}"/>
                        <TextBlock Text=", "/>
                        <TextBlock Text="{Binding Path=Kind}"/>     
                        <ComboBox />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
</ListBox>     
</Grid>
</Window>

如何将itemsource提供给组合框,或者我如何才能添加所有者?

2 个答案:

答案 0 :(得分:0)

如果使用DataContext,可以像这样设置Binding:

<ComboBox ItemsSource="{Binding Path=DataContext.MyItemsSource, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></ComboBox>

答案 1 :(得分:0)

首先,为了使用WPF或其他基于XAML的技术,您必须明白

UI is not Data. Data is Data. UI is UI.

这意味着您不应该操纵代码中的任何ComboBox或任何其他UI元素,以便用数据填充它们,而是创建ViewModel并将这些对象绑定到该元素。

在此示例中,Window本身用作ViewModel,因为它是一个简单的示例,但您应该考虑将所有应用程序逻辑移动到单独的类中:

<Window x:Class="MiscSamples.UIisNotData"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="UIisNotData" Height="300" Width="300">
    <UniformGrid Rows="1" Columns="2">
        <DockPanel>
            <TextBlock Text="Owners:" DockPanel.Dock="Top" FontWeight="Bold" TextAlignment="Center" Margin="2"/>
            <Button Content="Add" Width="80" DockPanel.Dock="Bottom" Margin="2" Click="AddOwner"/>

            <ListBox ItemsSource="{Binding Owners}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <TextBlock Text="{Binding Name}" x:Name="block"/>
                            <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Visibility="Collapsed" x:Name="box"/>
                        </Grid>
                        <DataTemplate.Triggers>
                            <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBoxItem}}" Value="True">
                                <Setter TargetName="block" Property="Visibility" Value="Collapsed"/>
                                <Setter TargetName="box" Property="Visibility" Value="Visible"/>
                            </DataTrigger>
                        </DataTemplate.Triggers>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </DockPanel>

        <DockPanel>
            <TextBlock Text="Dogs:" DockPanel.Dock="Top" FontWeight="Bold" TextAlignment="Center" Margin="2"/>
            <ListBox ItemsSource="{Binding Dogs}" HorizontalContentAlignment="Stretch">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <DockPanel>
                            <ComboBox ItemsSource="{Binding DataContext.Owners, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                                      SelectedItem="{Binding Owner}" DisplayMemberPath="Name"
                                      DockPanel.Dock="Right" Width="100"/>
                            <TextBlock>
                                <Run Text="{Binding Name}"/>
                                <Run Text=", "/>
                                <Run Text="{Binding Kind}"/>
                            </TextBlock>
                        </DockPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </DockPanel>
    </UniformGrid>
</Window>

背后的代码(此代码应放在ViewModel中)

public partial class UIisNotData : Window
    {
        public ObservableCollection<Owner> Owners { get; set; }
        public ObservableCollection<string> Kinds { get; set; }
        public ObservableCollection<Dog> Dogs { get; set; } 

        public UIisNotData()
        {
            InitializeComponent();

            Owners = new ObservableCollection<Owner>
                {
                    new Owner() {Name = "Jack"},
                    new Owner() {Name = "Mike"},
                    new Owner() {Name = "Kirk"},
                    new Owner() {Name = "John"},
                };

            Kinds = new ObservableCollection<string>
                {
                    "Affenpinscher",
                    "Afghan Hound",
                    "Airedale Terrier",
                    "Akita"
                    //.. All the rest of dog Breeds taken from http://www.petmd.com/dog/breeds?breed_list=az#.UVsQKpPcmQo
                };

            Dogs = new ObservableCollection<Dog>
                {
                    new Dog() {Name = "Bobby", Kind = Kinds[0], Owner = Owners[0]},
                    new Dog() {Name = "Fido", Kind = Kinds[1], Owner = Owners[1]},
                    new Dog() {Name = "Toby", Kind = Kinds[2], Owner = Owners[2]}
                };

            DataContext = this;
        }

        private void AddOwner(object sender, RoutedEventArgs e)
        {
            Owners.Add(new Owner(){Name = "New Owner"});
        }
    }

数据模型:

    public class Owner : PropertyChangedBase
    {
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    public class Dog: PropertyChangedBase
    {
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }

        private Owner _owner;
        public Owner Owner
        {
            get { return _owner; }
            set
            {
                _owner = value;
                OnPropertyChanged("Owner");
            }
        }

        private string _kind;
        public string Kind
        {
            get { return _kind; }
            set
            {
                _kind = value;
                OnPropertyChanged("Kind");
            }
        }
    }

PropertyChangedBase类

public class PropertyChangedBase:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

结果:

enter image description here

有关此示例需要考虑的三个重要方面:

  • 我绝不会在代码中操纵UI元素。在WPF中大部分时间都是完全不必要的。
  • 数据模型中的类实现INotifyPropertyChanged以支持WPF中的双向绑定。
  • 集合属于ObservableCollection<T>类型,以便在从集合中添加/删除元素时支持自动通知(以便自动更新ListBoxes等)。

您可能会注意到的另一件事是我的示例中的XAML元素没有特定的大小或Margin值。像Margin="338,10,0,0"这样的东西通常是从Visual Studio设计器中获得的,表示结构不良的布局。我建议您查看WPF中的布局元素(DockPanelStackPanelGridUniformGridWrapPanel等),然后自己开始编写XAML代码而不是使用设计师。这将提供更高水平的可扩展性,并且还可以避免固定位置元素的细微差别。