【问题标题】:adding elements to combobox from a list从列表中将元素添加到组合框
【发布时间】:2013-04-03 01:45:34
【问题描述】:

我的问题: 我有一个带有狗主人的列表框,我有一个带有狗的列表框。我想修改狗列表框项模板如下: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 提供给组合框,或者如何添加所有者?

【问题讨论】:

  • 考虑使用转换器,不要使用 3 个文本框,仅使用 1 个,并使用格式化字符串更改唯一文本块的文本或使用转换器。

标签: c# xaml combobox itemssource


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    首先,为了使用 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));
        }
    }
    

    结果:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-24
      • 2020-05-22
      • 1970-01-01
      • 2021-07-23
      • 1970-01-01
      • 2018-07-29
      • 2014-06-16
      相关资源
      最近更新 更多