ObservableCollection CollectionChanged event seems not to be firing – why? - c#

What’s wrong with this code? Clicking button1 doesn’t cause the messageBox to appear.
public partial class Form1 : Form
{
public ObservableCollection<string> aCollection2 = new ObservableCollection<string>();
myClass mc = new myClass();
public Form1()
{
InitializeComponent();
aCollection2.Add("a");
aCollection2.Add("b");
}
private void button1_Click(object sender, EventArgs e)
{
mc.myCollection = aCollection2;
}
private void button2_Click(object sender, EventArgs e)
{
mc.myCollection.Clear();
}
}
With myClass defined:
class myClass
{
public ObservableCollection<string> myCollection = new ObservableCollection<string>();
public myClass()
{
myCollection.CollectionChanged += Changed;
}
void Changed(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
MessageBox.Show(myCollection.Count.ToString());
}
}
EDIT:
When I add a 3rd button with:
private void button3_Click(object sender, EventArgs e)
{
mc.myCollection.Add("a");
}
It does show the messageBox. And so does button2. But after clicking button1 – none will fire anymore. How come?

You added an event handler to the original ObservableCollection instance from your field initializer.
You never added an event handler to the new ObservableCollection instance from the form.
Since the original ObservableCollection never changes, your handler never runs.
This is one of the many reasons why collection properties should be read only (and they should be properties, not fields)

Related

Trigger event programmatically and pass value to second page?

I want to pass a value from Mainpage to Page2. When I click Button_Click the variable “t” is passed to Page2.
However I need to trigger the Button_Click event from code, but then a “NullReferenceException” is thrown.
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Button_Click(new object(), new RoutedEventArgs());
}
public void Button_Click(object sender, RoutedEventArgs e)
{
string t = "Test";
navigate_page2(t);
}
public void navigate_page2(string t)
{
this.Frame.Navigate(typeof(Page2), t);
}
}
Button_Click(new object(), new RoutedEventArgs()); triggers the Button_Click event to do stuff, except when "navigate_page2" is called.
What is the difference between directly clicking and triggering the Button from code? I guess it is the "new RoutedEventArgs" somehow, but I don't know how to handle that... Thank you for any response!
Please do not call Button_Click directly, this method is associated with events in XAML.
If you want to re-use the code in the Button_Click event, you can pack it as a method to call.
Update
but then a “NullReferenceException” is thrown.
The problem is in this.Frame. for your current page, this.Frame does not exist. You need to create a sub-frame in xaml.
<Grid>
<Frame x:Name="MainFrame"/>
</Grid>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
btn_handle();
}
public void Button_Click(object sender, RoutedEventArgs e)
{
btn_handle();
}
public void btn_handle()
{
string t = "Test";
navigate_page2(t);
}
public void navigate_page2(string t)
{
MainFrame.Navigate(typeof(Page2), t);
}
}
Best regards.
As I can understand you are trying to pass a value from one page to another let take example for two forms that you need to pass one value from a form to another with a trigger of any click of button.
Form2
public partial class Form2 : Form
{
public event EventHandler TextEvent;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.Hide();
if (TextEvent != null)
{
TextEvent(label1.Text, null);
}
}
}
Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 obj = new Form2();
obj.Show();
obj.TextEvent += obj_TextEvent;
}
void obj_TextEvent(object sender, EventArgs e)
{
label1.Text = sender.ToString();
}
}
Here what I am doing is I have made an event in Form2 which triggers at clicking Button1 of Form2 and the data is pass as a sender to Form1 where Form2 obj has initiated the event and set label1 of Form1 as label1.Text = sender.ToString();

Access listbox from another class?

I made a class so when the user selects item from listbox it uninstalls that item, except the problem is I can't access the list box. I tried public aswell, but in the code of form1.cs the only thing clostest to that list box is
keep in mind name of listbox is ProgramslistBox
Ok guys I re edited this post;
private void button1_Click(object sender, EventArgs e)
{
if(ProgramsListbox.SelectedIndex == -1)
{
MessageBox.Show("Please select an item to uninstall!");
}
else
{
ProgramsListbox_SelectedIndexChanged("",EventArgs.Empty);
}
}
this code is the FORM1.CS class, and I have another class called UninstallItem.cs is where I want my code to be, this below is my other class
namespace PC_TECH_Registery_Cleaner
{
class UninstallItem
{
public void uninstallSelectedItem()
{
Form1 c = new Form1();
}
}
}
And this below is still in my FORM1.CS class, I was experimenting with it :
public void ProgramsListbox_SelectedIndexChanged(object sender, EventArgs e)
{
//this will access the Uninstall item class so we can uninstall selected item.
UninstallItem c = new UninstallItem();
c.uninstallSelectedItem();
}
Within your Form1.cs create instance of UnIstallItem class and use it. Then on Button Click call "RemoveSelected" method of UnInstaItem class by passing programsListBox to it and it should remove the selected item.
public class Form1:Form
{
ListBox ProgramsListbox;
UninstallItem unistall;
public Form1(){
InitializeComponent();
uninstall = new UninstallItem();
button1.Click+= button1_Click;
}
void button1_Click(object sender, EventArgs e){
unistall.RemoveSelected(ProgramsListbox);
}
}
Then in your external class;
public class UninstallItem{
public UninstallItem{}
public void RemoveSelected(ListBox list)
{
if(list.SelectedIndex==-1)
{
MessageBox.Show("Please Select Item from List");
return;
}
list.Items.RemoveAt(list.SelectedIndex);
}
}
The 2 easy ways to think about this are either
Call the method in your class from the event handler in your form
Have a method on your class which matches the signature of an event handler, and subscribe to the event.
The first requires no major change
private MyClass myClass = new MyClass();
public void ProgramsListbox_SelectedIndexChanged(object sender, EventArgs e)
{
myClass.DoSomething();
}
The second requires your class to have a specific method that matches the signature of that event handler currently in your form
public class MyClass
{
public void DoSomething(object sender, EventArgs e)
{
var listBox = (ListBox)sender;
// read selected index perhaps, or selected item maybe
}
}
And then in your form
private MyClass myClass = new MyClass();
protected override void OnLoad(EventArgs e)
{
this.ProgramsListBox.SelectedIndexChanged += myClass.DoSomething;
}

Passing BindingList<CustomObject> to button_Click method on second form

I have to forms.
First has datagridview with BindingList<CustomObject> as DataSource.
Second should add/remove/update DataSource from the first form.
How can I do this? Modifying etc is happening in button_Click(object sender, EventArgs e) on secondform. I could pass BindignList<> by ref to SecondForms() constructor, but I can't pass it further to button_Click()
What you can do is create an event in form2 that form1 will subscribe to. Keeping things sort of separate.
I don't know how you have structured Form1 and Form2 so I will just give an example.
class Form2 : Something
{
public event NotifySubscriberEventHandler NotifySubscriberEvent ;
public void button_Click(object sender, EventArgs e)
{
var handler = NotifySubscriberEvent ;
if( handler != null)
{
handler(this,EventArgs.Empty) ;
}
}
}
class Form1
{
public BindingList<T> MyBindingList {get;set;} //
public void CreateForm2()
{
Form2 form2 = new Form2() ;
form2.NotifySubscriberEvent += OnButtonClicked;
}
public void OnButtonClicked(object source, EventArgs e)
{
//Do Something when notified
MyBindingList.Add(...)
}
}
You will have to create a NotifySubsubscriberEventHandler delegate.
Here:
http://www.akadia.com/services/dotnet_delegates_and_events.html#Simple%20Event
But you already say you are passing BindingList into a constructor I assume like this:
public class Form2
{
private BindingList<T> bindingList ;
public Form2(BindingList<T> bindingList)
{
this.bindingList = bindingList ;
}
public void button_Click(object sender, EventArgs e)
{
// Do bindingList.Add() or whatever
}
}
Does the above not work? ^^

How do you associate click events of buttons created in code in C# with methods?

I'm building a Windows Phone app and I can't make a dynamically created Button associate with its event handler.
The code I'm using is:
public partial class MainPage : PhoneApplicationPage
{
Button AddButton
public MainPage()
{
CreateInterestEntry();
}
private void CreateInterestEntry()
{
EntrySegment = getEntrySegment();
ContentPanel.Children.Add(EntrySegment);
}
private void AddButton_Click(Object sender, RoutedEventArgs e)
{
//Stuff to do when button is clicked
}
private Grid getEntrySegment()
{
Grid EntrySegment = new Grid();
//Creating the grid goes here
AddButton = new Button();
AddButton.Content = "Add";
AddButton.Click += new EventHandler(AddButton_Click);
return EntrySegment;
}
}
}
With this code it complains that no overload for AddButton_Click matches delegate "System.EventHandler".
It's virtually identical to the code under Examples here at msdn, with the exception I've changed the argument type in AddButton_Click from EventArgs to RoutedEventArgs as otherwise Visual Studio tells me that it cannot implicitly convert from System.EventHandler to System.RoutedEventHandler.
Thanks in advance
Try this:
AddButton.Click += new RoutedEventHandler(AddButton_Click);
And the Click Event Handler:
void AddButton_Click(object sender, RoutedEventArgs e)
{
}

Problem controlling the flow of an application

I have a Windows Forms application that I'm working on, but I'm having trouble when I start the application. The application should load saved information from a config file, and then check for new items. When I start the application, it starts looking for new items before it has finished loading saved items. Because of this the user is alerted of new items that are not really new, they just have not been loaded from the file yet.
The Form:
public class MainForm : Form
{
A a;
public MainForm()
{
InitializeComponent();
a = new A();
a.ItemsFound += new A.NewItemsFoundEventHandler(a_FoundItems);
a.ItemsLoaded += new A.ItemsLoadedEventHandler(a_ItemsLoaded);
a.LoadItems();
}
public void a_FoundItems(object sender, EventArgs e)
{
//Alert user of new items.
}
public void a_ItemsLoaded(object sender, EventArgs e)
{
//Update GUI with items loaded from file.
this.UpdateTheGUI_ThisIsNotARealMethodInMyProgram();
//Then look for new items.
a.CheckForUpdates();
}
}
The other object:
public class A
{
public A(){}
public void LoadItems()
{
//Load Items from save file...
OnItemsLoaded(this);
}
public void CheckForUpdates()
{
//Check for new items...
//If new items are found, raise ItemsFound event
OnNewItemsFound(this,new EventArgs());
}
public delegate void NewItemsFoundEventHandler(object sender, EventArgs e);
public event NewItemsFoundEventHandler ItemsFound;
protected void OnNewItemsFound(object sender, EventArgs e)
{
if(ItemsFound != null)
{
ItemsFound(sender,e);
}
}
public delegate void ItemsLoadedEventHandler(object sender, EventArgs e);
public event ItemsLoadedEventHandler ItemsLoaded;
protected void OnItemsLoaded(object sender)
{
if(ItemsLoaded != null)
{
ItemsLoaded(sender,new System.EventArgs());
}
}
}
Should I have object A call it's functions on a new thread, and lock so CheckForUpdates cannot be called if LoadItems is running, or is there a simpler way to do this that I'm missing?
EDIT:
I found the problem. I was clearing the List of items (so it would not grow forever), but I was only filling it with the newly found items. So every time I ran the application only the newest items where in the list, and all the older items were flushed out.
STUPID!!!
Thanks for the help though, and sorry for the crappy question.
Is there any reason why the check is not in the constructor?
public MainForm()
{
InitializeComponent();
a = new A();
a.ItemsFound += new A.NewItemsFoundEventHandler(a_FoundItems);
a.ItemsLoaded += new A.ItemsLoadedEventHandler(a_ItemsLoaded);
a.LoadItems();
a.CheckForUpdates();
}
Hmm, from the code you've posted i dont see a problem, especially assuming all this runs on the ui thread.. can you post the code for the loading of items?
Perhaps the loading it self is firing the ItemsFound event? You could do the subscription for ItemsFound in the eventhandler for ItemsLoaded instead of in the constructor.
public class MainForm : Form
{
A a;
public MainForm()
{
InitializeComponent();
a = new A();
a.ItemsLoaded += new A.ItemsLoadedEventHandler(a_ItemsLoaded);
a.LoadItems();
}
public void a_ItemsLoaded(object sender, EventArgs e)
{
a.ItemsFound += new A.NewItemsFoundEventHandler(a_FoundItems);
a.CheckForUpdates();
}
}

Categories

Resources