Search code examples
c#.netwpfxamllistbox

Dynamically adding items to WPF listbox


I'm trying to build an application that the user points to a folder of PDF files. of Invoices, the program then parses the PDF files to find out which ones contains an email address and which ones don't. and this Is Where I'm stuck:

I then want to add the file names to either the Listbox for print or the Listbox for email.

I got all the other bits working, choosing the folder and parsing the PDF and adding the folder path to a textbox object.

I then run a function:

private void listFiles(string selectedPath)
        {
            string[] fileEntries = Directory.GetFiles(selectedPath);
            foreach (string files in fileEntries)
            {
                
                try
                {
                    ITextExtractionStrategy its = new iTextSharp.text.pdf.parser.LocationTextExtractionStrategy();
                    using (PdfReader reader = new PdfReader(files))
                    {
                        string thePage = PdfTextExtractor.GetTextFromPage(reader, 1, its);
                        string[] theLines = thePage.Split('\n');
                        if (theLines[1].Contains("@"))
                        {
                           // System.Windows.MessageBox.Show("denne fil kan sendes som email til " + theLines[1], "Email!");
                           
                        }
                        else
                        {
                            System.Windows.MessageBox.Show("denne fil skal Printes da " + theLines[1] + " ikke er en email", "PRINT!");
                        }
                    }
                }
                catch (Exception exc)
                {
                    System.Windows.MessageBox.Show("FEJL!", exc.Message);
                }



            }
        }

And it is in this function I want to be able to add the files to either Listbox.

My XAML looks like this:

<Grid.Resources>
        <local:ListofPrint x:Key="listofprint"/>
</Grid.Resources>

<ListBox x:Name="lbxPrint" ItemsSource="{StaticResource listofprint}" HorizontalAlignment="Left" Height="140" Margin="24.231,111.757,0,0" VerticalAlignment="Top" Width="230"/>

But I get the error: The name "ListofPrint" does not exist in the namespace "clr-namespace:test_app".

the ListofPrint is here:

public class ListofPrint : ObservableCollection<PDFtoPrint>
    {
        public ListofPrint(string xfile)
        {
            Add(new PDFtoPrint(xfile));
        }
    }

I've been trying to get the hang of the documentation on MSDN and have read 10 different similar Questions on this site, but I guess my problem is that I don't know exactly what my problem is. first of it's a data binding problem but I basically copied the sample from the documentation to play with but that is what is giving me the trouble.

Hopefully, someone here can explain to me the basics of data binding and how it corresponds to my ObservableCollection.


Solution

  • You need to create an instance of your collection class and bind the ListBox to it. The most simple thing is setting its DataContext to this. I wrote an example:

    Window:

    public class MyWindow : Window
    {
        // must be a property! This is your instance...
        public YourCollection MyObjects {get; } = new YourCollection();
    
        public MyWindow()
        {
            // set datacontext to the window's instance.
            this.DataContext = this;
            InitializeComponent();
        }
    
        public void Button_Click(object sender, EventArgs e)
        {
            // add an object to your collection (instead of directly to the listbox)
            MyObjects.AddTitle("Hi There");
        }
    }
    

    Your notifyObject collection:

    public class YourCollection : ObservableCollection<MyObject>
    {
        // some wrapper functions for example:
        public void Add(string title)
        {  
           this.Add(new MyObject { Title = title });
        }
    }
    

    Item class:

    // by implementing the INotifyPropertyChanged, changes to properties
    // will update the listbox on-the-fly
    public class MyObject : INotifyPropertyChanged
    {
         private string _title;
    
         // a property.
         public string Title
         {
             get { return _title;}
             set
             {
                 if(_title!= value)
                 {
                     _title = value;
                     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs( nameof(Title)));
                 }
             }
         }
         public event PropertyChangedEventHandler PropertyChanged;
    }
    

    Xaml:

    <ListBox ItemsSource="{Binding MyObjects}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Title}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>