I have a class that derives from ContextMenuStrip. This class has standard buttons and is used throughout the project:
public class ItemMenu : ContextMenuStrip
{
public ItemMenu (IContainer container)
: base(container)
{
MenuItemAdd = new ToolStripMenuItem("Add", null, AddNew);
this.Items.AddRange(new ToolStripItem[]
{
mnuAdd,
});
}
public void AddNew(object sender, EventArgs e)
{
//Code to add new item here...
}
}
And in the form:
cmsMenu = new ItemMenu(this.components);
Now I have a particular situation where I want that the form itself handles the code for adding an item.
How can I change the above class so that in default cases the class itself handles the actions, but in particular situations, other methods (events/delegates?) are used?
The following changes were required to get it to work:
public class ItemMenu : ContextMenuStrip
{
public event EventHandler AddNewItem;
public ItemMenu (IContainer container)
: base(container)
{
MenuItemAdd = new ToolStripMenuItem("Add", null, AddNew);
this.Items.AddRange(new ToolStripItem[]
{
mnuAdd,
});
}
public void AddNew(object sender, EventArgs e)
{
EventHandler handler = AddNewItem;
if (handler != null)
{
handler(sender, e);
}
else
{
OnAddNew(sender, e);
}
}
protected void OnAddNew(object sender, EventArgs e)
{
//Code to add new item here...
}
}
Related
I need some help. I am new to Events and handlers and I would like to begin using events for decoupling purposes but I am confused.
I have a class where I have a list view that is populated on OnAppearing. However to prevent onAppearing to happen each time the page is clicked I load the list once and then I would like to have items to get added or deleted to the list upon being added or removed from the server through the use of events.
The ListView page is a list of my favorite newspaper article Links. When clicking on any one of these links I get redirected to a LinksDetailsPage where I pass in the selected link and then display any details associated with the link.
Anyways...
I would like to add or remove an item on the my Favorites list seamlessly. So when I click on the AddItem or RemoveItem in the LinksDetailsPage I would like the item to either remove or add to theFavoritesPage List. Before I was only relying on the OnAppearing to work its magic and update the favorites list but it would lag to remove the item from the list, so this way I hope it would remove or add as soon as the even is invoked and not when the page loads on OnAppearing. However I think I am either not invoking the event properly or my subscriber is not subscribed properly. Events and delegates have been confusing for me from the get go. On top of that my favorites list is grouped so and it's my first time working with grouped lists as well.
Check out my code:
Subscriber
My Favorites Page:
public FavoritesPage()
{
InitializeComponent();
}
protected override async void OnAppearing()
{
if (_isDataLoaded)
return;
_isDataLoaded = true;
base.OnAppearing();
await LoadFavorites();
}
private async Task LoadFavorites()
{
groups = new ObservableCollection<LinksTypeGroup<string, NewspaperLink>>();
var links = await _db.GetAllFavorites();
var linkType = await _manager.GetLinkCategories();
foreach(var type in linkType)
{
var typegroup = links.FindAll(
delegate(NewspaperLink link)
{
return link.iLinkTypeID == type.iLinkTypeID;
});
groups.Add(new LinksTypeGroup<string, NewspaperLink>(type.Title, typegroup));
MyList.GroupDisplayBinding = new Binding("GroupKey");
MyList.ItemsSource = groups;
}
}
public void Listener(FavoritesPage P)
{
P.LinkAdded += Item_Added;
P.LinkDeleted += Item_Deleted;
}
void Item_Deleted(object sender, int e)
{
Console.WriteLine("Item_Deleted");
// remove item from groups ..see code above
}
void Item_Added(object sender, int e)
{
Console.WriteLine("Item_Added");
// add to groups ..see code above
}
I am not accessing anything so far.
Publisher
LinksDetailsPage:
private NewspaperLink _link;
public event EventHandler< NewspaperLink> ItemAdded;
public event EventHandler< NewspaperLink> ItemDeleted;
public LinksDetailsPage(NewspaperLink link)
{
_link = link;
BindingContext = _link;
InitializeComponent();
}
protected override async void OnAppearing()
{
base.OnAppearing();
await LoadLink();
}
private async Task LoadLink()
{
var url = await db.ReturnRecipeLink(_link.iLinkID);
linkWebView.Source = url;
CheckifExists(_link);
}
}
void AddLink(object sender, System.EventArgs e)
{
var link = BindingContext as NewspaperLink;
db.InsertIntoMyList(_link);
ItemAdded?.Invoke(this, link);
}
void DeleteLink(object sender, System.EventArgs e)
{
var link = BindingContext as NewspaperLink;
db.DeleteFromMyList(_link);
ItemDeleted?.Invoke(this, link);
}
Can someone guide me on how to make this even process work?
Event
If want to use Events, LinksDetailsPage should be declared something like following:
public partial class LinksDetailsPage : ContentPage
{
public event EventHandler<NewspaperLink> ItemAdded;
public event EventHandler<NewspaperLink> ItemDeleted;
public LinksDetailsPage()
{
InitializeComponent();
}
protected virtual void AddLink(NewspaperLink e)
{
EventHandler<NewspaperLink> handler = ItemAdded;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void DeleteLink( NewspaperLink e)
{
EventHandler<NewspaperLink> handler = ItemDeleted;
if (handler != null)
{
handler(this, e);
}
}
// Add click event
private void Add_Clicked(object sender, EventArgs e)
{
AddLink(new NewspaperLink() {link="first link" });
}
// Delete click event
private void Delete_Clicked(object sender, EventArgs e)
{
DeleteLink(new NewspaperLink() { link = "first link" });
}
}
public class NewspaperLink : EventArgs
{
public string link { get; set; }
}
Then you need to subscribe it in the ListView page when navigating to the LinksDetailsPage page:
private async void Button_Clicked(object sender, EventArgs e)
{
LinksDetailsPage detailPage = new LinksDetailsPage();
detailPage.ItemAdded += DetailGridPage_ItemAdded;
detailPage.ItemDeleted += DetailGridPage_ItemDeleted;
await Navigation.PushModalAsync(detailGridPage);
}
private void DetailGridPage_ItemDeleted(object sender, NewspaperLink e)
{
Console.WriteLine("The tlink was deleted : " + e.link);
}
private void DetailGridPage_ItemAdded(object sender, NewspaperLink e)
{
Console.WriteLine("The link was added : "+e.link);
}
Delegate
Similarly, if want to use Delegate, you only need to declare something in List Page as follows:
public partial class ListViewPage : ContentPage
{
public delegate void ItemAddedDelegate(NewspaperLink e);
public delegate void ItemDeletedDelegate(NewspaperLink e);
public ListViewPage()
{
InitializeComponent();
}
private async void Button_Clicked(object sender, EventArgs e)
{
ItemAddedDelegate itemAddedDelegate = AddMethod;
ItemDeletedDelegate itemDeletedDelegate = DeleteMethod;
DetailGridPage detailGridPage = new DetailGridPage(itemAddedDelegate, itemDeletedDelegate);
await Navigation.PushModalAsync(detailGridPage);
}
public static void AddMethod(NewspaperLink item)
{
Console.WriteLine("Add" + item.link);
}
public static void DeleteMethod(NewspaperLink link)
{
Console.WriteLine("Delete" + item.link);
}
}
Then in LinksDetailsPage, you can pass the add or delete delegate method to ListViewPage.
public partial class LinksDetailsPage : ContentPage
{
private ListViewPage.ItemAddedDelegate itemAddedDelegate;
private ListViewPage.ItemDeletedDelegate itemDeletedDelegate;
public DetailGridPage()
{
InitializeComponent();
}
public LinksDetailsPage(ListViewPage.ItemAddedDelegate itemAddedDelegate, ListViewPage.ItemDeletedDelegate itemDeletedDelegate)
{
InitializeComponent();
this.itemAddedDelegate = itemAddedDelegate;
this.itemDeletedDelegate = itemDeletedDelegate;
}
// Add click event
private void Add_Clicked(object sender, EventArgs e)
{
itemAddedDelegate(new NewspaperLink() { link = "first link" });
}
// Delete click event
private void Delete_Clicked(object sender, EventArgs e)
{
itemDeletedDelegate(new NewspaperLink() { link = "first link" });
}
}
public class NewspaperLink : EventArgs
{
public string link { get; set; }
}
MessageCenter
If using MessageCenter, it should be the best convenient method to achieve that.
Only Subscribe it in ListView page:
public ListViewPage()
{
InitializeComponent();
MessagingCenter.Subscribe<object, NewspaperLink>(this, "Add", async (sender, arg) =>
{
await DisplayAlert("Message received", "arg=" + arg.link, "OK");
});
MessagingCenter.Subscribe<object, NewspaperLink>(this, "Delete", async (sender, arg) =>
{
await DisplayAlert("Message received", "arg=" + arg.link, "OK");
});
}
And send message in LinksDetailsPage as follows:
// Add click event
private void Add_Clicked(object sender, EventArgs e)
{
NewspaperLink newspaperLink= new NewspaperLink() { link = "first link" };
MessagingCenter.Send<object, NewspaperLink>(this, "Add", newspaperLink);
}
// Delete click event
private void Delete_Clicked(object sender, EventArgs e)
{
NewspaperLink newspaperLink = new NewspaperLink() { link = "first link" };
MessagingCenter.Send<object, NewspaperLink>(this, "Delete", newspaperLink);
}
I have an issue with a custom event i have created. I have made a Usercontrol that looks the following:
public partial class UCListView : UserControl {
public UCListView() {
InitializeComponent();
}
public event EventHandler SubmitClick;
public event EventHandler MouseButtonUpEvent;
private void SubmitButton_OnClick(object sender, RoutedEventArgs e) {
if (SubmitClick != null)
SubmitClick(this, e);
}
private void MouseButtonUp(object sender, RoutedEventArgs e) {
if (MouseButtonUpEvent != null) {
MouseButtonUpEvent(this, e);
}
}
}
Here is the MouseButtonUp event i have.
The following is where i listen to the event:
public partial class RoundsteelWindow : WindowControls {
private UCListView uc;
public RoundsteelWindow() {
InitializeComponent();
uc = new UCListView();
uc.SubmitClick += new EventHandler(ButtonPressed);
uc.MouseButtonUpEvent += new EventHandler(MousePressed);
stkTest.Children.Add(uc);
base.Test<RoundSteel>(uc, "Roundsteel");
}
}
Here is the WindowControls, where the MousePressed method can be seen. This is the same as the code snippet beneath this code. Really don't see the issue:
public abstract class WindowControls : Window {
public IMaterialWith14Elements _ReturnObject { get; set; }
public double amount { get; set; }
private UCListView _uc;
public void Test<T>(UCListView uc, string type) where T: IMaterialWith14Elements, new() {
_uc = uc;
List<T> test = MaterialLogic.GetList(type) as List<T>;
foreach (T material in test) {
uc.listView.Items.Add(material.Name);
}
}
private string str;
public void MousePressed(object sender, EventArgs eventArgs) {
var item = (sender as ListView).SelectedItem;
if (item != null) {
_ReturnObject = _uc.listView.SelectedItems as FlatSteel ;
str = item.ToString();
_uc.amountText.IsEnabled = true;
}
}
public void ButtonPressed(object sender, EventArgs e) {
if (!string.IsNullOrEmpty(_uc.amountText.Text)) {
amount = _uc.amountText.Text.customParseToDouble();
this.Close();
}
else {
MessageBox.Show("Indtast venligst en værdi.");
}
}
}
Now the problem is the following: With the following code it is working, but this class is not using the windowcontrols. It is called by another class which handles all of the buttons.
private void flatsteelListView_PreviewMouseLeftButtonUp(object sender, RoutedEventArgs e) {
var item = (sender as ListView).SelectedItem;
if (item != null) {
_returnObject = flatsteelListView.SelectedItems as FlatSteel;
str = item.ToString();
amountTextbox.IsEnabled = true;
FindObject(str);
}
}
The first picture shows the working window. This is where there is not used a usercontrol. Actually this is a previous issue i have worked with and got help with here on stackoverflow Help for thisissue.
The second picture is showing the next window using the usercontrol that has been created. The button event works and closes the window. Here comes then the issue, when the listview item is pressed. It is doing the same thing as on the first picture(where it works), but it is giving me a null reference, which doesn't make any sense to me. I have also checked the object sender to see if there was a difference between the sender of these two different windows.
I simply can't figure out why this is not working.
greetings darophi
Your sender is an object of UCListView class which is inherited from UserControl and you are trying to use it like ListView. So as result of operation (sender as ListView) you get null because sender is not an instance of ListView class and not inherits it.
Here is my code in my userControl
public partial class UserControlHomeScreen : UserControl
{
public event EventHandler SomethingHappened;
public void DoSomething()
{
EventHandler handler = SomethingHappened;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
public void HandleEvent(object sender, EventArgs args)
{
MessageBox.Show("Wafak.");
}
public UserControlHomeScreen()
{
InitializeComponent();
}
private void btnAverageDailyBal_Click(object sender, EventArgs e)
{
this.Tag = 0;
this.Hide();
}
private void btnComputeTransferPricing_Click(object sender, EventArgs e)
{
this.Tag = 1;
this.Hide();
}
}
And here is my code in my main form
private void HomeScreen()
{
uHomeScreen = new UserControlHomeScreen();
uHomeScreen.Dock = DockStyle.Fill;
//uHomeScreen.Disposed += new EventHandler(uHomeScreen_Disposed);
uHomeScreen.SomethingHappened += new EventHandler(uHomeScreen_SomethingHappened);
panelMain.Controls.Add(uHomeScreen);
}
void uHomeScreen_SomethingHappened(object sender, EventArgs e)
{
MessageBox.Show("throw new NotImplementedException();");
}
What i want to happen is that when the usercontrol is hidden i want to fire an event in my main form but does not work, what am i missing? please help. thanks!
Your naming convention for event raiser (DoSomething) is confusing, your code doesn't call DoSomething (or raise the event SomethingHappened), so how could it fire for you? Add the following code in your user control class:
//override the OnVisibleChanged
protected override void OnVisibleChanged(EventArgs e){
if(!Visible) DoSomething();
}
I've followed this question and tried to build my solution. The problem is that 'UserControlButtonClicked' appears to be null! So 'UserControlButtonClicked(this, EventArgs.Empty)' inside the if, doesn't run, and the method 'addStepContent' in the parent page is never called.
UserControl 'StepsBar'
public sealed partial class StepsBar : UserControl
{
public event EventHandler UserControlAddStepContent;
[...]
public StepsBar()
{
this.InitializeComponent();
Image step_1 = new Image();
ButtonInfo step_1Info = new ButtonInfo();
step_1Info.Add((int)stepNumber.one, (int)stepStatus.normal);
step_1.Tag = step_1Info;
step_1.Source = setBackground((int)stepStatus.normal);
step_1.Tapped += stepTapped;
[...]
}
public void stepTapped(Object sender, RoutedEventArgs e)
{
[...]
if (step != null)
{
[...]
firePageEvent();
}
}
public void firePageEvent()
{
if (UserControlAddStepContent != null)
{
UserControlAddStepContent(this, EventArgs.Empty);
}
}
Parent Page
public Violation()
{
this.InitializeComponent();
StepsBar stepsBar = new StepsBar();
stepsBar.UserControlAddStepContent += new EventHandler(addStepContent);
}
private void addStepContent(object sender, EventArgs e)
{
CheckBox check_1 = new CheckBox();
check_1.Content = "Check me!";
bodyStackPanel.Children.Add(check_1);
}
This assumes that you want to use an existing delegate rather than make your own and you aren't passing anything specific to the parent page by event args.
In the user control's code-behind (adapt as necessary if not using code-behind or C#):
public partial class MyUserControl : System.Web.UI.UserControl
{
public event EventHandler UserControlButtonClicked;
private void OnUserControlButtonClick()
{
if (UserControlButtonClicked != null)
{
UserControlButtonClicked(this, EventArgs.Empty);
}
}
protected void TheButton_Click(object sender, EventArgs e)
{
// .... do stuff then fire off the event
OnUserControlButtonClick();
}
// .... other code for the user control beyond this point
}
In the page itself you subscribe to the event with something like this:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// hook up event handler for exposed user control event
MyUserControl.UserControlButtonClicked += new
EventHandler(MyUserControl_UserControlButtonClicked);
}
private void MyUserControl_UserControlButtonClicked(object sender, EventArgs e)
{
// ... do something when event is fired
}
}
Solved. The problem was this, on the parent page.
StepsBar stepsBar = new StepsBar();
stepsBar.UserControlAddStepContent += new EventHandler(addStepContent);
The istance of StepsBar was not added to the page. D'OH!
So here's what I've done:
stepsBar.UserControlAddStepContent += new EventHandler(addStepContent);
and on the xaml of the parent page:
<local:StepsBar x:Name="stepsBar"/>
I'm trying to subscribe to the the save button event of a user control that is launched in a separate radwindow from the calling parent. but I am getting object not initialized error, I know why but what am I missing?
Update: I found my error but it appears that if (this.SaveEvent!= null) in the ControlBase is always null
Parent Control Code:
public partial class myControl : ControlBase
{
private myChildControl __myChildControl;
private void myControl_PreRender(object sender, EventArgs e)
{
// error occurs here
//this.__myChildControl.SaveEvent += new myChildControl.SaveEventHandler(__myChildControl_SaveEvent);
// found my error
this.SaveEvent += new myChildControl.SaveEventHandler(__myChildControl_SaveEvent);
}
private void __myChildControl _SaveEvent(object sender, CustomEventArgs e)
{
this.Label1.Text = e.CustomEventArg1.ToString();
this.Label2.Text = e.CustomEventArg2.ToString();
}
}
Child Control Launched in RadWindow:
public partial class myChildControl : ControlBase
{
protected void btnSave_OnClick(object sender, EventArgs e)
{
CustomEventArgs _cea = new CustomEventArgs {CustomEventArg1 = 123, CustomEventArg2 = 12};
callBaseMethod(_cea);
}
}
ControlBase Code:
public class ControlBase : UserControl
{
public event CustomEventHandler SaveEvent;
public delegate void CustomEventHandler(object sender, CustomEventArgs e);
internal void callBaseMethod(CustomEventArgs cea)
{
if (this.SaveEvent!= null)
{
this.SaveEvent(this, cea);
}
}
}
CustomEventArgs class:
public class CustomEventArgs : EventArgs
{
public int CustomEventArgs1 { get; set; }
public int CustomEventArgs2 { get; set; }
}
This isn't possible in codebehind: the RadWindow presents a separate aspx/ascx page altogether that is linked to the main page through javascript alone.
What you need to do is handle the RadWindow OnClientClose event in javascript, then fire something in the parent page that performs the appropriate tasks.