How to access ListBox dynamically-created-items

2019-05-23 23:49发布

问题:

XAML:

<Window x:Class="WpfApp_ListBoxTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
  <ListBox Name="lb" Margin="0,0,0,70"></ListBox>
  <Button Height="23" HorizontalAlignment="Left" Margin="12,0,0,41" Name="btnAdd" VerticalAlignment="Bottom" Content="Add item" Width="75" Click="btnAdd_Click"></Button>
  <TextBox Height="23" Margin="93,0,12,41" Name="txtInput" VerticalAlignment="Bottom" />
  <Button Height="23" HorizontalAlignment="Left" Margin="12,0,0,12" Name="btnGet" VerticalAlignment="Bottom" Content="Get value" Width="75" Click="btnGet_Click"></Button>
  <TextBox Height="23" Margin="93,0,12,12" Name="txtReturn" VerticalAlignment="Bottom" IsReadOnly="True" />
 </Grid>
</Window>

Csharp:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;

namespace WpfApp_ListBoxTest
{
 /// <summary>
 /// Interaction logic for Window1.xaml
 /// </summary>
 public partial class Window1 : Window
 {
  public Window1()
  {
   InitializeComponent();
  }

  private void btnAdd_Click(object sender, RoutedEventArgs e)
  {
   TextBox txt = new TextBox();
   txt.Width = 200;
   txt.Text = txtInput.Text;
   lb.Items.Add(txt);
  }

  private void btnGet_Click(object sender, RoutedEventArgs e)
  {
   // What do I need to write here to get the value of the Text property of the selected TextBox?

  }
 }
}

And screenshot: (Sorry I'm not allowed to post picture directly) http://i825.photobucket.com/albums/zz180/mGlushed/get_listbox_item_property.png

(In the picture above, I want to get the value "b" when I click the "Get value" button.)

I would like to know if there is a simple way to achieve this.

I'm new to WPF, so I only know to do this the long way, which is: Create an array. Everytime a new TextBox is created, add it into the array. Then access the TextBox'es through the array. But that doesn't sound very optimal, I think.

回答1:

The 'WPF Way' of doing what you want is to use data binding:

  1. Define a class with a string property called Text.
  2. Create a collection of that class.
  3. Bind your list box ItemsSource to the collection.
  4. Create a DataTemplate that shows a TextBox with its Text property bound using {Binding Path=Text}.
  5. In btnAdd_Click add an item to the collection (not directly to the ListBox)
  6. In btnGet_Click you can get the text entered by casting ListBox.SelectedItem to your class and getting its Text property.

Example:

The simple class:

public class VMObject
{
    public VMObject(string text)
    {
        Text = text;
    }

    public string Text { get; set; }
}

The window code-behind:

public partial class Window1 : Window
{
    public ObservableCollection<VMObject> VM { get; set; }

    public Window1()
    {
        VM = new ObservableCollection<VMObject>();
        InitializeComponent();
    }

    private void btnAdd_Click(object sender, RoutedEventArgs e)
    {
        VM.Add(new VMObject(txtInput.Text));
    }

    private void btnGet_Click(object sender, RoutedEventArgs e)
    {
        if (lb.SelectedItem == null)
            MessageBox.Show("No item is selected!");
        txtReturn.Text = ((VMObject)lb.SelectedItem).Text;
    }
}

The XAML:

<Window x:Class="lbtest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Name="Window"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <DataTemplate x:Key="TextBoxTemplate">
            <TextBox Text="{Binding Path=Text}"/>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox Name="lb" Margin="0,0,0,70"
                 ItemsSource="{Binding ElementName=Window, Path=VM}"
                 ItemTemplate="{StaticResource TextBoxTemplate}" />
        <Button Height="23" HorizontalAlignment="Left" Margin="12,0,0,41"
                Name="btnAdd" VerticalAlignment="Bottom"
                Content="Add item" Width="75" Click="btnAdd_Click" />
        <TextBox Height="23" Margin="93,0,12,41"
                 Name="txtInput" VerticalAlignment="Bottom" />
        <Button Height="23" HorizontalAlignment="Left" Margin="12,0,0,12"
                Name="btnGet" VerticalAlignment="Bottom"
                Content="Get value" Width="75" Click="btnGet_Click" />
        <TextBox Height="23" Margin="93,0,12,12"
                 Name="txtReturn" VerticalAlignment="Bottom" IsReadOnly="True" />
    </Grid>
</Window>


回答2:

for a checkbox item:

private void chk_Checked(object sender, RoutedEventArgs e)
{
    CheckBox chk = (CheckBox)sender;
    MessageBox.Show(chk.Content.ToString()); 
}


回答3:

No need for TextBox:s. ListBox handle strings fine.

    private void btnAdd_Click(object sender, RoutedEventArgs e)
    {
        // No need to create TextBox, ListBox handle strings fine.
        lb.Items.Add(txtInput.Text);
    }

    private void btnGet_Click(object sender, RoutedEventArgs e)
    {
        // No selection, but button has been pressed.
        if(lb.SelectedItem == -1)
            return;
        // Get selected item.
        txtReturn.Text = (string)lb.SelectedItem;

        /* If you change ListBox selection mode to multiple
         * you can get all selected items by using foreach loop.
        foreach (Object selected in lb.SelectedItems)
        {
            txtReturn.Text +=  (string) selected;
        }
         */
    }


回答4:

If you just want to get the Text property of the selected TextBox (admiting your ListBox is in single selection mode) it it quite simple:

private void btnGet_Click(object sender, RoutedEventArgs e)
{
    if(lb.SelectedItem != -1)
    {
        TextBox selectedTextBox = (TextBox)lb.SelectedItem;
        txtReturn.Text = selectedTextBox.Text;
    }
}

But if you want to implement the pretty WPF way, you should follow the Aviad P. solution, my solution do it well too.

Regards.


EDIT: If do not have a real need of TextBox functionalities, but only a string container, so follow Tuukka's solution.



标签: wpf listbox