In the Contact Screen (CR302000) I have created a Tab with a grid that Displays all the orders related to the selected Contact through a SOOrder. UsrInstitutionalContact. The view works correctly on the grid.
I need to link the Order Number from the grid to the SO.
I did all the steps to make it work and works fine except for one problem. I cannot get the current OrdNbr.
I tested the process hardcoding the OrdNbr to make sure that the:
PXRedirectHelper.TryRedirect(graph, PXRedirectHelper.WindowMode.NewWindow); works.
This is the grid displaying the fields as I wanted working correctly.
This is the view that I'm using for the grid
public SelectFrom<Contact>.
LeftJoin<SOOrder>.On<SOOrderExt.usrInstitutionalContact.IsEqual<Contact.contactID>>.
Where<Contact.contactID.IsEqual<Contact.contactID.FromCurrent>>.View ContactOrders;
Here is the Action code and what I have tried so far without any success:
1 public PXAction<Contact> ViewSalesOrder;
2
3 [PXButton]
4 protected virtual void viewSalesOrder()
5 {
6 SOOrderEntry graph = PXGraph.CreateInstance<SOOrderEntry>();
7
8 if (ContactOrders.Current != null)
9 {
10 Contact curRow = Base.ContactCurrent.Current;
11 SOOrder soorder = SelectFrom<SOOrder>.
12 Where<SOOrder.orderNbr.IsEqual<#P.AsString>>.View.Select(Base, "EMC000994");
13
14 graph.Document.Current = soorder;
15 PXRedirectHelper.TryRedirect(graph, PXRedirectHelper.WindowMode.NewWindow);
16 }
17 }
Line 10 is not returning the OrdNbr. In fact, it does not show any field from the SO, but it shows it on the grid. I need to retrieve the current ordrNbr to pass it to the SOOrder FBQL.
Line 12, as you can see I hardcoded the OrdNbr just for the purpose of testing the process.
Ensure that on the PXGrid, you have the property SyncPosition set to True. This would ensure when you click on a grid row, it "selects" it and makes it available using Current/FromCurrent.
Related
I'm writing an application in C# using Microsoft Visual Studio 2019. The application communicates with several Arduino boards. Sending and receiving works asynchronously using the TAP model, and works fine.
The application is based on a Windows Form App, using .NET Framework 4.7.2. I added a DataGridView to the form, using a DataTable as DataSource. The intention is to use this DataGridView as a data logger, showing 5 columns: TimeStamp, DeviceID, Direction, Command and ErrorStatus.
If I disable the DataGridView, I reach up to 500 commands per second on a Chinese Arduino clone. On a real Arduino I seem only to get up to 244 commands per second - see other question on stackoverflow below - but this is not the question now:
Communication speed over USB (PC/Arduino) using SerialPort in C# seems to “clip”
When I enable my DataGridView, I see communication speed dropping to about 25 commands/second, and this is purely because of the updating of the lines in the DataGridView. But that seems only the case when the DataGridView starts scrolling.
See below code snippet:
dt.Rows.Add(new string[]
{
DateTime.Now.ToString("HH:mm:ss:fff"),
device._FMGSDevice,
action,
notifyData.Command,
notifyData.notifyError.ToString()
});
if (dt.Rows.Count > maxLines)
dt.Rows.RemoveAt(0);
dt is the DataTable that is used as DataSource for the DataGridView. For every communication, a line is added at the end of the DataTable, which then automatically updates in the DataGridView.
maxLines is a constant currently set at 500. To avoid that my DataGridView gets too much lines, I limit it to 500 lines. If the limit is reached, I remove the first line with "RemoveAt(0)" after having added the new line, to keep it at maximum 500 lines.
I now see that once the DataGridView starts scrolling (the "RemoveAt(0)" causes all the lines to move up with one line), the speed goes dramatically down.
Does anyone has an idea how to speed up the scrolling? Or is there another item I could use to log? (although, I need filtering as well).
I don't know exactly your application but you can try the delete method instead of RemoveAt and see if the performances improve. it should be:
DataRow dr = dtName.Rows[0];
dr.Delete();
dtName.AcceptChanges();
Alternatively you can increase the number of record to remove, for example remove the first 10 or 20 records instead only the first.
The suggestion from #TaW worked best so far. At least, it was the easiest to implement. I have not yet experimented with Virtual Mode nor have I tried ListView, because these require quite some time to implement.
I created a derived class from DataGridView as below (see link where I found this):
Horrible redraw performance of the DataGridView on one of my two screens
class CustomDataGridView : DataGridView
{
public CustomDataGridView()
{
// if not remote desktop session then enable double-buffering optimization
if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
DoubleBuffered = true;
}
}
Because I'm using Designer, I manually changed the code there to use the CustomDataGridView class instead.
this.dgLogView = new HW_Hub.CustomDataGridView();
Although, what I'm not sure, is it allowed to change code in "...designer.cs"? I have the feeling that Visual Studio "owns" this file, and make changes automatically. Do I need another way to overrule the standard implementation?
Consider not to update the data automatically. People will be reading the data, maybe selecting parts of it. It is fairly annoying if the data that you just selected scrolls away.
It is similar to editing a document will parts that you are reading, or just selected suddenly disappear.
Add a "Refresh" button, which will refresh the data.
If you think that live updates of the data is important, so operators can see which data changes, consider to use a timer. If the timer elapses, refresh the data.
Something like this:
// the data in one Row:
class ArduinoLogData
{
... // properties that will be shown in the columns
}
BindingList<ArduinoLogData> DisplayedArduinoData
{
get => (BindingList<LoggedArduinoRow>)this.DataGridView1.DataSource;
set => this.DataGridView1.DataSource = value;
}
// Fetch ArduinoData
IEnumerable<ArduinoLogData> FetchArduinoLogdata()
{
...
}
Consider to create an overload in which you state which arduinos must be fetched, so you can update only the arduinos that are currently visible. Use DataGridViewRow.Displayed to get the ArduinoLogData that is currently displayed:
IEnumerable<ArduinoLogData> DisplayedData => this.DataGridView1.Rows
.Where(row => row.Displayed)
.Select(row => row.DataBoundItem)
.Cast<ArduinoLogData>();
And a method:
void RefreshArduinoLogData(ICollection<ArduinoLogData> itemsToRefresh)
{
... // update only these items.
}
void RefreshDisplayedArduinoLogData()
{
this.RefreshArduinoLogData(this.DisplayedData.ToList());
}
This will update only the visible items, about 40 rows or so.
Do this once a second:
Timer refreshTime = new Timer
{
AutoReset = true,
Interval = TimeSpan.FromSeconds(1).TotalMilliseconds,
};
timer.Elapsed += OnTimerTick;
timer.Enabled = true;
void OnTimerTick(object sender, ...)
{
this.RefreshDisplayedArduinoLogData();
}
Don't forget to Dispose your Timer when your Form closes, or at last when the Form is disposed.
I have a table below that contains the students' results in a DataGridView:-
ID NAME RESULT
1 Peter PASS
1 Peter SILVER
2 Sam FAIL
2 Sam SILVER
3 Simon FAIL
4 Cliff PASS
5 Jason FAIL
5 Jason FAIL
6 Leonard PASS
6 Leonard FAIL
I'm trying to produce a simple program that will filter out certain rows base on the Results upon a click of a button. What I have achieved right now is that I have able to filter out those who with PASS and/or SILVER as their Result and only display out FAIL.
The problem is right now whenever the button is clicked, it will removed the rows with a PASS and/or SILVER, except the 2nd Row: 1 Peter SILVER. Leaving me with this table below as the end result:-
The only way to resolved this right now is to click the button again.
Below is the source code for the button:-
private void btnGenerate_Click(object sender, EventArgs e)
{
if (dtList.Rows.Count != 0)
{
try
{
foreach (DataGridViewRow dr in dtList.Rows)
{
//Column names in excel file
string colID = dr.Cells["ID"].Value.ToString();
string colName = dr.Cells["Name"].Value.ToString();
string colResult = dr.Cells["Result"].Value.ToString();
if (!colResult.Equals("FAIL", StringComparison.InvariantCultureIgnoreCase))
{
dtList.Rows.Remove(dr);
}
}
}
catch
{
}
}
}
The problem is you are changing the list you are iterating over. This is never a great idea...
In this case you look at the first row (Peter/Pass) and remove it. You then look at the second row. But wait, we removed a row so the second row is in fact actually now the old third row - we have just skipped the original second row.
You don't notice this problem anywhere else because all other rows that want to be removed are followed by rows you want to keep.
The way to fix this is to either:
Create a new list with the items you want to keep and then bind
that new list to whereever you are displaying
Create a list of items that you want to remove from the datatable
while you are iterating the table. Then once you have a list of
items you want to remove iterate over that list removing them from
the datatable.
Iterate through the list with a for loop starting with the last
index. This will mean that when you remove items you only effect
those that come after which in this case you will have already
processed.
The second is probably the easiest way to go in this situation. The first involves extra code and the third may not be obvious why you are doing that to somebody that comes after you.
I have a .Net Entity Framework application. My data from DB is pulled correctly, but while displaying on the JQGRID, for some reason all of the 200 records are displayed correctly except for 1 single record (it has similar structure and data as other records )
Any ideas as to why this problem would come?
Edit : There are 2 similar records with fiscal year different, 1 has FY13, other is FY15. If I view the running website while debugging, both FY13 and FY15 records are displayed, but if I directly run the application (without debug mode ) only FY13 which is the first record order wise before FY15 is displayed and FY15 record is not displayed.
Can anyone explain this weird behavior ?
I started to use Xamarin.iOS, and the first app i'm trying to build is a Notes App, just like default Apple Notes app.
I'm using the recipe from Xamarin Recipes, and used UITableView to show the data, and TableSource class to manage cells and items.
The problem start when I want to save the data, so I will be able to load the notes after reopen the app. I'm using ADO.Net, and its working well. I tried to save the data to table contains to columns: ID & Text.
The issue is how to work with the DB table and at the same time with the UITableView.
For example: I loaded few items, let say that they will get the ID from Db: 1, 2, 3, same as they are in UITableView IndexPath. Now i'm deleting item number 2, so than item that was num 3, is now 2 in UITableView.
When trying to access and edit item number 2 (old 3) - Can't find him in the DB.
The reason for the problem is known, but how to fix it - I really dont know.
Any suggestion will be great.
Thanks, Tal.
you are doing little wrong lets start say you have your record id is unique may be 1 - 2 - 3
you now forget about indexPath just focus on your record id,
load the data and now you have deleted the record 2, no problem edited your data id 3 and updated into DB, but for this you have to use array of dictionary so that eavery record have there property like
id and message so you always update the Right dataset
I use SpecFlow with Coded UI to create some automated functional tests for a WPF application.
Let's see the following SpecFlow scenario:
Scenario: Issue
When Results button is pressed
When Result 123 is selected
When Results button is pressed
When Result 123 is selected
1st and 3rd row parameter: Results
2nd and 4th row parameter: 123
Here are the methods for the upper mentioned steps:
When Results button is pressed
public void PressButton(string buttonName)
{
WpfButton uIButton = this.UIAUT.UIButton;
uIButton.SearchProperties[WpfButton.PropertyNames.Name] = buttonName;
uIButton.WaitForControlEnabled();
Mouse.Click(uIButton);
}
When Result 123 is selected
public void SelectResultByID(string resultId)
{
WpfListItem uIResult = this.UIAUT.UITier1List.UITier2ListBox.UITier3ListItem;
var allResults = uIResult.FindMatchingControls();
foreach (WpfListItem item in allResults)
{
string[] elem = item.GetChildren().GetNamesOfControls();
if (elem[0] == resultID)
{
Mouse.Click(item);
}
}
}
The first three rows are OK. When the 4th step When Result 123 is selected is executed again var allResults = uIResult.FindMatchingControls(); is empty so the foreach part is skipped, no action is taken and the test is passed.
Could someone tell me what is wrong? It is obvious that I miss something.
Assuming you code is generated by recording (or is similar) then I would suspect the "cacheing" nature of the higher level UI Controls. The application may draw one UI Control containing the first 123 and draw another UI Control for the second 123. These controls look identical but are different and have different window-ids (or handles or whatever). One of the UI Controls in
WpfListItem uIResult = this.UIAUT.UITier1List.UITier2ListBox.UITier3ListItem;
probably refers to the UI Control of the first 123 even though it is no longer on display. I suspect UITier3ListItem or its child controls; if it were ...1... or ...2... then I would expect a failure message rather than zero matches.