从WPF中的ListBox中删除动态创建的按钮

时间:2013-09-02 07:38:09

标签: wpf button data-binding binding

我正在尝试使用 ListBox.Items.Remove 从列表框中删除动态创建的按钮,但我不断收到的错误“当ItemsSource所在时,操作无效使用。用ItemsControl.ItemsSource访问和修改元素。“问题是, ItemsControl.ItemsSource 在我的代码中不是一个有效选项。

代码有点破旧:我有一个包含ListBox和“添加”和“删除”按钮的MainWindow。添加按钮会将您发送到一个窗口,您可以在其中输入名字和姓氏。单击“完成”将新创建的配置文件的按钮添加到列表框(您可以通过单击所述按钮来访问配置文件)。除了将firstname和lastname绑定到那里的标签之外,我没有将Profile代码包含为空。

我如何访问/修改按钮/配置文件以删除它们?我知道这与数据绑定有关,但我对如何删除项目感到很困惑。

非常感谢任何帮助。我在下面包含了MainWindow和ProfileCreator代码。

<Window x:Class="SavingButtons.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">

<Window.Resources>
    <DataTemplate x:Key="UserTemplate">
        <StackPanel Orientation="Horizontal">
            <Button Name="TestAddButton" Click="TestAddButton_Clicked" Content="{Binding FirstName}" Width="100" Height="40"></Button> 
        </StackPanel>
    </DataTemplate>
</Window.Resources>

<Grid>
    <Button Name="AddProfileButton" Content="Add Profile" HorizontalAlignment="Left" Margin="22,29,0,0" VerticalAlignment="Top" Width="75" Click="AddProfileButton_Click"/>
    <ListBox Name="ButtonHoldersListbox" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}" ItemTemplate="{StaticResource UserTemplate}" HorizontalAlignment="Left" Height="202" Margin="22,69,0,0" VerticalAlignment="Top" Width="183" />
    <Button Name="DeleteUserButton" Click="DeleteUserButton_Click" Content="Delete User" HorizontalAlignment="Left" Margin="246,69,0,0" VerticalAlignment="Top" Width="105"/>
</Grid>

namespace SavingButtons
{
public partial class MainWindow : Window
{
    NewProfile np;
    public int buttonNumberID;
    public MainWindow()
    {
        InitializeComponent();
        np = new NewProfile(this);
    }

    private void AddProfileButton_Click(object sender, RoutedEventArgs e)
    {
        np.Show();
    }
    //adds button to listbox
    internal void TestAddButton_Clicked(object sender, RoutedEventArgs e)
    {
        Button cmd = (Button)sender;
        if (cmd.DataContext is User)
        {
            //Profile is where the finished information is displayed//
            Profile pro = new Profile();
            pro.DataContext = cmd.DataContext;
            pro.Show();
        }
    }
    //this is where confusion ensues
    private void DeleteUserButton_Click(object sender, RoutedEventArgs e)
    {
        //error occurs here
        ButtonHoldersListbox.Items.Remove(ButtonHoldersListbox.SelectedItem);

    }
}
}

个人资料创建者:

<Window x:Class="SavingButtons.NewProfile"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="NewProfile" Height="300" Width="500">
<Grid>
    <Label Content="FirstName" HorizontalAlignment="Left" Margin="64,44,0,0" VerticalAlignment="Top"/>
    <Label Content="LastName" HorizontalAlignment="Left" Margin="64,97,0,0" VerticalAlignment="Top"/>
    <Button Name="UploadImageButton" Click="UploadImageButton_Click" Content="Upload Image" HorizontalAlignment="Left" Margin="64,146,0,0" VerticalAlignment="Top" Width="75"/>

    <TextBox Name="FirstNameTextBox" HorizontalAlignment="Left" Height="23" Margin="126,47,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
    <TextBox Name="LastNameTextBox" HorizontalAlignment="Left" Height="23" Margin="126,99,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
    <Image Name="imgPhoto" HorizontalAlignment="Left" Height="100" Margin="173,146,0,0" VerticalAlignment="Top" Width="100"/>

    <Button Name="ProfileFinishedLaunch" Content="Done" HorizontalAlignment="Left" Margin="360,232,0,0" VerticalAlignment="Top" Width="75" Click="ProfileFinishedLaunch_Click"/>
</Grid>

 namespace SavingButtons
{
public partial class NewProfile : Window
{
    public ObservableCollection<User> ProfileList;
    public MainWindow mMain;

    public NewProfile(MainWindow main)
    {
        InitializeComponent();
        ProfileList = new ObservableCollection<User>();
        mMain = main;
    }

    //loads image
    private void UploadImageButton_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog op = new OpenFileDialog();
        op.Title = "Select a picture";
        op.Filter = "All supported graphics|*.jpg;*.jpeg;*.png|" +
            "JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|" +
            "Portable Network Graphic (*.png)|*.png";
        if (op.ShowDialog() == true)
        {
            imgPhoto.Source = new BitmapImage(new System.Uri(op.FileName));
        }
    }
    //creates a new user out of all the info, inserts new user into the collection, adds new button
    private void ProfileFinishedLaunch_Click(object sender, RoutedEventArgs e)
    {
        mMain.buttonNumberID++;
        ProfileList.Add(new User { FirstName = FirstNameTextBox.Text, LastName = LastNameTextBox.Text, imgPhoto = imgPhoto.Source });

        mMain.ButtonHoldersListbox.DataContext = ProfileList; 

        mMain.Show();
        this.Hide();
    }

3 个答案:

答案 0 :(得分:1)

You are setting your Listbox`到其他窗口属性,每次添加新项目后都会这样做。

发生错误,因为列表框项目是通过绑定到ItemsSource属性设置的,在这种情况下,ListBox.Items是只读的,因此您无法直接删除或添加项目。

而不是现在拥有的内容,将ObservableCollection<User>属性添加到MainWindow类,并将ListBox绑定到此属性。在NewProfile窗口中,您需要将新用户项添加到此集合中。删除操作将与从该集合中删除项目(实际上是发件人DataContext

一起使用
public partial class MainWindow : Window
{
    public ObservableCollection<User> Profiles {get; set;}

    //...

    private void DeleteUserButton_Click(object sender, RoutedEventArgs e)
    {
      var removable = ButtonHoldersListbox.SelectedItem as User;
      if(removable != null)
        Profiles.Remove(removable);
    }
}


<ListBox Name="ButtonHoldersListbox" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Profiles}" ItemTemplate="{StaticResource UserTemplate}" HorizontalAlignment="Left" Height="202" Margin="22,69,0,0" VerticalAlignment="Top" Width="183" />


public partial class NewProfile : Window
{

//creates a new user out of all the info, inserts new user into the collection, adds new button
private void ProfileFinishedLaunch_Click(object sender, RoutedEventArgs e)
{
    mMain.buttonNumberID++;
    var newUser = new User { FirstName = FirstNameTextBox.Text, LastName = LastNameTextBox.Text, imgPhoto = imgPhoto.Source };

    mMain.Profiles.Add(newUser); 

    //Don't set the listbox.DataContext here

    mMain.Show();
    this.Hide();
}

答案 1 :(得分:0)

如果将itemssource设置为usercontrol,则无法直接操作它的项目。编辑它的itemssource而不是。给你一个简单的例子。

 public partial class MainWindow : Window
{
    ObservableCollection<int> ProfileList;
    public MainWindow()
    {
        InitializeComponent();
        ProfileList = new ObservableCollection<int>();
        this.DataContext = ProfileList;
    }

    private void btnAdd_Click(object sender, RoutedEventArgs e)
    {
        Random r = new Random();
        int num = r.Next(100);
        ProfileList.Add(num);
        //lstShow.Items.Add(num);   error!
    }

    private void btnDel_Click(object sender, RoutedEventArgs e)
    {
        if (lstShow.SelectedIndex > -1)
        {
            ProfileList.Remove((int)lstShow.SelectedItem);
            //lstShow.Items.Remove((int)lstShow.SelectedItem);   error!
        }
    }
}

答案 2 :(得分:0)

感谢Miklos,我确实解决了我的问题,然而,绑定仍然令人困惑。主要是: ListBox如何知道绑定ObservableCollection ProfileList?在Mikalos版本中,他明确地将ObservableCollection绑定到XAML中的Listbox(注意:Mikalos observable集合命名为“Profile”)

ItemsSource="{Binding Profiles}"

这似乎是最明确的。相反,我唯一能够使它工作的方式就是这种方式(ProfileList是我用于可观察集合的名称):

ItemsSource="{Binding}" 

不确定它如何知道绑定到我的observableCollection。我将在下面包含我的工作代码。

<Window x:Class="SavingButtons.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">

<Window.Resources>
    <DataTemplate x:Key="UserTemplate">
        <StackPanel Orientation="Horizontal">
            <Button Name="TestButton" Click="cmdDeleteUser_Clicked" Content="{Binding FirstName}" Width="100" Height="40"></Button> 
        </StackPanel>
    </DataTemplate>
</Window.Resources>

<Grid>
    <Button Name="AddProfileButton" Content="Add Profile" HorizontalAlignment="Left" Margin="22,29,0,0" VerticalAlignment="Top" Width="75" Click="AddProfileButton_Click"/>
    <ListBox Name="ButtonHoldersListbox" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}" ItemTemplate="{StaticResource UserTemplate}" HorizontalAlignment="Left" Height="202" Margin="22,69,0,0" VerticalAlignment="Top" Width="183" />
    <Button Name="DeleteUserButton" Click="DeleteUserButton_Click" Content="Delete User" HorizontalAlignment="Left" Margin="246,69,0,0" VerticalAlignment="Top" Width="105"/>
</Grid>

我的ProfileCreator Cs:

public partial class NewProfile : Window
{
    public MainWindow mMain;
    public NewProfile(MainWindow main)
    {
        InitializeComponent();
        mMain = main;
    }

    //creates a new user out of all the info, inserts new user into the collection, adds new button
    private void ProfileFinishedLaunch_Click(object sender, RoutedEventArgs e)
    {
        ////Mikalos CODE-----------------------------------------------------------//
        var newUser = new User { FirstName = FirstNameTextBox.Text, LastName = LastNameTextBox.Text, imgPhoto = imgPhoto.Source };
        mMain.ProfileList.Add(newUser);

        mMain.ButtonHoldersListbox.DataContext = mMain.ProfileList;//Mikalo suggested not putting ListBox.DataContext here,
        //however, this is the only place it works. 

        mMain.Show();
        this.Hide();
        //---------------------------------------------------------------//   
    }