C# WPF refresh listbox from another window - c#

I'm making a WPF project based on an Access database.
The database has two tables:
tblMovies (MovieID: PK, Title, Director, Genre etc)
tblActors (ActorID: PK, MovieID: FK, Firstname, Lastname etc)
I have listbox where I can see all the movies, and if I click on one, it shows a new window with all the details about that movie: the title, director, genre, but also the actors.
In this window I have added a button to create a new actor. This opens a new window where you can enter the MovieID (FK) and the information about the actor.
When I click save changes, it works and the window closes, but my listboxActors needs to be manually refreshed (I have added a button for that) to see the new actor.
Is there a way to refresh my listboxActors after I click "save changes" in my other window?
I first did it by closing my first screen when clicking add new actor, and then if I saved it would reopen the screen, and it'd automatically be refreshed, but I don't want it that way.
My listboxActors:
listBoxActors.ItemsSource = mov.Actors;
Save button (in the other screen)
private void buttonSaveNewActor_Click(object sender, RoutedEventArgs e)
{
Actor act = new Actor();
act.MovieID = Convert.ToInt32(textBoxMovieID.Text);
act.FirstName = textBoxFirstName.Text;
act.LastName = textBoxLastName.Text;
act.Country = textBoxCountry.Text;
act.Born = Convert.ToDateTime(BornDate.SelectedDate);
act.Bio = textBoxBio.Text;
ActorRepository.AddActor(act);
MessageBox.Show("The actor: " + act.FirstName + " " + act.LastName + " has been created");
this.Hide();
}
The refresh button:
private void buttonRefresh_Click(object sender, RoutedEventArgs e)
{
listBoxActors.ItemsSource = null;
listBoxActors.ItemsSource = mov.Actors;
}
Thanks in advance!

Well, Thanks for the explanatory comment...! I have a suggestion for you, please let me know if this helps you to code your scenario:
So you have two forms WindowShowDetails Let it be the main-form and WindowAddActor be the child, the Their will be a button in the main form which opens the child form, and you are doing some tasks in the child and press the Save button, which will save those details and closes that form. And you wanted to refresh the List in the main form associated with this event. For this you can use delegates and events;For this you have to do a number of tasks, in the main-form as well as in the child, Let me show you how it can help you:
Define a delegate in the main form:
public delegate void RefreshList();
Define an event of that delegate type
public event RefreshList RefreshListEvent;
Define a method that will do the action(ie, Refreshing the grid)
private void RefreshListView()
{
// Code to refresh the grid
}
Now need to define a Delegate in the WindowAddActor
Public Delegate UpdateActor;
Now we have to code the button click that opens the WindowAddActor form Let the button be btnAddActor so its Click event will be btnAddActor_click, we have to initialize our delegate-event, the instance of the WindowAddActor and assign the event to Delegate in the WindowAddActor before showing that form. this can be coded as :
private void btnAddActor_click(object sender, EventArgs e)
{
WindowAddActor actorInstance = new WindowAddActor();
RefreshListEvent += new RefreshList(RefreshListView); // event initialization
actorInstance.UpdateActor = RefreshListEvent; // assigning event to the Delegate
actorInstance.Show();
}
Now we have to call the delegate from the SaveButton's click event that is
private void buttonSaveNewActor_Click(object sender, RoutedEventArgs e)
{
// Perform save operation
UpdateActor.DynamicInvoke(); this will call the `RefreshListView` method of mainWindow
this.Close();
}

Related

Why can I not call a form object in two events?

I'm making like a add contact form with two buttons, ADD CONTACT and EDIT CONTACT. When a user clicks add contact, it pops up another form where the user can add contact information.
I want to give them the option to edit that info by clicking the EDIT CONTACT button which should pop up the SAME form.
However its not letting me call the object of the form twice, saying that I cannot press the edit button after the add button.
How do I call a form object twice?
//instatiating an object of the form
FormContact contactForm = new FormContact();
public FormManager()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, EventArgs e)
{
//displaying it when the user clicks add button
contactForm.Show();
}
private void btnEdit_Click(object sender, EventArgs e)
{
//trying to display it again but gives this exception
///System.ObjectDisposedException: 'Cannot access a disposed
///object.
///Object name: 'FormContact'.'
contactForm.Show();
}
Error:
///System.ObjectDisposedException: 'Cannot access a disposed
///object.
///Object name: 'FormContact'.'
The problem is you're closing the form after you've shown it.
You click the Show button
Your only instance of the form is shown
You close it with the X in the top corner
The runtime destroys the form (disposes it) after it is closed
You try to show it again but this this it's gone, trashed, doesn't exist any more, waiting to be garbage collected
Either make a new form each time you open it (to reduce code clutter, assign this same event handler to both button clicks, or copy paste it out twice if you want them to be coded differently eventually):
private void btnAddOrEdit_Click(object sender, EventArgs e)
{
new FormContact().Show();
}
Or intercept the FormClosing event of the FormContact form and cancel the closing, and perform a Hide() instead so that instead of being destroyed your form is made invisible. It will then still exist and can be Show()n the next time. To handle the event, open the FormContact designer, click anywhere in the form background, click lightning bolt in properties grid, double click the FormClosing entry:
private void FormClosing(object sender, FormClosingEventArgs e){
e.Cancel = true;
this.Hide();
}
Which method you choose depends how you want your program to behave:
If you make a new form each time, and you Show instead of ShowDialog your user could click Add twice and see two forms. Then could click Add 10 times and see 10 forms. Using ShowDialog means that the main window won't accept any more clicks until the FormContact is closed. You might or might not want this either
If you Hide (not close; hiding is different from closing) and Show the same form rather than making a new one then the user can click Add 10 times but they still only see one form
FormContact contactForm = new FormContact(); is a Member variable, it's scope is Private and is visible to the entire class.
After you first Show the form:
contactForm.Show();
The form is already showing. Therefore if you call Show again, it won't do anything as the instance of the form/class is already showing.
If you want to show two instances of the form, you will need to instantiate two instances eg:
private void btnAdd_Click(object sender, EventArgs e)
{
FormContact contactForm = new FormContact();
contactForm.Show();
}
private void btnEdit_Click(object sender, EventArgs e)
{
FormContact contactForm = new FormContact();
contactForm.Show();
}
Or make two instances of it:
FormContact contactForm1 = new FormContact();
FormContact contactForm2 = new FormContact();
private void btnAdd_Click(object sender, EventArgs e)
{
contactForm1.Show();
}
private void btnEdit_Click(object sender, EventArgs e)
{
contactForm2.Show();
}
Or add a argument in the parameter of the Constructor to indicate Add or Edit, eg:
public class FormContact
{
public FormContact(int id)
{
if (id > 0)
{
//Load contact for Editing
}
else
{
//Clear all fields for Adding
foreach(var ctrl in this.Controls)
{
if (ctrl Is TextBoxBase) ctrl.Text = string.Empty
//TODO other controls types... if (ctrl Is ....
}
}
}
}
Then you can call it passing a contactID to edit or 0 to add:
FormContact contactForm = new FormContact(contactID);
contactForm.Show();
I've got another answer, in both methods simply show your form modally:
contactForm.ShowModal();

how to retrieve text of buttons clicked in windows form with one single method

I have a windows form application with multiple buttons. I need to retrieve the text property of any button clicked in order to create a query to the database. the only way I know is to create a button click event and cast the sender as button then do a switch case for each button Id which seems very hectic since I probably will have more than 100 buttons in the entire application. So my question is there a generic key press method I can create which can retrieve the text property of any button pressed/clicked on the form? Please excuse me if the question is not very clear. Any help will be appreciate
Use a single click event handler for all similar kind of buttons. This way there will be click event subscribed for every button but only one method which will be executed for all buttons. You can determine which button was pressed as follows.
Using sender object as follows;
private void button_Click(object sender, EventArgs e)
{
var buttonText = ((Button)sender).Text;
//Query using buttonText
}
Update:
Above answer will still require you to subscribe click event for each button. If you don't want that then have a look at following approach;
You could use (ClickTransparentButton or) disable (Enabled=false) all these buttons and add click event on parent Form. Once you get click event you can get button which was clicked as follows;
private void Form1_Click(object sender, EventArgs e)
{
var p = PointToClient(Cursor.Position);
var control = GetChildAtPoint(p);
if(control is Button)
{
var buttonText = ((Button)control).Text;
//Query using buttonText
}
}
But this has few disadvantages such as, you will not be able to operate these buttons using keyboard.
and more...
Create some function as buttons click handler:
private void buttonClickHandler(object sender, EventArgs e)
{
string buttonName = (sender as Button).Text;
}
2A. Connect Click event of every button to this handler.
2B. To automate connection of button click handler use something like that:
private void connectButtonsHandlers()
{
foreach(var c in this.Controls)
{
if(c is Button)
{
(c as Button).Click += buttonClickHandler;
}
}
}
Add this code to form constructor to perform connection at program start.

Having problems with TabControls

I am trying to change a tabpage name on a parent form to what a user types in a textbox on a child form when a strip menu button is clicked. I have everything working in that I can pull the correct information between both forms but every time it goes to get the currently selected tabpage it always returns "0".
Function to set new tabpage name on Forum1 (The message boxes are from trying to debug)
public void setNewTabName(string TextBoxText)
{
MessageBox.Show("Called");
MessageBox.Show(TextBoxText);
int CurrentSelectedTab = tabControl1.SelectedIndex;
MessageBox.Show(CurrentSelectedTab.ToString());
tabControl1.TabPages[CurrentSelectedTab].Text = TextBoxText;
}
Function (Form2) for getting the textbox info and passing it to Form1
private void button1_Click(object sender, EventArgs e)
{
BT frm1 = new BT();
frm1.setNewTabName(getTextBoxInfo());
}
public string getTextBoxInfo()
{
return textBox1.Text;
}
Any help would be greatly appreciated. I think I posted all the relevant code but if you need anything else I can post the whole thing. The only thing that is really left out is that it creates a new tabpage on a button click.
Edit: The same method works fine when it is taken out of the child GUI.
I think that the problem is that you create a new form (class BT) each time the button is clicked. I suggest you to move the form creation from button click event to parent form load function.

Windows Forms - get Text value from object of type button

I have a Windows form named Form1 and panel within this form named panel1. I use the panel only to place buttons there so that I can group them and work with them separately from the other buttons in my Form1. For the purpose of my program I need to handle every button click made from the buttons inside panel1. For this purpose I use the same code snippet:
public Form1()
{
InitializeComponent();
// Set a click event handler for the button in the panel
foreach (var button in panel1.Controls.OfType<Button>())
{
button.Click += HandleClick;
}
}
What I need to do is to have a way to identify which button exactly has been clicked. For this purpose I played a little bit with my handler method:
private void HandleClick(object o, EventArgs e)
{
MessageBox.Show("HI" + o.ToString());
}
which gave me some hope because I get this:
It's the second part - Text: button4 which is actually enough information to continue with my work. But I can't find a way to get this piece of information without some complicated string manipulations. So is there a way to get this or other unique information about the button been clicked given the way I have written my code?
private void HandleClick(object sender, EventArgs e)
{
var btn = sender as Button;
if (btn != null)
{
MessageBox.Show(btn.Text);
}
}
One option is to cast the object to a Button, but rather than doing the casting you can change how the event handler is assigned so that you don't need to cast in the first place:
foreach (var button in panel1.Controls.OfType<Button>())
{
button.Click += (_,args)=> HandleClick(button, args);
}
Then just change the signature of HandleClick to:
private void HandleClick(Button button, EventArgs e);
You need to cast sender to the Button class so you can access its properties:
Button b = (Button)sender;
MessageBox.Show(b.Text);

Re-bind datagrid when window is closed

I have a data grid that displays data from a sql server. I have an add button, that when clicked it opens a new window where the user can put the information for the new item that is being added. When the user clicks save, the data is being saved to the database, but its not showing up the in the grid. Is there a way that I can make the datagrid bind when the add window is closed? Let me know if more info is needed. Thanks.
In my main window, that contains the datagrid code, i have an add button:
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
showAddWindow();
}
And, the showAddWindow method is:
private void showAddWindow()
{
add addWindow = new add(dgDataView);
addWindow.Owner = this;
addWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
addWindow.ShowDialog();
}
If you know the Id of new inserted object, then you can send it to the main form, and call Add.Row on the grid with the new info. This way you'll not make a callback to the database for rebinding.
Assuming this is WinForms:
First, when calling the "Add" window, use ShowDialog() instead of Show()
In the main form with the DataGrid the code would look like
private void btnAdd_Click(Object sender, EventArgs e)
{
DialogResult b = frmAdd.ShowDialog();
if(b == DialogResult.Ok)
{
// code to re-bind the grid here.
}
}
in the frmAdd form, you will need to make your Save button set the DialogResult for the form to be DialogResult.Ok after updating the database.
I'm guessing that what you have tried is along the lines of:
private void btnAdd_Click(Object sender, EventArgs e)
{
frmAdd.ShowDialog();
// code to re-bind the grid here.
}
The difference is that with the ShowDialog() call, the main form will wait until the "add" form is closed to continue executing. In my second code sample, just using Show(), the code to re-bind the grid happens immediately after showing the "Add" form, before the user gets a chance to update the data.
(note, I did that code off the top of my head, not in Visual Studio, so it may have mistakes)

Categories

Resources