I'm using the VSTA C# on an infopath 2010 form, whereby by using cascading drop downs (Course Title & Course Details) information is displayed.
So when a user selects the Course Title drop down, the Course details is populated with the StartTime, EndTime, Location and Development Category information from a Sharepoint 2010 list.
Now the problem I have is that I want the user to only view the course details for today and onwards, and not view course details for the past. This is the code whereby I display the coursedetails. I've tried declaring a dateTime variable and using it to compare with a string that converts to DateTime with Today, to make it later than the DateTime variable, but it gives me an error after I select a course title, it says "Object Reference not set to an instance of an object". With the troubleshooting tips: "Use the new keyword to create an object instance. Check to determine if the object is null before calling the method. Get gengeral help for this exception"
using (web = site.OpenWeb())
{
try
{
//SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(delegate()
//{
SPList lstDocs = web.Lists["Training Calander"] as SPList;
string sTitle = "";
string sSDate = "";
string sEDate = "";
string sLocation = "";
string SDCategory = "";
string CourseDetails = "";
//DateTime TodayDate = DateTime.Today;
//DateTime dt1 = Convert.ToDateTime(sEDate);
if (lstDocs != null)
{
SortedList<string, string> lstDetails = new SortedList<string, string>();
foreach (SPListItem item in lstDocs.Items)
{
try
{
sTitle = item["Title"].ToString();
sSDate = item["StartTime"].ToString();
sEDate = item["EndTime"].ToString();
sLocation = item["Location"].ToString();
SDCategory = item["Development Category"].ToString();
}
catch { }
if (sTitle == nValue) //&& (dt >= TodayDate))
{
try
{
CourseDetails = sSDate + " - " + sEDate + " | " + sLocation + " | " + SDCategory;
lstDetails.Add(CourseDetails,CourseDetails);
}
catch { }
}
}
I believe the problem is best solved before you execute your foreach loop. You need to create a query that will select only the Items that meet your criteria using a Where clause. They you can iterate through your loop without having to test the date on each pass, which is going to be slower.
Assuming Startdate is stored as a date variable, this should be a trivial query to write.
Apologies if I have misunderstood your issue.
foreach (SPListItem item in lstDocs.Items.Where(item => item.StartTime.Date >= DateTime.Now.Date))
This is assuming there is a property called StartTime in the SPListItem class and that you are using .NET 3+ and have access to Linq.
Related
I have a scenario where I am supposed to add a feature to the existing code and this feature is supposed to take input of from the user and form a string. Right now by default the code ships with full name = firstname and lastname. But I am supposed to make it configurable according to user demand, where the user can add any property like location or phone number to display with the full name. So for e.g the format can be [firstname + lastname + location or lastname + firstname + phonenumber ].
And I have managed to take the users input and store it in a variable called test and here is the code for it.
[DataMember]
public string FullName
{
get
{
string test = "";
test = Services.GetService<IGlobalOptionsBrokerDataAccess>().test1();
return string.Format("{0} {1} {2}", this.FirstName, this.MiddleName, this.LastName);
}
set
{
_fullName = value;
}
}
So how can I make it work dynamically? Here the screenshot of how the value is available in the test variable. If the user wants to have ManagerID then how can I make it work dynamically?
Is there anything more I should provide so that it would be easier for you guys out there?
May not be an optimal solution, but this is what I thought of quickly. Making your format string dynamic could help you.
var posDict = new Dictionary<string, string> {
{"FirstName","{0}" },
{"MiddleName","{1}" },
{"LastName","{2}" }};
var test = "FirstName,LastName,MiddleName";
var posString = "";
foreach (var prop in test.Split(','))
posString += $"{posDict.First(x => x.Key == prop).Value} ";
return string.Format(posString, this.FirstName, this.MiddleName, this.LastName);
I found a better solution other than the mentioned above.
string[] columnNames = format.Split(new char[] { ',' });
string userFullNameAsPerFormat = string.Empty;
string defaultFullName = this.FirstName + " " + this.LastName;
// Get the Type object corresponding to MyClass.
Type myType = typeof(Courion.BusinessServices.Access.ProfileDTO);
// Get the PropertyInfo object by passing the property name.
PropertyInfo myPropInfo = myType.GetProperty(item.Trim());
userFullNameAsPerFormat += (string) myPropInfo.GetValue(this) + " ";
I'm making an app in Windows Forms that simulates a Point of Sales. I'm creating now the part where the user clicks on a product button and it adds to a listbox an item like this: "'Quantity' - 'Name of the product' - 'cost'".
When the button is clicked again is supposed to edit the item like this: "'Quantity+1' - 'Name of the product' - 'cost*2'".
However it just add another item with that information.
So far, my code is the following:
private void bprod1_Click(object sender, EventArgs e)
{
MySqlCommand cmdp1 = new MySqlCommand("SELECT preco_unitario FROM produtos where designacao='" + bprod1.Text + "';", mConn);
mConn.Open();
MySqlDataReader drp1 = cmdp1.ExecuteReader();
drp1.Read();
string getpreco1 = drp1["preco_unitario"].ToString();
mConn.Close();
quant1 = quant1 + 1;
var preco1tot = quant1 * Convert.ToDecimal(getpreco1);
var text1 = quant1.ToString() + " - " + bprod1.Text + " - " + preco1tot.ToString();
listvenda.Items.Add(text1);
}
bprod1 is my button. quant1 starts with value 0. getpreco1 is the value I get from the database (product's cost).
My objective is, when clicked the second time and so on, increase the quantity and add the cost without creating a new item.
I could just delete the item and add another one with the new info, but I want the item to be in the same place as the other, and not on the end of the list.
I appreciate any suggestions and help.
Hope you guys understand what I intend to do.
This line:
listvenda.Items.Add(text1);
is why you're seeing a new item every single time. A mature application would be more likely to use either private class or Model approaches.
Create a new class file within the same namespace and call it something. See below:
public class myProduct
{
public int Quantity {get; set;}
public int Name {get; set;}
public double Price {get; set;}
public myProduct(string name)
{
this.Quantity = 1; this.Name = name; this.Price = 0;
}
public override string ToString()
{
return this.Quantity.ToString() + "-" + this.Name + "-" +
(this.Price * this.Quantity).ToString(c,
CultureInfo.CurrentCulture);
}
}
Now, where you were just adding values, you can check to see if the line exists, and if it does, operate on it. Otherwise, add a new line. Don't bother with ToString() methods and such, as you can actually populate your listbox with a list of the new class! It will call the ToString() method when displaying values.
List<myProduct> listvendaBind = new List<myProduct>();
///insert code here to build your list from the database if you havent already. Otherwise, skip this step so you dont overwrite your list
//now the code for modification
var x = listvendaBind.Where(t => t.Name == newProduct.Name).FirstOrDefault();
if(x.Count() > 0 && (x != null)
listvendaBind[listvendaBind.IndexOf(x[0])].Quantity++;
else
listvendaBind.Add(newProduct);
listvenda.DataSource = listvendaBind;
This is untested, as I'm working on another project at the moment, but should serve as proof of concept.
This is only for learning and I do not recommended using it outside testing environment but you can do something like this:
insetad of
listvenda.Items.Add(text1);
do this:
bool notFound = true;
for(int i=0; i<listvenda.Items.Count; i++)
{
if(((string)listvenda.Items[i]).Contains(" - " + bprod1.Text + " - "))
{
listvenda.Items[i] = text1;
notFound = false;
break;
}
}
if(notFound)
listvenda.Items.Add(text1);
but as I said it should only be temporary solution. Instead of this use CDove solution
I want to know the quickest and simplest way to sort the code shown below. Sorting from newRecord.AppCode would not be suitable as it will change the meaning of the output. So I need to sort every line from string outp. What would be the best way? Also I would like to make every row distinct. I beleive using LINQ would be very quick but I am not that great at it. Help appreciated. So close to getting it done! Note: Data is being pulled from a tsv. Using .net 3.5, visual studio 2008) Will mark answer as soon as I get progress. :)
while ((line = sr.ReadLine()) != null)
{
String[] splitted = line.Split('\t');
appcodes.Add(line);
Records newRecord = new Records();
newRecord.Server = splitted[0];
newRecord.Instance = splitted[1];
newRecord.AppCode = splitted[2];
newRecord.Database = splitted[3];
listrecords.Add(newRecord);
for (int i = 0; i < appcodes.Count(); i++)
{
if (newRecord.AppCode==appcodes[i].ToUpper())
{
String outp = newRecord.AppCode + " " + newRecord.Server + " " + newRecord.Instance + " " + newRecord.Database;
Console.WriteLine(outp);
}
}
}
have lists named Keepers and newkeepers. Was trying to do something like outp.sort() and outp.sort() but it doesnt work in strings. This is how I solved the problem.
Keepers.Add(outp);
Keepers.Sort();
newKeepers = Keepers.Distinct().ToList();
foreach (object o in newKeepers)
{
Console.WriteLine(o);
}
Console.ReadLine();
As you can see, newrecords contain different fields so I wrote a LINQ statement to solve the problem.
var sorted_list = (from r in newrecords
orderby r.AppCode, r.Server, r.Instance, r.Database
select r).Distinct().ToList();
var distinctSortedList = sorted_list.Distinct().ToList();
I'm a beginner with dhtmlx scheduler, I use dbfirst with mvc4 razor syntax.
So please can anybody help me to set the start time and endtime values I'm getting from the database:
here is my code:
controller:
sched.Config.first_hour = 8;
sched.Config.last_hour = 19;
public string GetDbValues()
{
string strState = "";
List<tblSettings> settings = new List<tblSettings>();
settings = _config.GetSettings();
var defaultState = from setting in settings
where (setting.Desc == "start time"
|| setting.Desc == "end time")
// starttime as 08 and end time as 20 from database
select setting.Settings;
foreach (var oState in defaultState)
{strState += oState + "|";
}
strState = strState.Remove(strState.Length - 1);
return strState;
}
I get the values for first_hour and last_hour as string from the output.
How to assign this string value to the first_hour and last_hour?
//I use linq to get the db values because of the table structure:
ID(int), Settings(nvarchar) ,Desc (nvarchar)
why do you concatenate the settings into string? More comprehensive data format will simplify the task. You could return List as it is and then just iterate it with foreach, applying needed settings. If for some reason you don't want to pass tblSettings objects, you can select data into Dictionary and then again, apply the values
var data = _config.GetSettings().ToDictionary(
s => s.Desc,
s => s.Setting,
StringComparer.Ordinal);
if(data.ContainsKey("start time"))
scheduler.Config.first_hour = int.Parse(data["start time"]);
if (data.ContainsKey("end time"))
scheduler.Config.first_hour = int.Parse(data["end time"]);
I have a DataTable, and I want to add new items to a Sharepoint list using the data in the table's DataRows. But I'm having trouble adding data for a field where the type is "Person or Group", because this field seems to require an ID, not just "lastname, firstname". I made a class to build the CAML for a call to UpdateListItems(), which works fine for adding any other type of data to the list:
public class CAMLBuilder
{
List<string> nameFields;
public CAMLBuilder()
{
nameFields = new List<string>();
nameFields.Add("Requestor");
}
public XmlElement batchAddElement(DataTable addTable)
{
XmlDocument doc = new XmlDocument();
XmlElement element = doc.CreateElement("Batch");
element.SetAttribute("OnError", "Continue");
element.SetAttribute("ListVersion", "1");
element.SetAttribute("ViewName", "");
int methodCtr = 1;
string batchStr = "";
foreach (DataRow dr in addTable.Rows)
{
batchStr += "<Method ID='" + methodCtr + "' Cmd='New'>";
foreach (DataColumn dc in addTable.Columns)
{
batchStr+="<Field Name='"+dc.ColumnName+"'>" + convertName(dc.ColumnName,Convert.ToString(dr[dc])) + "</Field>";
}
batchStr+="</Method>";
methodCtr++;
}
element.InnerXml = batchStr;
return element;
}
private string convertName(string columnName,string name)
{
if (nameFields.Contains(columnName))
{
name = "-1;#" + name;
}
return name;
}
}
The "-1;#" in convertName() is something that I saw in this discussion as a workaround that lets you avoid looking up the person's ID. But it doesn't work; I get this error message in my returned XML:
0x81020054The user does not exist or is not unique.
Is there a way to build the CAML so that I don't need the ID and can just use the name?
My solution so far is to use the People.asmx web service. The following code assumes that I have created a reference to the web service called PeopleService, and an instance of the service called ps:
public string findPersonID(string searchText)
{
PeopleService.PrincipalInfo[] arrayPrincipalInfo = ps.SearchPrincipals(searchText, 10, PeopleService.SPPrincipalType.All);
if (arrayPrincipalInfo.Count() > 0)
{
return Convert.ToString(arrayPrincipalInfo[0].UserInfoID);
}
else
{
return string.Empty;
}
}
This is not ideal, because it requires that every row in my DataTable must call the web service separately (maybe optimized by grouping all identical names and only calling the function once for each unique name), which is a lot of web traffic if there are a lot of names. Hopefully someone else has a better solution.