【问题标题】:Deleting dynamically created button from ListBox in WPF从 WPF 中的 ListBox 中删除动态创建的按钮
【发布时间】:2013-09-05 05:59:24
【问题描述】:

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

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

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

任何帮助将不胜感激。我在下面包含了 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();
    }

【问题讨论】:

    标签: wpf button data-binding binding


    【解决方案1】:

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

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

    ObservableCollection&lt;User&gt; 属性添加到您的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();
    }
    

    【讨论】:

    • 感谢 miklos,在您的代码的帮助下,我得到了它的帮助。我按照您的建议在 mainWindow 中实现了 observable 集合(将其重命名为“ProfileList”),并实现了 deleteUserButton 的代码,但在那之后,您的建议都没有奏效。
    • --在 MainWindow XAML 中,我尝试绑定 ItemsSource="{Binding ProfileList} (就像您建议的那样)。我尝试了多种不同的尝试以使其按照您的建议方式工作,但是它工作的唯一方法是 ItemsSource="{Binding}。你的方式是有道理的,它是明确的。我不知道为什么它不能按照你的方式工作。
    • -- 在您的代码中,您评论了“不要在此处设置 listbox.DataContext”。我尝试将 listbox.DataContext 放在 InitializeComponent() 和其他几个地方,但它只在 ProfileFinishedLaunch_Click 内有效。我不确定您最初为什么建议将 listbox.datacontext 放在其他地方。
    • 您应该在 InitializeComponent() 之后的 MainWindow 构造函数中将 ListBox.DataContext 设置为 Profiles,然后从 ProfileFinishedLaunch_click 方法中删除该设置。
    【解决方案2】:

    如果你将 itemsource 设置为 usercontrol 你不能直接操作它的项目。改为编辑它的 itemsource。举个简单的例子。

     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!
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      感谢 Miklos,我确实解决了我的问题,但是,绑定仍然很混乱。主要是:ListBox是如何知道绑定ObservableCollection ProfileList的?在Mikalos版本中,他显式地将ObservableCollection绑定到XAML中的Listbox(注意:Mikalos observable collection被命名为“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();
              //---------------------------------------------------------------//   
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-16
        • 1970-01-01
        • 1970-01-01
        • 2019-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多