My webpart event handling does not fire in SharePoint - sharepoint

I started coding something complicated and then realized my event handlers don't work, so I super simplified a button with an event handler. Please see the code below and maybe you can tell me why it doesn't fire?
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using System.Web.UI.WebControls;
namespace PrinterSolution
{
[Guid("60e54fde-01bd-482e-9e3b-85e0e73ae33d")]
public class ManageUsers : Microsoft.SharePoint.WebPartPages.WebPart
{
Button btnNew;
protected override void CreateChildControls()
{
btnNew = new Button();
btnNew.CommandName = "New";
btnNew.CommandArgument = "Argument";
btnNew.Command += new CommandEventHandler(btnNew_Command);
this.Controls.Add(btnNew);
}
void btnNew_Command(object sender, CommandEventArgs e)
{
ViewState["state"] = "newstate";
}
//protected override void OnLoad(EventArgs e)
//{
// this.EnsureChildControls();
//}
}
}

I had a similar problem. In my case the button was contained in a panel and although buttons on the parent control worked correctly the button on the child Panel control didn't.
It turns out that you need to call EnsureChildControls in the OnLoad method in the child panel to ensure that CreateChildControls is called early enough in the life cycle of the page so that controls can respond to events. This is described briefly in this answer here which is where I discovered the solution to my problem.
Following this instruction I just added the following code to my panel control:
protected override void OnLoad(EventArgs e)
{
EnsureChildControls();
base.OnLoad(e);
}
I notice that there appears to be a lot of confusion about this issue in the forums so to demonstrate that this works I added trace statements to my code. Below are the results from the before and after cases. Note that the position of Survey list creating child controls moves from within the PreRender event to within the Load event.
Before:
After:

Related

How to call a method when clicking button

Very unfamiliar with Acumatica, I am trying to make a button clickable that I configured on the Employee Time Card screen. I want it to call a method when clicked but I have been unsuccessful.
Here is my the screen. The button is labeled PUNCH CARD.
Made some changes:
When I click on the PUNCH CARD button I do see a POST back to the server: https://dev.domain.tld/db/(W(20))/pages/ep/ep305000.aspx?PopupPanel=Inline&HideScript=On&TimeCardCD=TC00000001
I think I should be seeing some exception response on the screen but I see nothing.
Here is the aspx code. I don't know what to put in the DependOnGrid attribute. I just copied what was on Yuri Zaletskyy's blog. Is this always set to this or is there something specific to the site / page I am working with? If so how do I determine what to put here?
<px:PXToolBarButton Text="Punch Card" Visible="True" DependOnGrid="grdJiraProjects">
<AutoCallBack Target="" Enabled="True" Command="punchCard">
<Behavior CommitChanges="True" /></AutoCallBack>
<PopupCommand>
<Behavior CommitChanges="True" />
</PopupCommand></px:PXToolBarButton>
C# Code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PX.Common;
using PX.Data;
using PX.Objects.CR;
using PX.Objects.CS;
using PX.Objects.IN;
using PX.Objects.CT;
using PX.Objects.PM;
using PX.Objects.GL;
using System.Diagnostics;
using System.Globalization;
using PX.SM;
using PX.TM;
using PX.Web.UI;
using Branch = PX.Objects.GL.Branch;
using System.Text;
using PX.Objects.GL.FinPeriods.TableDefinition;
using PX.Objects.GL.FinPeriods;
using PX.Objects;
using PX.Objects.EP;
namespace TimeTracking
{
public class TimeCardMaint_Extension : PXGraphExtension<PX.Objects.EP.TimeCardMaint>
{
public PXSelect<PMTimeActivity> PMTimeActivity;
public PXAction<EPTimeCard> PunchCard;
#region Event Handlers
protected void EPTimecardDetail_UsrPIXIClockIn_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e, PXFieldUpdated InvokeBaseHandler)
{
if(InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (PMTimeActivity)e.Row;
var rows = row.GetExtension<PMTimeActivityExt>();
updateTotalHours(cache, rows, row);
}
protected void EPTimecardDetail_UsrPIXIClockOut_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e, PXFieldUpdated InvokeBaseHandler)
{
if(InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (PMTimeActivity)e.Row;
var rows = row.GetExtension<PMTimeActivityExt>();
updateTotalHours(cache, rows, row);
}
#endregion
public void punchCard()
{
throw new PXException("You Clicked Punch Time Card on Action Bar");
}
public void updateTotalHours(PXCache cache, PMTimeActivityExt rows, PMTimeActivity row)
{
if (rows.UsrPIXIClockIn != null && rows.UsrPIXIClockOut != null)
{
DateTime dtClockIn = DateTime.Parse(rows.UsrPIXIClockIn.ToString());
DateTime dtClockOut = DateTime.Parse(rows.UsrPIXIClockOut.ToString());
double total = (dtClockOut - dtClockIn).TotalHours;
rows.UsrPIXITotalHours = (decimal) total;
}
}
}
}
One common catch that results in the button action event handler not being called is using the wrong DAC for the action generic type parameter.
Make sure the action generic type matches the graph primary DAC. In your case this would be EPTimeCard:
public PXAction<EPTimeCard> PunchCard;
Do you have a Graph Extension?
That's where you should put the action event handler for the button.
In your case TimeCardMaint is the graph of the employee time card screen:
using PX.Data;
using PX.Web.UI;
using System.Collections;
namespace PX.Objects.EP
{
public class TimeCardMaint_Extension : PXGraphExtension<TimeCardMaint>
{
public PXAction<EPTimeCard> PunchCard;
[PXButton]
[PXUIField(DisplayName = "Punch Card")]
public virtual IEnumerable punchCard(PXAdapter adapter)
{
// This is where you handle button click event
return adapter.Get();
}
}
}
There is something special about the button you added. It is located in a grid toolbar. It's often the case that you want grid toolbar actions to operate on the currently selected line. For that to work you need to declare the action in ASP file and set it's DependOnGrid property:
This is explained in more details here:
http://blog.zaletskyy.com/dependongrid-in-acumatica-or-how-to-get-currently-selected-record-in-grid
This link could help you too:
http://blog.zaletskyy.com/add-button-to-grid-in-acumatica
Once everything is setup you could then access the currently selected record in the grid from your action event handler like this:
[PXButton]
[PXUIField(DisplayName = "Punch Card")]
public virtual IEnumerable punchCard(PXAdapter adapter)
{
EPTimeCardDetail row = Base.Activities.Current as EPTimeCardDetail;
if (row != null)
{
// Presumably do some Punch Card action on selected row from Details tab Activities grid
}
return adapter.Get();
}

Action listeners not firing

I've been developing with codenameone for over a year, and I never ran into this problem before, I feel like I'm losing my mind. I just redesigned one part of an app I'm working on, and now the ActionListeners aren't firing. I'm attaching them to a Button and a SpanButton in the code:
ActionListener goToDoc = new ActionListener() {
String mDocId = docId;
#Override
public void actionPerformed(ActionEvent evt) {
mStateMachine.currentExpertId = mDocId;
mStateMachine.showForm("DoctorDetails", null);
}
};
name.addActionListener(goToDoc);
Util.downloadImageToStorage(mStateMachine.URL_PREFIX+"images/doctors/"+(String)value.get("doc_pic"),
"doc_post_pic_"+(String)value.get("doc_id")+".png", new Callback<Image>() {
#Override
public void onSucess(Image img) {
pic.setIcon(img.scaledWidth(mStateMachine.getProportionalWidth(.23)));
StateMachine.applyGreenBorder(pic);
pic.addActionListener(goToDoc);
pic.getParent().revalidate();
}
#Override
public void onError(Object sender, Throwable err, int errorCode, String errorMessage) {
System.out.println("Unable to download expert profile picture");
}
});
When I debug the code, the components do show that the ActionListener is attached, but the actionPerformed method is never reached, no matter how many times I click on the buttons. I experience this problem both on the simulator and on an Android device. I have yet to test on an iPhone.
Did you set a parent to be a lead component or focusable?
The reason the click event wasn't firing was because the Components weren't enabled, possibly a bug in the BUI Builder. After checking off the 'Enabled' and 'Focusable' checkboxes in the GUI Builder, and seeing they were unchecked every time I went back to that form, I just used component.setFocusable(true) and component.setEnabled(true) in the code, and it worked fine after that.

Accessing UI from non-ui thread using dispatcher did not work

I am beginner to C# .net. I have simple app in wpf which access a listbox from user thread. in winforms i can use invokerequired, a equivalent for wpf using dispatcher did not help. My system also hangs for the buttons so debugging is though. Please provide solution for the below code. thanks in advance
private void Monitor_mtd()
{
while (AppStatus != 0)
{
if (flag2 == 1)
{
listBox1.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new list1MtdDelegate(list1Mtd), "Best practice");
}
}
}
private delegate void list1MtdDelegate(string ls1);
private void list1Mtd(string ls1)
{
listBox1.Items.Add(ls1);
}
private void button1_Click_1(object sender, RoutedEventArgs e)
{
Monitor = new Thread(new ThreadStart(Monitor_mtd));
Monitor.Start();
flag1 = 1;
}
private void button2_Click(object sender, RoutedEventArgs e)
{
flag2 = 1;
}
There are a couple of issues that arise in your approach. Firstly, the way that you bind your data to the ListBox and secondly trying to update the ListBox from a user thread.
You can solve the binding of the ListBox by using an ObservableCollection so that the UI is updated with the necessary values (have a look at this post for more information on this). However, this also raises another problem and that is that the ObservableCollection cannot be called from another thread other than the one it is dispatching (see more on this here also). This means that you need another implementation for the ObservableCollection. Thomas Levesque made an AsyncObservableCollection that can be modified from any thread and still notify the UI when its modified.
I made a sample implementation that you can download here showing the full solution.

Why would MonoTouch not garbage collect my custom UIButton unless I call button.RemoveFromSuperview()?

There seems to be something holding a reference to my custom button, MyButton (which inherits from UIButton), causing it not to be garbage collected unless I remove it from the superview. This, in turn, would cause the view controller that it is on to also not be finalized and collected.
In my example, I have my custom button but I also have a standard UIButton on the view controller which does not need to be removed from the superview in order to be collected. What's the difference? Looks pretty similar to me.
See this code. The irrelevant lines were removed for example's sake. Some things to note about the sample:
-MyButton is pretty empty. Just a constructor and nothing else overridden.
-Imagine MyViewController being on a UINavigationController
-LoadView() just creates the buttons, hooks up an event for each and adds it to the view
-Touching _button would push another MyViewController to the nav controller
-I'm doing some reference cleanup when popping view controllers off the nav controller in ViewDidAppear()
-In CleanUpRefs() you'll see that I have to remove _myButton from superview in order for all the objects to be garbage collected. _button, on the other hand does not need to be removed.
-I'm expecting the entire MyViewController to be collected, including all subviews, when popping from the nav controller but commenting out _myButton.RemoveFromSuperview() stops this from happening.
public class MyViewController : UIViewController
{
private UIButton _button;
private MyButton _myButton;
private MyViewController _nextController;
public override void LoadView()
{
base.LoadView();
_button = UIButton.FromType(UIButtonType.RoundedRect);
_button.TouchUpInside += PushNewController;
View.AddSubview(_button);
_myButton = new MyButton();
_myButton.TouchUpInside += MyButtonTouched;
View.AddSubview(_myButton);
}
private void PushNewController(object sender, EventArgs e)
{
_nextController = new MyViewController();
NavigationController.PushViewController(_nextController, true);
}
private void MyButtonTouched(object sender, EventArgs e)
{
Console.WriteLine("MyButton touched");
}
public void CleanUpRefs()
{
//_button.RemoveFromSuperview();
_myButton.RemoveFromSuperview();
// remove reference from hooking up event handler
_button.TouchUpInside -= PushNewController;
_myButton.TouchUpInside -= MyButtonTouched;
_button = null;
_myButton = null;
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if(_nextController != null)
{
_nextController.CleanUpRefs();
_nextController = null;
}
}
}
It seems as if there's something different with the fact that MyButton isn't a straight UIButton in that it is inherited. But then again, why would there be an extra reference count to it that's being removed by calling RemoveFromSuperview() especially when there's a UIButton just like it that doesn't need to be removed?
(I apologize for the really bad layout, stackoverflow seems to have problems laying out bullets right above code snippets)
Update: I filed a bug report with the MonoTouch team. You can download the sample project from there if you want to run it. Bug 92.
The reason for not garbage collecting in that scenario is just a bug in MonoTouch.
The upcoming MonoTouch release will contain a fix for this. If you are in a hurry, you can replace your /Developer/MonoTouch/usr/lib/mono/2.1/monotouch.dll with the copy I placed here:
http://tirania.org/tmp/monotouch.dll
I would make a backup, in case I did something wrong in my work-in-progress library.

How To Make UserControl In MasterPage Public For All Child Pages

I have a UserControl which I have added to my web.config
<add tagPrefix="BCF" src="~/controls/MyMessageBox.ascx" tagName="error"/>
and added to my master page
<BCF:error ID="BCError" runat="server" Visible="false" />
Now I need to be able to reference this control AND its public properties from all child pages that use that masterpage. I did this is my BasePage OnLoad event
public UserControl BCError;
BCError = (UserControl)Master.FindControl("BCError");
Problem is, although I can do this in the .aspx page
BCError.Visible = true;
I cannot reference any of the Controls properties I have put in? Such as ShowError .. If I do
BCError.ShowError = "Error Message";
I just get an error saying
'System.Web.UI.UserControl' does not contain a definition for 'ShowInfo' and no extension method 'ShowInfo'
Can you please point me in the right direction!
This is the code for the user control... I can use the properties in the masterpage code behind (And in a page if I put the control directly into it) but cannot use them in the child page code behind?? It doesn't even show the properties or wrapper methods in the intellisense?
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class MyMessageBox : System.Web.UI.UserControl
{
#region Properties
public bool ShowCloseButton { get; set; }
#endregion
#region Load
protected void Page_Load(object sender, EventArgs e)
{
if (ShowCloseButton)
CloseButton.Attributes.Add("onclick", "document.getElementById('" + MessageBox.ClientID + "').style.display = 'none'");
}
#endregion
#region Wrapper methods
public void ShowError(string message)
{
Show(MessageType.Error, message);
}
public void ShowInfo(string message)
{
Show(MessageType.Info, message);
}
public void ShowSuccess(string message)
{
Show(MessageType.Success, message);
}
public void ShowWarning(string message)
{
Show(MessageType.Warning, message);
}
#endregion
#region Show control
public void Show(MessageType messageType, string message)
{
CloseButton.Visible = ShowCloseButton;
litMessage.Text = message;
MessageBox.CssClass = messageType.ToString().ToLower();
this.Visible = true;
}
#endregion
#region Enum
public enum MessageType
{
Error = 1,
Info = 2,
Success = 3,
Warning = 4
}
#endregion
}
Ok I think I reproduced roughly what your describing and I deleted my original answer cause it was way off.
What I found is that when you want a content page to reference a user control being used in a master page and the control is accesible and what not, you will get an error indicating that you need to reference a specific assembly, and then you get errors indicating that no Method exists of type such and such.
By adding the Register page directive on the child page to the user control resolved this issue. I reproduced this even with the control defined in the web.config or on the page. In both cases I still had to explicitly add a Register on the content page.
This doesn't make sense to me but it allowed my code to compile and work. Give it a shot let me know.
Once you do this you can reference the control like
this.Master.MessageBox.ShowInfo();
This assumes that you have a public property called MessageBox on the Master Page.
Edit
I've also found that this works much better if you register the control on both the master and the content page and not use the web.config.
Edit
If you don't want your child page to reference the user control your other option is expose methods on the master page like ShowInfo() which would delegate to the user control.
You need to declare it as your control type to access it's properties.
public MyMessageBox BCError;
BCError = (MyMessageBox )Master.FindControl("BCError");
Try using this in the pages that inherit from your master page:
<%# MasterType VirtualPath="~/MasterPageName.Master" %>

Resources