What im wondering how to do is when someone edits a list item and it goes through my event code that is fired when a change is made and save is hit, i dont want anyone to be able to edit that list item itself while its still processnig that request. So i was wondering if while in that event i can disable the individual item from being edited by someone else untill it is done doing what it is doing.
Not sure if I understand exactly what you are want.
Try adding a field, hidden if you like, to the list or content type to use as a flag. When you enter your event code, make sure you check the flag first and if not set, set it and do your stuff. After you have done your stuff, unset the flag.
Here is some code to illustrate. Note that I have used a column named "updating". You can use the properties of the SPListItem as well if you do not care to add a column.
Oh, and don't forget to call DisableEventFiring before you to SPListItem.Update and then EnableEventFiring() afterwards. For get this and you will have a very nasty infinite loop on your hands.
.b
public override void ItemAdding(SPItemEventProperties properties)
{
if (properties.ListItem["updating"].ToString() == "updating")
{
properties.Cancel = true;
properties.ErrorMessage = "Item is currently updating, please try again later";
}
else
{
properties.ListItem["updating"] = "updating";
this.DisableEventFiring();
properties.ListItem.Update();
this.EnableEventFiring();
// do your stuff
properties.ListItem["updating"] = "";
this.DisableEventFiring();
properties.ListItem.Update();
this.EnableEventFiring();
}
}
I have no doubt that Bjørns solution will work but you have to be very carefull when implementing it.
Pls. remember at your updating method should include a "finally" that resets the flag, no matter which exception gets thrown, other wise your list will be locked down for ever :-(
Related
Consider the following code:
public class TestClass
{
public int? NullableInt { get; set; }
private bool DoPreChecks()
{
if(NullableInt == null)
return false;
return true;
}
public bool DoTest()
{
if(!DoPreChecks())
return false;
//Here R# tells me that "nullableInt" may be null
if (NullableInt.Value > 10)
{
// Do something
}
return true;
}
}
R# would be correct to worry that "NullableInt.Value" may be null when I reference it in "DoTest", except that if it was, then "DoPreChecks" would have returned false and that means I would never have gotten to this line. I was looking at R#'s code annotations and I see I can tell it what output to expect under limited conditions and it seems like that may be something I could leverage here, but I don't see any way to tell it that when the output is true/false/null/notnull, then a class variable (which has nothing to do with the input or output) will have a certain value type (true/false/null/notnull). Can something like this be done?
The use case here is this -- I have a dozen methods that all rely on the same preconditions, including several class variables being initialized. Rather than putting all those checks in each method, I want to have them all run the "DoPreChecks" method and if it returns true, we're good to go. The problem is that R# can't follow that and thinks I have lots of possible null reference exceptions. I could:
Ignore the errors completely and just tolerate wiggly lines everywhere
Disable and restore the warning at the beginning and ending of these methods
Disable the warning 1 line at a time
Do null checks or assertions before each use
The problem with each is...
Violates company policy to just ignore warnings
Disabling this check over large swaths of code would be worse than ignoring individual warnings because other valid issues may be there, but get disabled
This would require a LOT of R# comments, thus negating the helpfulness of DoPreChecks method
Same as #3
Right now I'm leaning toward getting an exception on the policy and just ignoring the warnings, but if there is a way to tell R# what is going on, that would be a much better solution. Can it be done without adding parameters or complicating the return type?
There is no contract annotation in ReSharper that sets up a relation between return value of a method and nullness of a field/property
I am getting an Excel spreadsheet with columns but, no data when I click on the Excel icon on a grid.
I have put a grid on the CR306030 page that is tied to a view of a custom DAC that relates back to the CRActivity record for the page. I have set the SkinID to Inquire and the AllowImport = true. The view in my Graph extension class looks like this:
[PXImport(typeof(CRActivity))]
public PXSelect<MyDac,
Where<MyDac.activityNoteID,
Equal<Current<CRActivity.noteID>>>> MyDacView;
I'm not sure what I am missing. I am trying to export the data in the grid so, I may be way off here.
TIA!
This happened because I had an update() call inside of a FieldSelecting() event handler. This, for some reason, caused the export to quit working. This presents another problem for me that I will post in another question but, the export issue is resolved. Here's what my code looked like in the extended graph that was causing the issue:
protected virtual void CRActivity_UsrCustomField_FieldSelecting(PXCache cache, PXFieldSelectingEventArgs e)
{
CRActivity activity = (CRActivity) e.Row;
CRActivityExt activityExt = activity.GetExtension<CRActivityExt>();
// Some code here.
e.ReturnValue = TotalValue;
activityExt.UsrCustomField = TotalValue;
Base.Events.Update(activity);
}
I changed it to this in order to get the export working:
protected virtual void CRActivity_UsrCustomField_FieldSelecting(PXCache cache, PXFieldSelectingEventArgs e)
{
CRActivity activity = (CRActivity) e.Row;
CRActivityExt activityExt = activity.GetExtension<CRActivityExt>();
// Some code here.
e.ReturnValue = TotalValue;
//activityExt.UsrCustomField = TotalValue;
//Base.Events.Update(activity);
}
Adding Export button is all that should be required. Setting SkinID to inquire will do that for you.
It seems you are running into an uncommon scenario so I would suggest to rollback tentative solutions like adding Import functionality that isn't required in case your implementation has errors causing conflicts with export functionality.
Next issue I would suspect is a kind of security/rights issues or an explicit call to disallow exporting records. Removing unnecessary code and substituting the DAC you are using could help expose the root cause as some specific entity could have been locked down by security while others aren't.
If you're familiar with Acumatica web services it could be worth a shot to test if records from the grid can be retrieved by web service. If they can't then that points towards security/rights issues.
I'm trying to detect if a module has gone "stale" in Geb. That is, if using will throw:
org.openqa.selenium.StaleElementReferenceException
The below code seems to work, but I feel like its excessively hacky (I'm just calling any arbitrary method on module (toString() seemed like a decent choice) and checking if it throws the stale element exception.
static boolean isStale(Module module)
{
boolean isStale = false
try {
module.toString() // arbitrary method call
} catch (StaleElementReferenceException e) {
isStale = true
}
return isStale
}
Is there a cleaner way to do this?
If you are trying to detect page changes, however arbitrary those pages are then I would probably tackle it the other way around - detecting the new content and not the stale content. First, you have to find something (an element or a state of an element) that you can use in your at checker to detect that the new page has "loaded". Then you would execute the page changing action and wrap an at checker verification inside of a waitFor {} call. This should be more reliable than your current approach, especially because Geb doesn't cache any content elements by default.
Disclaimer (fully editable/removable)
I've done my homework but to the best of my recognition, I can't see the very thing I'd like to know (which is a bit surprising, so I'm sure that a kind soul will flag me as a duplicate - please accept my apology in advance, haha).
Background and anticipated issue
When I start Outlook, I'm performing an update from CRM Dynamics, which takes a while. So, I decided to put the update in a thread. It works as supposed to but there's a button on the ribbon allowing a user to manually call for an update. Anticipating a frantic user, I realize that someone will click the button before the original update is finished and all kinds of excrement may hit the gas redistributive device.
Suggested solution
In order to avoid that, I've put a private property as follows.
private bool KeepYourPantsOn { get; set; }
As long as the said property is true (which it is set to right before I start the updating thread), all the frantic clicking will be either ignored or treated by a calm and informative
MessageBox.Show("Yes, yes... Updating still... Keep your pants on.");
but as soon as the thread is done, I'd like the property to flip over to false enabling the user to manually update Outlook.
Implementation problem
My hick-up is that I haven't found any OnFinished, WhenDone etc. method to call in order to switch the value of KeepYourPantsOn. Moreover, I haven't really seen any suggested solution on how to resolve that (or, rather - I haven't perceived any solution - I might have seen one without realizing that was it, due to ignorance within the area of threaded programming).
You should be able to just set the bool to false as the last line in your thread (or as the last line before looping back to wait on something, if your thread does that).
Note #Tudor comment regarding volatile - just to be sure, do it.
You can create a backing store for your property to hold the value and use a lock whenever you set or get the value to ensure that no concurrency issue arises.
After that, when you start processing on a separate thread, set the value to true and before exiting the method set the value to false.
On user click just check the value of KeepYourPantsOn property and display the message if it is still true.
class YourClass
{
private static readonly object _syncRoot = new object();
private bool _keepYourPantsOn;
public bool KeepYourPantsOn
{
get
{
lock(_syncRoot)
{
return _keepYourPantsOn;
}
}
set
{
lock(_syncRoot)
{
_keepYourPantsOn = value;
}
}
}
private ThreadMethod()
{
KeepYourPantsOn = true; //signal that the update process is starting...
// perform your logic
KeepYourPantsOn = false; //signal that the update process is finished
}
public ManualUpdate()
{
if(KeepYourPantsOn)
MessageBox.Show("Yes, yes... Updating still... Keep your pants on.");
else
Update();
}
}
I'm new to Sharepoint and I'm currently maintaining an established solution which has a bug. Unfortunately I cannot solve the Problem. I get an SPException with ErrorCode 2130575305 in the ItemAdded event when I try to use the properties.ListItem.Update() Method.
It seems like there is a Problem when updating a item shortly after it is updated?
I tried everything I found on the Internet, from using the "ItemAdding" method over allowunsafeupdates to disableeventfiring, but nothing worked, now I ran out of steam
A little piece of program code:
SPListitem itm = list.GetItems(query).Add();
// all single line of text
itm["property"] = anotheritem["property" + "something" + itm["property"];
itm.Update();
and afterward in the overridden ItemAdded:
SPListItem itm = properties.ListItem;
itm["anotherproperty"] = "something different";
itm.Update(); // <- this throws the error
The Original Error Message is in German so it won't help you much, but its saying something along "SPException, please press back in your browser and try again", which isn't of any help anyways.
Also, I can't use try catch in code as it seems to be some sort of web exception?
Sorry x0n, I couldn't try your answer yesterday.
it doesn't work, unfortunately, there is no list in properties, only a listid, and even if I know which list calls the itemadded event and navigate to it through lists["listname"].getitembyid(properties.listitem.id) it won't work.
isn't "grapping a fresh copy" exactly what i did by writing splistitem itm = properties.listitem; already?
Is there a way to "release" the item on the beginning of the itemAdded and reuse it later?
public override void ItemAdded(SPItemEventProperties properties)
{
SPListItem itm = properties.ListItem;
itm["somefield"] = "sometext";
itm.Update(); // <- error, itm.SystemUpdate() throws the same error btw.
base.ItemAdded(properties);
}
I also read the help on msdn, it only tells me the error but not how to handle it, so it wasn't much helpful.
About brian's answer: if itemadded already is the synchronous call there shouldn't be a problem?
When you receive error codes the best resource is MSDN or google. - http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.listitem.update.aspx
The error code means the field is read only, which could mean many things. This could be due to permissions of the executing account or a simple race condition.
SharePoint essentially queues up a lot of changes and therefore you can certainly run into timing issues between the different executing threads. If you are changing an item in a sync event(adding) and then again in the async(added) event I would strongly lean towards rethinking the logic of what you are trying to actually do.