0

我的问题:我有一个带有狗主人的列表框,我有一个带有狗的列表框。我想修改狗列表框项模板如下:DogName(textblock)+DogKind(textblock)+Owners(combobox)。前两个是成功的,但我无法将现有所有者添加到组合框中。如果我给我的组合框起一个名字,例如:

<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 提供给组合框,或者我如何才能添加所有者?

4

2 回答 2

0

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

<ComboBox ItemsSource="{Binding Path=DataContext.MyItemsSource, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></ComboBox>
于 2013-04-02T16:39:03.557 回答
0

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

UI 不是数据。数据就是数据。用户界面就是用户界面。

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

在此示例中,Window使用 as 本身是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));
    }
}

结果:

在此处输入图像描述

关于此示例,您需要考虑 3 个重要方面:

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

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

于 2013-04-02T17:39:42.090 回答