May i know how to update the second element's attribute using linq to xml? I do write some code but it doesnt work, it only update the user attribute....I'm sorry for asking this kind simple question.
My XML:
<Settings>
<Settig>
<User id="1" username="Aplha"/>
<Location Nation="USA" State="Miami" />
<Email>user1#hotmail.com</Email>
</Setting>
</Settings>
My Cs :
public static void saveSetting(MainWindow main)
{
XDocument document = XDocument.Load("Setting.xml");
IEnumerable<XElement> query = from p in document.Descendants("User")
where p.Attribute("id").Value == "1"
select p;
foreach (XElement element in query)
{
string i = "New York";
element.SetAttributeValue("State", i);
}
document.Save("Setting.xml");
}
You want to select the Setting elements; you can still select on id=1, like this:
IEnumerable<XElement> query = from p in document.Descendants("Setting")
where p.Element("User").Attribute("id").Value == "1"
select p;
Then select the Location element before updating:
foreach (XElement element in query)
{
element.Element("Location").SetAttributeValue("State", "New York");
}
Related
How to display popup exceptions instead of the one with a red dot on the row for the line items? I was able to have them in RowInserting for a little bit but after a series of code changes I get the red dot one instead. It even did not create a new row as I wanted but now it does. RowInserting event:
protected virtual void SOLine_RowInserting(PXCache sender, PXRowInsertingEventArgs e)
{
var listMissingOEdesc = new List<int>();
var select = Base.Transactions.Select();
foreach (SOLine row in select)
{
var isOEDesc = IsOEDescEnabled(sender, row);
var rowExt = PXCache<SOLine>.GetExtension<SOLineExt>(row);
if (isOEDesc == true)
if (rowExt.UsrOedesc == null)
listMissingOEdesc.Add(row.SortOrder.Value);
}
if (listMissingOEdesc.Count > 0)
{
throw new PXException("Line items with sort order {0} do not have OE Desc filled out. Cannot add a new line.", string.Join(", ", listMissingOEdesc));
}
else
Base.Actions.PressSave();
}
Thanks!
There is no easy way, if any at all, to display popup exception and prevent the grid from inserting a new row. The way the framework is designed, PXGrid first inserts a new row on the webpage. After that PXGrid sends a callback to the application server either requesting default field values for the new row (if PXGrid's Mode has InitNewRow="True") or sends all values captured from the webpage to the application server, so the new row can be inserted in the PXCache. Whenever an event handler, on the field or row level, gets invoked, the new row will still be visible to the user on the web page. Even if you invoke Ask method on the Transactions data view within one of the event handlers, the new row won't disappear from the webpage.
With all that said, the best and probably the only way to display popup exception and prevent the grid from inserting a new row is by replacing the standard Add New Row button on PXGrid with a custom action, which will first run the validation and display popup exception, if necessary. Otherwise, a new row will be inserted into PXGrid. It's also required to enable or disable the custom NewSOTran action based on the state of the standard PXGrid's Insert button.
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
public void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
NewSOTran.SetEnabled(Base.Transactions.AllowInsert);
}
public PXAction<SOOrder> NewSOTran;
[PXButton(CommitChanges = true)]
[PXUIField]
protected void newSOTran()
{
var listMissingOEdesc = new List<SOLine>();
var select = Base.Transactions.Select();
foreach (SOLine row in select)
{
var isOEDesc = !string.IsNullOrEmpty(row.TranDesc);
if (isOEDesc == true)
listMissingOEdesc.Add(row);
}
if (listMissingOEdesc.Count > 0)
{
throw new PXException("Cannot add a new line.");
}
var newTran = Base.Transactions.Insert();
Base.Transactions.Cache.ActiveRow = newTran;
}
}
In Aspx there will required 3 major chages:
SyncPositionWithGraph property set to True for PXGrid:
<px:PXGrid ID="grid" runat="server" DataSourceID="ds" Width="100%" TabIndex="100"
SkinID="DetailsInTab" StatusField="Availability" SyncPosition="True" Height="473px"
SyncPositionWithGraph="True" >
the standard AddNew action must be replaced by a custom NewSOTran action:
<ActionBar>
<Actions>
<AddNew ToolBarVisible ="False" />
</Actions>
<CustomItems>
<px:PXToolBarButton CommandName="NewSOTran" CommandSourceID="ds"
DisplayStyle="Image">
<Images Normal="main#AddNew" />
<ActionBar GroupIndex="0" Order="2" />
</px:PXToolBarButton>
...
</CustomItems>
</ActionBar>
AllowAddNew property set to false in the Mode section of PXGrid to prevent the standart Insert button from execution when users use keyboard shortcuts or double-click on PXGrid:
<Mode InitNewRow = "True" AllowFormEdit="True" AllowUpload="True" AllowDragRows="true"
AllowAddNew="false" />
To select new records’ first cell and switch it to the edit mode (unless the first cell is read-only), it's also required to subscribe to the Initialize and ToolsButtonClick client events of PXGrid:
<ClientEvents Initialize="initTransactionsGrid"
ToolsButtonClick="transactionsGriduttonClick" />
and define the following JavaScript functions:
var isInitEvents = false;
function initTransactionsGrid(a, b) {
if (isInitEvents) return;
isInitEvents = true;
a.events.addEventHandler("afterRepaint", editNewSOTran);
}
function editNewSOTran() {
if (lastActiveRowIndex != null) {
var grid = px_alls["grid"];
if (grid.activeRow) {
var activeRowIndex = grid.rows.indexOf(grid.activeRow);
if (activeRowIndex != lastActiveRowIndex) {
grid.activeRow.activateCell(0, false);
grid.beginEdit();
}
}
lastActiveRowIndex = null;
}
}
var lastActiveRowIndex;
function transactionsGriduttonClick(sender, args) {
if (args.button && args.button.commandName == "NewSOTran") {
if (sender.activeRow)
lastActiveRowIndex = sender.rows.indexOf(sender.activeRow);
else
lastActiveRowIndex = -1;
return;
}
lastActiveRowIndex = null;
}
To package custom JavaScript code into customization, in Layout Editor you can drag and drop a Java Script element from the Add Controls tab and copy your entire JavaScript code into the Script property.
I'm customizing the Approve Time Card Summaries screen to do the following:
1.) Add a checkbox to the filter section
2.) When this checkbox is checked, don't show the 'Approved' rows in the grid.
I've added a cache extension with a new unbound boolean field, and added the checkbox to the filter / header section of the screen.
What I'm wondering is - Is there an IEnumerable method (can I use 'summary'?) that can check that header filter field and only yield return the rows that pass the filter test? If so, I'm not sure what the syntax would be to do this.
Or - would it be better to rewrite the Summary view select statement in the Graph extension with the added where clause?
Thanks...
I figured out how to do this. In the Graph extension, I rewrote the 'Summary' view and then used the IEnumerable 'summary' delegate to return only the rows where it meets the checkbox criteria I set up. To wit:
public PXSelectJoin<EPSummaryApprove
, LeftJoin<EPEarningType, On<EPEarningType.typeCD, Equal<EPSummaryApprove.earningType>>>
, Where2<Where<EPSummaryApprove.taskApproverID, Equal<Current<EPSummaryFilter.approverID>>, Or<Where<EPSummaryApprove.taskApproverID, IsNull, And<EPSummaryApprove.approverID, Equal<Current<EPSummaryFilter.approverID>>>>>>
, And2<Where<EPSummaryApprove.weekId, GreaterEqual<Current<EPSummaryFilter.fromWeek>>, Or<Current<EPSummaryFilter.fromWeek>, IsNull>>
, And2<Where<EPSummaryApprove.weekId, LessEqual<Current<EPSummaryFilter.tillWeek>>, Or<Current<EPSummaryFilter.tillWeek>, IsNull>>
, And2<Where<EPSummaryApprove.projectID, Equal<Current<EPSummaryFilter.projectID>>, Or<Current<EPSummaryFilter.projectID>, IsNull>>
, And2<Where<EPSummaryApprove.projectTaskID, Equal<Current<EPSummaryFilter.projectTaskID>>, Or<Current<EPSummaryFilter.projectTaskID>, IsNull>>
, And<Where<EPSummaryApprove.employeeID, Equal<Current<EPSummaryFilter.employeeID>>, Or<Current<EPSummaryFilter.employeeID>, IsNull>>
>
>
>
>
>
>
> Summary;
protected IEnumerable summary()
{
var epsf = (EPSummaryFilter)Base.Filter.Cache.Current;
var epse = PXCache<EPSummaryFilter>.GetExtension<EPSummaryFilterExt>(epsf);
foreach(var res in Base.Summary.Select())
{
var sum = (EPSummaryApprove)res;
if (epse != null)
{
if (epse.ExcludeApproved == true)
{
if (sum.IsApprove != true)
{
yield return res;
}
}
else
yield return res;
}
else
yield return res;
}
}
I'm using C# to modify a view within a photo library across my sharepoint 2013 farm where there are around 600 sites at the moment.
I'm using the method
olist.Views.Add("AllPictures", strColl, sQuery, 40, true, true,Microsoft.SharePoint.SPViewCollection.SPViewType.Html, false)
and basically I'm trying to recreate the main "All Pictures" view as running a routine to switch this view to a grid has caused this view to no longer display anything. My problem is that once I've deleted the view and run the code above it will create a new All Pictures view that has a baseviewid of 6 so the photos appear as thumbnails rather than a table with the details of the photo. I need to be able to specify the baseviewid as 1 but I've not yet found a way to do this.
Solution:
Use code which I found here http://stefan-stanev-sharepoint-blog.blogspot.co.uk/2010/02/listviewwebpart-spview-two-sides-of.html in the comments section. I hope Stefan doesn't mind me copying some of it here.
Important to note is that the wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper(); line is commented out because otherwise it will use the baseviewid of the current default view which is 6
which is exactly what we don't want.
The code gets the Photos and Videos list, then gets all the web parts that the list uses, when it gets the AllPictures web part it then saves it for later deletion, adds a new listviewwebpart (but at this stage we can
only add the baseviewid), then deletes the current web part (it seems to only work well in this order) and then gets the hidden view that is created, see stefan's blog for more details.
The second call to Program.UseList then resets some of the view back to how it should look if there is a baseviewid of 1, for this I look at another site with a baseviewid of 1 and checked in sharepoint designer at the XmlDefinition
to see exactly what the xml should look like.
Hope this helps someone else out.
public void LibraryCode(string url)
{
Guid hiddenViewGuid = Guid.Empty;
SPList library = null;
string listUrl = "Photos1/Forms/AllPictures.aspx";
Program.UseList(url, listUrl, list =>
{
SPFile file = list.ParentWeb.GetFile(listUrl);
Guid listID = file.ParentFolder.ParentListId;
if (!listID.Equals(Guid.Empty))
{
library = list.ParentWeb.Lists[listID];
if (library.ForceCheckout && file.Level != SPFileLevel.Checkout) file.CheckOut();
}
SPLimitedWebPartManager mngr = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
SPLimitedWebPartCollection webparts = mngr.WebParts;
System.Web.UI.WebControls.WebParts.WebPart op = null;
for (int k = 0; k < webparts.Count; k++)
{
//get reference to webpart
op = webparts[k];
//check webpart Title to find webpart whose value is to be changed
if (op.Title.Equals("AllPictures"))
{
break;
}
}
XsltListViewWebPart wp = new XsltListViewWebPart();
wp.ListName = list.ID.ToString("B").ToUpper();
//comment out the line below or the new view gets the same baseviewid as
//wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
wp.XmlDefinition = "<View BaseViewID='1'/>";
mngr.AddWebPart(wp, "Left", 1);
//remove existing web part otherwise there will be two tables of the data on the same page
mngr.DeleteWebPart(op);
hiddenViewGuid = new Guid(wp.ViewGuid);
});
Program.UseList(url, listUrl, list =>
{
SPView view = list.Views[hiddenViewGuid];
view.Title = "All Pictures";
view.Update();
// load the passed viewSchema in an XmlDocument
XmlDocument doc = new XmlDocument();
doc.LoadXml(view.HtmlSchemaXml);
// set the Name attribute with the ID of the hidden LVP's SPView - we use a simple trick to update the full schema of the hidden view
XmlElement root = doc.DocumentElement;
root.SetAttribute("Name", view.ID.ToString("B").ToUpper());
root.SetAttribute("BaseViewID", "1");
root.SetAttribute("Type", "HTML");
root.SetAttribute("Hidden", "False");
// do some changes to the view schema
XmlElement viewFieldsEl = doc.SelectSingleNode("//ViewFields") as XmlElement;
if (viewFieldsEl != null) { viewFieldsEl.InnerXml = #"<FieldRef Name=""DocIcon""/>
<FieldRef Name=""LinkFilename""/>
<FieldRef Name=""ImageSize""/>
<FieldRef Name=""FileSizeDisplay""/>
<FieldRef Name=""Modified""/>
<FieldRef Name=""RequiredField"" Explicit=""TRUE""/>
<FieldRef Name=""PreviewOnForm"" Explicit=""TRUE""/>
<FieldRef Name=""ImageCreateDate""/>
<FieldRef Name=""Project_x0020_Tags""/>
<FieldRef Name=""_Comments""/>
<FieldRef Name=""Originator""/>"; }
XmlElement javascriptEl = doc.SelectSingleNode("//JSLink") as XmlElement;
if (javascriptEl != null) { javascriptEl.InnerXml = "clienttemplates.js|callout.js"; }
// create a dummy view to hold the new schema
SPView cloneView = new SPView(list, doc);
// a small trick with reflection so that we can update the dummy view
typeof(SPView).GetField("m_bExistsInDatabase", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(cloneView, true);
// this will actually update the hidden SPView associated with the LVP
cloneView.Update();
if (library != null)
{
SPFile file = list.ParentWeb.GetFile(listUrl);
if (library.ForceCheckout) file.CheckIn("");
if (library.EnableMinorVersions) file.Publish("");
if (library.EnableModeration) file.Approve("");
}
});
}
I need to assign a filtered list to another list, however I do not know the list structure that will filter, just know the parameter for the filter. It Only returns an SPListItemCollection and I need to return a SPList.
Below follows method in which capture the list, I need to return a list, but filtered by query:
/// <summary>
/// reads the list to display
/// </summary>
/// <returns></returns>
public SPList GetListFromProjectWorkSpace()
{
SPList list = null;
Guid projUID = _helper.GetProjUID();
if (projUID == Guid.Empty)
{
return list;
}
// read project data
IProjectWssInfoDataSet dataset = _service.ReadWssData(projUID);
if (dataset.ProjWssInfo.Count == 0)
{
return list;
}
// get workspace name and url
string workspaceName = dataset.ProjWssInfo[0].WorkspaceName;
string workspaceUrl = dataset.ProjWssInfo[0].WorkspaceUrl;
SPSecurity.RunWithElevatedPrivileges(()=>
{
using (SPSite site = new SPSite(workspaceUrl))
{
for (int i = 0; i < site.AllWebs.Count; i++)
{
if (!site.AllWebs[i].ServerRelativeUrl.Contains(workspaceName))
{
continue;
}
try
{
list = site.AllWebs[i].Lists[SelectedList];
}
catch
{
}
}
SPQuery query = new SPQuery();
query.Query = #"<Where>
<Contains>
<FieldRef Name='LinkFilenameNoMenu' />
<Value Type='Computed'>work</Value>
</Contains>
</Where>";
SPListItemCollection itens = list.Items.List.GetItems(query);
// I need help here
}
});
return list;
}
att,
Eduardo
There is no method to “assign a list into another list”. You have to understand the fundamental distinction between list metadata and list content (items):
SPList represents the metadata of a list;
SPListItemCollection contains particular items of a list — its data.
In case you need to copy the (filtered) content of one list into another list, you have to understand the structures (permitted content types, fields) of both lists and copy the items one by one (with possible data transformations).
Note: to get the list's metadata knowing a collection of its items, there the SPListItemCollection.List property.
I have a website in Sharepoint 2007. I want to make a query where the field "home" of the webpages is equal to 1 in one specific SPWeb and (this is the important part) its sub-SPwebs.
I can make this work with the site in question and not with the subsites. That is to say: It is not recursive but I indicate it in the "webs scope='recursive'" clause.
I include also the List I want to use, that is to say, the pages (not documents, master pages or whatever) this is whay i look for the "850" basetemplate (the one for pages).
The code I am using is this (i have tried with other methods with the same query and the result is the same):
string campo="home";
SPSiteDataQuery qry = new SPSiteDataQuery();
qry.Query = "<Where><Eq><FieldRef Name='";
qry.Query += campo + "'/><Value
Type='Boolean'>1</Value></Eq>";
qry.Query += "</Where><OrderBy><FieldRef
Name='Modified' Ascending='false'> />";
qry.Webs = "<Webs Scope='Recursive'/>";
qry.ViewFields = "<FieldRef Name='Title'/><FieldRef
Name='Modified'/>";
//this gives me system privileges
using (SPSite site = new SPSite(CurrentSite.ID,
GetSystemToken(CurrentSite)))
{
using (SPWeb web = site.OpenWeb("/News/"))
{
StringBuilder sb = new StringBuilder();
sb.Append("<Lists>");
foreach (SPList list in web.Lists)
{
if (list.BaseTemplate.ToString() ==
"850")
{
sb.Append("<List ID=\"" +
list.ID.ToString() + "\"/>");
}
}
sb.Append("</Lists>");
qry.Lists = sb.ToString();
dt = web.GetSiteData(qry);
..................
So, the only solution I found was to make a loop after the precedent code through the Webs but i don't think this is a very optimized way:
foreach (SPWeb w2 in web.Webs)
{
sb = new StringBuilder();
sb.Append("<Lists>");
foreach (SPList list in w2.Lists)
{
if (list.BaseTemplate.ToString()
== "850")
{
sb.Append("<List ID=\""
+ list.ID.ToString() + "\"/>");
}
}
sb.Append("</Lists>");
qry.Lists = sb.ToString();
DataTable dttmp = w2.GetSiteData(qry);
if (dttmp != null
&& dttmp.Rows.Count > 0)
{
dt.Merge(dttmp);
}
w2.Dispose();
}
Finally I did the following, i don't know what has worked finally, i have changed the way I ask the Lists and i have included RowLimit:
DataTable dt = null;
DataView dv = null;
SPSiteDataQuery qry = new SPSiteDataQuery();
qry.Query = "<Where><Eq><FieldRef Name='";
qry.Query += campo + "'/><Value Type='Boolean'>1</Value></Eq>";
qry.Query += "</Where><OrderBy><FieldRef Name='Modified' Ascending='false' /></OrderBy>";
qry.Webs = "<Webs Scope='Recursive'/>";
qry.Lists = "<Lists ServerTemplate='850' Hidden='FALSE' MaxListsLimit='50'/>";
qry.RowLimit = 3;
qry.ViewFields = "<FieldRef Name='Title'/><FieldRef Name='Modified'/><FieldRef Name='FileRef'/>";
using (SPSite site = new SPSite(CurrentSite.ID, GetSystemToken(CurrentSite)))
{
using (SPWeb web = site.OpenWeb(webUrl))
{
dt = web.GetSiteData(qry);
dv = dt.DefaultView;
}
}
return dv;
You talk about setting the webs scope to recursive, but in your (ill-formatted) example code you leave the webs property blank, meaning the site data query will only search through the specified web.
This specific (omitted) detail of your code is very important, because making even the slightest spelling mistake in the innerXML specification will silently revert the behaviour back to the default, meaning only the current web will be searched. A typical pitfall would be getting the capitalization wrong in either Webs or Scope.
For the record, the correct way of specifying this is
qry.Webs = "<Webs Scope='Recursive' />";
As a quick check, you can try setting the scope to SiteCollection, see if that works.
[Edit] Agreed, now your Webs property shows up it seems fine :-). Have you tried setting the Nullable='TRUE' attribute in the fieldref of the Campo field? If the field isn't present (or corrupted or whatever) in any of the subsites, that might help. [/Edit]