I am creating an addon and for that i have successfully connected di and ui api. i am creating everything (forms, buttons, textbox etc ) manually by code to learn as this is my first one. when i debug i can see my form with all the fields i created. here is the code for form creation.
SAPbouiCOM.FormCreationParams oCreationParams = null;
oCreationParams = ((SAPbouiCOM.FormCreationParams(SBO_Application.CreateObject(SAPbouiCOM.BoCreatableObjectType.cot_FormCreationParams)));
oCreationParams.BorderStyle = SAPbouiCOM.BoFormBorderStyle.fbs_Fixed;
oCreationParams.UniqueID = "Form2";
oForm = SBO_Application.Forms.AddEx(oCreationParams);
oForm.Title = "Simple Form";
oForm.Left = 417;
oForm.Top = 520;
oForm.ClientHeight = 610;
oForm.ClientWidth = 770;
here is how i create my button
SAPbouiCOM.Button oButton = null;
oItem = oForm.Items.Add("Button1", SAPbouiCOM.BoFormItemTypes.it_BUTTON);
oItem.Left = 6;
oItem.Width = 65;
oItem.Top = 51;
oItem.Height = 19;
oItem.Enabled = true;
oButton = ((SAPbouiCOM.Button)(oItem.Specific));
oButton.Caption = "Add";
the problem is when i try to add the values of textbox in database on button click event, i am not able to generate a button click event.
from my knowledge when we create a button from toolbox and uses system form, it automatically initializes the button ON InitializeComponent() function and also creates a delegates pointing to button click event.
May i know how to achieve all these through code.
i tried to initialize button through my manual code and also created delegates pointing to a button click function but i was unable to achieve my result.
Try adding a method that captures SAP B1 item events like this:
public void HandleItemEvent(ref SAPbouiCOM.ItemEvent pVal)
{
if (pVal.BeforeAction == false && pVal.EventType == SAPbouiCOM.BoEventTypes.et_ITEM_PRESSED && pVal.ItemUID == "Button1")
{
// You code here
}
}
Related
I am working with sage 200 summer edition and I have an issue with a piece of code I need to be able to do a null check on the Sage.Controls.Button but even if I place it into a var it will still crash its what is called an amendable button in windows forms.
While true most people will stright away suggest this is a null issue and how to solve it its not that quite simple casue I am dealing with sage objects I have searched for existing refersnces for the underlyingcontrol function and cannot find any documenation on the object or how to handle the null
If I just do the following
var control = (Sage.Common.Controls.Button)Form.FindControlByName("saveButton").UnderlyingControl;
And do an if statement around that it will still crash. Any Ideas how to handle this.
public override void ConfigureForm()
{
var sopOrderReturnLine = (Sage.Accounting.SOP.SOPOrderReturnLine) Form.BoundObjects[0];
_itemDescription = sopOrderReturnLine.ItemDescription;
if (sopOrderReturnLine.SOPOrderReturn.SpareBit1)
{
var button = new Button();
button.Name = "extraInfoButton";
button.Text = "Extra Info...";
button.Alignment = ButtonAlignmentInContainer.Left;
var buttonPanel = (ControlPanel) Form.FindControlByName("buttonPanel").UnderlyingControl;
buttonPanel.Controls.Add(button);
button.Click += new EventHandler(button_Click);
}
var control = (Sage.Common.Controls.Button)Form.FindControlByName("saveButton").UnderlyingControl;
if (control !=null)
{
var saveButton = (Sage.Common.Controls.Button)Form.FindControlByName("saveButton").UnderlyingControl;
saveButton.BeforeClick += new System.ComponentModel.CancelEventHandler(saveButton_BeforeClick);
}
}
So I found this very puzzling problem which involves dynamic buttons.
Here is my method that creates the buttons:
private void CreateButtons()
{
//Button outside loop works
Button selectItem = new Button();
selectItem.Text = "Hello World";
selectItem.ID = "btn";
selectItem.Click += selectItem_Click;
PlaceHolder1.Controls.Add(selectItem);
int ItemCounter = 0;
for (int i = 0; i < BillDate.Count; i++)
{ //Button inside loop doesnt work
ItemCounter++;
Button selectItem = new Button();
selectItem.Text = "Hello World";
selectItem.ID = "btn-" + ItemCounter.ToString();
selectItem.Click += selectItem_Click;
PlaceHolder1.Controls.Add(selectItem);
}
}
Now here is the problem,
the button that is created outside the loop works fine (event handler selectItem_Click only redirects page).
Why does the button not work inside the loop and why does it work outside the loop?
All of the buttons in your loop have the same ID, since you're not incrementing ItemCounter. While you could just use i instead, you don't appear to be using the ID at all, so you're better off just not setting it in the first place.
Also keep in mind that on the post back the buttons need to be created and added to the page in the PreInit event in order for the event handler to be able to run.
Dynamically creating controls, particularly controls that have handlers on subsequent postbacks, can be quite tricky. It's not uncommon at all to need data from the request to be able to generate the controls, but to need the controls to be generated before the request is processed by ASP for the events to fire. It's dramatically easier to create a template that you bind your data to, using something like a GridView or a Repeater instead, as it will be able to properly handle re-creating the controls before the request is processed while still allowing you to have a dynamic number of instances of the template.
**Use the below code it will work.**
private void CreateButtons()
{
//Button outside loop works
Button selectItem = new Button();
selectItem.Text = "Hello World";
selectItem.ID = "btn";
selectItem.Click += selectItem_Click;
PlaceHolder1.Controls.Add(selectItem);
int ItemCounter = 0;
for (int i = 0; i < BillDate.Count; i++)
{ //Button inside loop doesnt work
Button selectItem = new Button();
selectItem.Text = "Hello World";
selectItem.ID = "btn-" + ItemCounter.ToString();
selectItem.Click += selectItem_Click;
ItemCounter++;
PlaceHolder1.Controls.Add(selectItem);
}
}
I have a C# Form application that has a TabControl in the main form. This TabControl is used to display multilple TabPages that contain a CustomControl. This CustomControl is just a Panel with a few buttons and a PictureBox.
Here is a picture of my app when it starts up. As you can see the tab control (the white area) is empty:
If the user clicks the "Add Image" button they are presented with an OpenFileDialog to select the image then the addImage method is called with the selected file:
private void doAddImage()
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = Constants.Global.IMAGE_FILE_FILTER();
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string imageFileName = openFileDialog.FileName;
addImage(imageFileName);
}
}
private void addImage(string imageFileName)
{
// Create a new bitmap and image preview custom control. Then create a new tab
// page and add the custom control to the tab page.
Bitmap bitMap = new Bitmap(imageFileName);
ImagePreviewCustomControl previewControl = new ImagePreviewCustomControl(bitMap);
previewControl.Dock = DockStyle.Fill;
TabPage tabPage = new TabPage(Path.GetFileNameWithoutExtension(imageFileName));
tabPage.Controls.Add(previewControl);
// Insert the new tab page to the right of the currently selected tab page
int selectedTabIndex = imagesTabControl.SelectedIndex;
imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex + 1;
}
As you can see, in the addImage method I create the Bitmap, CustomControl, and TabPage and then insert it into the TabControl.
I start my application, click the "Add Image" button, everything works just fine.
Here is a picture with a tab page added:
While I am testing my app I don't want to have to add an image manually using the OpenFileDialog every time so in my constructor I just call addImage with some fixed image file name that I want to test with:
public ImageViewerApp()
{
InitializeComponent();
addImage(#"C:\MyImages\Calculator-3-icon.png");
}
The problem I am having is that when I try to add the image in my constructor it doesn't show up in the TabControl. The application starts up blank (like the first picture).
As stated above when the application is already running and I click the "Add Image" button it gets added just fine.
I found a property in the TabControl class called Created which states:
"Gets a value indicating whether the control has been created"
So to try and figure out what's going on I write the value of Created to the console just before I call addImage in the constructor. (I have a custom console for debugging my Form applications.)
public ImageViewerApp()
{
InitializeComponent();
TestConsole.WriteLine(imagesTabControl.Created);
addImage(#"D:\Development\Work\Other\Stardock\Start8\_downloaded\Calculator-3-icon.png");
}
The value of Created just before the call to addImage in the constructor is:
False
I put another console output inside the addImage method:
private void doAddImage()
{
TestConsole.WriteLine(imagesTabControl.Created);
OpenFileDialog openFileDialog = new OpenFileDialog();
...
...
}
The value of Created after the app has started and the user presses the "Add Image" button is:
True
Why is it that the TabControl is not Created inside my constructor (even after the InitializeComponent() call) and the once the application is running it is Created?
=UPDATE========================================================================
Based on the suggestion by Hans Passant I have added the following code to my addImage method:
int selectedTabIndex = -1;
if (imagesTabControl.TabCount > 0)
{
selectedTabIndex = imagesTabControl.SelectedIndex;
}
else
{
selectedTabIndex = imagesTabControl.SelectedIndex + 1;
}
imagesTabControl.TabPages.Insert(selectedTabIndex, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex;
This doesn't work.
===============================================================================
=UPDATE2=======================================================================
int selectedTabIndex = imagesTabControl.SelectedIndex;
if (imagesTabControl.TabCount == 0) selectedTabIndex = -1;
imagesTabControl.TabPages.Insert(selectedTabIndex, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex;
This causes the following Exception:
{"InvalidArgument=Value of '-1' is not valid for 'index'.\r\nParameter name: index"}
===============================================================================
=UPDATE3=======================================================================
I tried the folllowing code:
int selectedTabIndex = imagesTabControl.SelectedIndex;
if (imagesTabControl.TabCount == 0) selectedTabIndex = -1;
imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex + 1;
This one doesn't throw an exception but again no tab page added after calling
addImage in the constructor.
===============================================================================
=UPDATE4=======================================================================
I have kindof given up on adding an image in the constructor. So instead I am using an enum RunMode and a variable RUN_MODE of that type. Then, if RUN_MODE == RunMode.TESTI call a method to add a random image when I click the button. (The OpenFileDialog is not used. I just parse through all the image files in the fixed directory IMAGE_DIRECTORY.
enum RunMode { NORMAL, TEST }
private static string IMAGE_DIRECTORY = #"D:\\Work\Images";
...
...
private void doAddImage()
{
if (RUN_MODE == RunMode.TEST)
{
addRandomImage();
return;
}
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = Constants.Global.IMAGE_FILE_FILTER();
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string imageFileName = openFileDialog.FileName;
addImage(imageFileName);
}
}
private void addRandomImage()
{
string[] allFiles = Directory.GetFiles(IMAGE_DIRECTORY);
List<string> imageFileNames = new List<string>();
foreach (string file in allFiles)
{
bool isImageFile = Constants.Global.IMAGE_EXTENSIONS.Contains(Path.GetExtension(file));
if (isImageFile)
{
imageFileNames.Add(file);
}
}
int randomIndex = new Random().Next(imageFileNames.Count);
addImage(imageFileNames.ElementAt(randomIndex));
}
This works. Now when I click the "Add Image" button during TEST_MODE I skip the
OpenFileDialog and just add a random image.
I would like to understand the issues with TabControl but at this point I just
need to continue development. My current solution works great.
As I person who like to understand everything I would like to use other people's
suggestions so I will keep monitoring this question for a solution.
===============================================================================
JonP's answer gave me the idea to just wait for the window handle to be created before inserting the tab, so I tried some events occuring between Form construction and Tab Control display.
I found it to work with both the Load or Shown events:
Right-click on the Form (the root, not child controls) in the Designer view > Properties > Events (flash icon) > Behavior > enter a method name for the Load or Shown event and confirm. To generate a Load event callback you can also double-click on the Form itself. This should generate something like this:
this.Load += new System.EventHandler(this.Form1_Load);
// or
this.Shown += new System.EventHandler(this.Form1_Shown);
Setup the tabs in the callback:
private void Form1_Load(object sender, EventArgs e)
{
// Add image (this will call imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage))
// This must be done on Load event because Insert requires
// the window handle, which is not ready in the constructor
addImage(#"path_to_image.png");
}
I have had this problem too and have found a workaround; I think it must be a bug with Insert():
Don't use Insert(), it usually does nothing, use Add() instead; this reliably adds a TabPage to the end of the collection.
After adding it swap it with the tab position where you actually want it.
imagesTabControl.TabPages.Add(tabPage);
// Now swap the two tabs:
imagesTabControl.TabPages[imagesTabControl.TabCount - 1] = imagesTabControl.TabPages[selectedTabIndex + 1];
imagesTabControl.TabPage[selectedTabIndex + 1] = tabPage;
Your mileage may vary of course :-)
Stop Press! An even better fix is to read the class's Handle member before calling Insert():
var handle = imagesTabControl.Handle;
Insert() works perfectly after you do that. Obvious isn't it???? The help page for Handle has this possible relevant Remark showing that the object actually does something when you read Handle:
The value of the Handle property is a Windows HWND. If the handle has not yet been created, referencing this property will force the handle to be created.
You could remove the TabControl from the designer and then instead just manually create the TabControl programmatically and add it to the Form immediately after InitializeComponent(). Then after you create the TabControl, call addImage(). Something like:
InitializeComponent();
TabControl tc = new TabControl();
tc.Location = new Point(10, 10);
tc.Size = new Size(100, 100);
tc.Visible = true;
tc.Anchor = (AnchorStyles.Bottom | AnchorStyles.Right | AnchorStyles.Left | AnchorStyles.Top);
this.Controls.Add(tc)
addImage("c:\pathToImage\image.bmp");
I am dynamically creating buttons in C# with this logic
for (int i = 1; i <= vap; ++i)
{
newButtons[i] = new Button();
newButtons[i].BackColor = Color.Gray;
newButtons[i].Name = "Button4" + i.ToString();
newButtons[i].Click += new EventHandler(NewButtons_Click);
newButtons[i].Location = new System.Drawing.Point(width,height);
newButtons[i].Size = new System.Drawing.Size(76, 38);
tabPage5.Controls.Add(newButtons[i]);
}
This is creating a button and the click event is also working but my problem is I don't know how to get the text of the newly created button. On form load I am putting the text of button from database and this also happening correctly, but I want to know how to get the text of dynamically created buttons.
You won't be able to get the text until after you populate it from the database (careful not to try and get the text too early).
But this should work:
string buttonText = FindControl("Button41").Text;
Update
Since you want the button text from within the click event, you can access the sender object:
Button button = sender as Button;
string buttonText = button.Text;
You just have to set the Text property of the button when you add it.
Using something along the lines of...
string BtnTxt = FindControl("ExampleButton1").Text;
should work fine.
This may cause problems later on however if you are trying to pull text content of buttons in a random order.
In a Web Part for Sharepoint, I'm trying to add a variable number/ordering of ButtonColumns to a DataGrid dynamically based on an option the user has selected. The problem is that the dynamic columns aren't firing off the events I set up on the DataGrid (such as SelectedIndexChanged). When the table originally constained a static set of columns, they were created in CreateChildControls() and everything worked peachy. However, since they are now dynamic, I have to delay adding them until after a search button's click event fires. I was wondering if there was some place I needed to move the column creation to that still allowed it to be dynamic but also allowed it to register/fire events.
outputDG creation in CreateChildControls():
outputDG = new System.Web.UI.WebControls.DataGrid();
outputDG.CellPadding = 4;
outputDG.HeaderStyle.Font.Bold = false;
outputDG.HeaderStyle.Font.Name = "Verdana";
outputDG.HeaderStyle.BackColor = Color.FromArgb(242,242,242);
outputDG.HeaderStyle.ForeColor = Color.FromArgb(128,128,128);
outputDG.HeaderStyle.Wrap = false;
//outputDG.ItemStyle.BorderColor = Color.Navy;
outputDG.HorizontalAlign = HorizontalAlign.Left;
//outputDG.BorderWidth = 1;
outputDG.GridLines = GridLines.Horizontal;
outputDG.Width = propsMgr.SearchGridWidth;
outputDG.PageSize = 10;
outputDG.AllowPaging = true;
outputDG.PagerStyle.Mode = PagerMode.NumericPages;
outputDG.PagerStyle.PageButtonCount = 5;
outputDG.PagerStyle.NextPageText = "Next Page";
outputDG.PagerStyle.PrevPageText = "Previous Page";
outputDG.PagerStyle.Visible = true;
outputDG.PageIndexChanged += new DataGridPageChangedEventHandler(this.outputDG_PageIndexChanged);
outputDG.AllowSorting = false;
outputDG.SortCommand += new DataGridSortCommandEventHandler(this.outputDG_SortCommand);
outputDG.SelectedItemStyle.BackColor = Color.FromArgb(255,244,206);
outputDG.SelectedIndexChanged += new EventHandler(this.outputDG_SelectedIndexChanged);
outputDG.ItemCreated += new DataGridItemEventHandler(this.outputDG_ItemCreated);
outputDG.AutoGenerateColumns = false;
outputDG.ItemCommand += new DataGridCommandEventHandler(outputDG_ItemCommand);
Controls.Add(outputDG);
During the search button's click event:
ButtonColumn buttonColumnSelect = new ButtonColumn();
buttonColumnSelect.ButtonType = ButtonColumnType.LinkButton;
buttonColumnSelect.CommandName = "Select";
buttonColumnSelect.HeaderText = "Column";
buttonColumnSelect.DataTextField = "columnField";
outputDG.Columns.Add(buttonColumnSelect);
And then later on it that same event I go through the result set and add in my data rows. Like I mentioned, this all worked back when the ButtomColumn code was up in CreateChildControls(), but it stopped working as soon as it was moved into an event. My best guess is that the event for the column doesn't have a chance to register in order to fire since it's happening from a different event. If I need to tackle this problem by building up the DataGrid differently, I'm definitely willing; I just need to be able to dynamically specify different columns to use.
maybe u need to set the ID-Attribute on the DataGrid.
otherwise it would be difficult for asp to find your control.
The fix for my case was to move the adding of the columns to the page's load event and the adding of the DataGrid to the controls after all of the columns are added.