简体   繁体   中英

How do you bind information to a DataGrid in an a WPF Application with multiple windows?

I am currently working on an application wherein information is searched for and then retrieved from an Excel document. The main window of the application is the window where the user searches for a particular item, and once the user presses the search button, another window appears displaying the results of that search on a DataGrid, however my DataGrid fails to display the results of the search on the DataGrid. As of now all of the logic used to search through and retrieve information happens in the code-behind of the main window search screen, and I've attempted to bind the information to the DataGrid like this.

public partial class MainWindow : Window, INotifyPropertyChanged
{
     //Initialized variables for Result and Add New Cable windows
     private AddWindow newCableWindow;
     private ResultsWindow searchResults = new ResultsWindow();


    //Creates a list to hold all CableLines in ExcelDocument
    private BindingList<CableLine> cableLines = new BindingList<CableLine>();

     public BindingList<CableLine> CableLines
     {
            get { return cableLines; }
            set
            {
                if (!cableLines.Equals(value))
                {
                    cableLines = value;
                    RaisePropertyChanged("CableLines");
                }
            }
     }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private void SearchButton_Click(object sender, RoutedEventArgs e)
    {

        SearchExcel(SearchType.CableSize);

        searchResults.Show();

    }
}

in the main window code-behind. However, this is not the windows that will display the information gathered when the Search Button is clicked. So, in the results class I tried this.

public partial class ResultsWindow : Window, INotifyPropertyChanged
{
    MainWindow searchWindow;
    AddWindow newCableWindow;

    private BindingList<CableLine> cableLines = new BindingList<CableLine>();

    public BindingList<CableLine> CableLines
    {
        get { return cableLines; }
        set
        {
            if (!cableLines.Equals(value))
            {
                CableLines = value;
                RaisePropertyChanged("CableLines");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

and in the XAML code for this ResultsWindow class, I have set up the DataGrid like this,

<DataGrid
                Grid.Row="0"
                Height="225"
                AutoGenerateColumns="False"
                HorizontalAlignment="Center"
                Background="LightGray"
                ItemsSource="{Binding CableLines}"
                >


                <DataGrid.Columns>
                    <DataGridTextColumn Header="Job #" Width="Auto" Binding="{Binding JobNo}"/>
                    <DataGridTextColumn Header="Page #" Width="Auto" Binding="{Binding PageNo}"/>
                    <DataGridTextColumn Header="Link To Job" Width="Auto" Binding="{Binding LinkToJob}"/>
                    <DataGridTextColumn Header="PCU Part #" Width="Auto" Binding="{Binding PCUPartNo}"/>
                    <DataGridTextColumn Header="Manufacturing Part #" Width="Auto" Binding="{Binding ManufactPartNo}"/>
                    <DataGridTextColumn Header="Manufacturer" Width="Auto" Binding="{Binding Manufacturer}"/>
                    <DataGridTextColumn Header="Cable Conductor Size" Width="Auto" Binding="{Binding CableConductorSize}"/>
                    <DataGridTextColumn Header="Description" Width="Auto" Binding="{Binding Description}"/>
                    <DataGridTextColumn Header="QTY" Width="Auto" Binding="{Binding QTY}"/>
                    <DataGridTextColumn Header="Group Number" Width="Auto" Binding="{Binding GroupNum}"/>
                </DataGrid.Columns>
            </DataGrid>

I have a feeling that the problem arises from the fact that the searching is done in the MainWindow code behind and thus the list that is the ItemSource for the DataGrid which is updated through the function inside the SearchButton_Click function and is not updated in the code behind for the Result Window, I'm just not sure how I should do that or the best way to approach that. This is really the first app I've ever really worked on and I'm new to the concept of WPF and using multiple windows in an application and I know it's a lot of information, so I appreciate any help I can get. Thanks in advance.

UPDATE: Items are added to the cable line via the SearchExcel function which is executed in the SearchButton_Click event handler. The function looks like this:

private void SearchExcel(SearchType searchType) {

        var searchedRows = new List<int>();

        //Switch statement making a decision based on how the user searched for the cable
        switch (searchType)
        {
            case SearchType.CableSize:
                int cableSizeColumn = GetColumnNum("Cable Conductor Size");

                //Checks that the correct column in the spreadsheet was found.
                if (cableSizeColumn == -1)
                {
                    throw new InvalidOperationException("The \"Cable Conductor Size\" could not be found.");
                }

                //variable to keep track of the last row that contained a value since only first cell in merged cells contains the value
                int lastGoodRow = 0;

                //Searches through every row in the column, getting the rows where the size number matches the search
                for (int i = HeaderRow + 1; i <= usedRows.Count(); i++)
                {
                    var currentCellValue = Convert.ToString(cableSheet.Cells[i, cableSizeColumn].Value2);
                    var desiredCellValue = Convert.ToString(CableSizeDropdown.Text);

                    if (String.Equals(desiredCellValue, currentCellValue))
                    {
                        lastGoodRow = i;
                        searchedRows.Add(i);
                    }
                    else if(currentCellValue == null && !IsRowEmpty(i))
                    {
                        searchedRows.Add(++lastGoodRow);
                    }
                }
                break;

                //TODO: Add switch statement for other kind of search
        }

        //Ensures that rows have been found that correspond correctly to the search
        if(searchedRows.Count == 0)
        {
            throw new InvalidOperationException($"The chosen cable size {CableSizeDropdown.Text.ToString()} could not be found.");
        }

        foreach (int row in searchedRows)
        {
            AddLine(row);
        }
    }

where the row numbers with the desired information are first saved (in the Excel sheet the rows with the same information in the column I'm searching are merged, which means that only the first cell actually contains the value that I'm searching for which is why I add the check for null and check that the row isn't empty, since if that particular row value is null, but the row itself isn't empty then that means that row also contains the value I'm looking for). Once I have the row numbers that have the value I'm looking for, I call the AddLine method for each row number, which is where things are actually added to the CableLines list.

       private void AddLine(int rowNum)
    {
        string pageNo = "";
        string jobNo = "";
        string linkToJob = "";
        string pcuPartNo = "";
        string manufactPartNo = "";
        string manufact = "";
        string description = "";
        int cableConductorSize = 0;
        int qty = 0;
        int groupNum = 0;

        //iterates through every cell in row number and gets the information from it
        for (int i = 1; i <= usedColumns.Count(); i++)
        {
            if (i == GetColumnNum("Job #"))
            {
                jobNo = (cableSheet.Cells[rowNum, i].Value2 != null) ? cableSheet.Cells[rowNum, i].Value2.ToString() : "";
                break;
            }
            else if (i == GetColumnNum("Page #"))
            {
                pageNo = (cableSheet.Cells[rowNum, i].Value2 != null) ? cableSheet.Cells[rowNum, i].Value2.ToString() : "";
                break;
            }
            else if (i == GetColumnNum("Link To Job"))
            {
                linkToJob = (cableSheet.Cells[rowNum, i].Value2 != null) ? cableSheet.Cells[rowNum, i].Value2.ToString() : "";
                break;
            }
            else if (i == GetColumnNum("PCU Part #"))
            {
                pcuPartNo = (cableSheet.Cells[rowNum, i].Value2 != null) ? cableSheet.Cells[rowNum, i].Value2.ToString() : "";
                break;
            }
            else if (i == GetColumnNum("Manufacturing Part #"))
            {
                manufactPartNo = (cableSheet.Cells[rowNum, i].Value2 != null) ? cableSheet.Cells[rowNum, i].Value2.ToString() : "";
                break;
            }
            else if (i == GetColumnNum("Manufacturer"))
            {
                manufact = (cableSheet.Cells[rowNum, i].Value2 != null) ? cableSheet.Cells[rowNum, i].Value2.ToString() : "";
                break;
            }
            else if (i == GetColumnNum("Cable Conductor Size"))
            {
                cableConductorSize = (cableSheet.Cells[rowNum, i].Value2 != null) ? cableSheet.Cells[rowNum, i].Value2.ToString() : "";
                break;
            }
            else if (i == GetColumnNum("Description"))
            {
                description = (cableSheet.Cells[rowNum, i].Value2 != null) ? cableSheet.Cells[rowNum, i].Value2.ToString() : "";
                break;
            }
            else if (i == GetColumnNum("QTY"))
            {
                qty = (cableSheet.Cells[rowNum, i].Value2 != null) ? Convert.ToInt32(cableSheet.Cells[rowNum, i].Value2) : 0;
                break;
            }
            else if (i == GetColumnNum("Group Number"))
            {
                groupNum = (cableSheet.Cells[rowNum, i].Value2 != null) ? Convert.ToInt32(cableSheet.Cells[rowNum, i].Value2) : 0;
                break;
            }
            else
            {
                throw new InvalidOperationException("An invalid column was recognized.");
            }
        }

        cableLines.Add(new CableLine(jobNo, pageNo, linkToJob, pcuPartNo, manufactPartNo, manufact, description, cableConductorSize, qty, groupNum));
    }

The thought here is that the function gets the row number and goes through every used cell in that row and adds information to a certain property of the CableLine class (which is just a class to represent a single line of information in the Excel sheet) and when that's done, it adds a new CableLine object to the CableLines list with the information that it has gathered from the row in the Excel sheet.

I managed to figure out a solution to the problem myself while working on the project. All I had to do was reference the DataGrid x:Name using the instance of the Results window and then set the DataGrid's ItemSource to the list of cable lines updated through the AddLine function. So after the for each loop in the SearchExcel function where the AddLine() method is called, I simply referenced searchResults.searchResults(in this case this is the x:Name I gave to my DataGrid).ItemSource = cableLines, and this worked fine for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM