I have some vehicle information that I want to send in an email.
I have all code working but spacing out the information is a problem. Each vehicle has a checklist and that checklist then gets emailed. So I loop through the list and get the defect and the comment.
foreach (var item in chkList.CheckItems)
{
if (item.Defect == true)
{
defect += string.Format("{0,-40} {1}\n", item.ItemTitle, item.Comment);
}
}
if (hasDefect == true)
{
Utils.ChecklistSendMail("Checklist", ToAddresses.Split(';'),
"Vehicle Reg: " + reg + "\n" +
"Checklist No: " + chkList.CheckListNo + "\n"+
"Date: " + ChecklistDate.ToShortDateString() + "\n" +
"Defects: Comments: " + "\n" +
defect);
}
Email then looks like this:
Vehicle Reg: XLZ 8194
Checklist No: 0
Date: 22/03/2016
Defects: Comments:
Vehicle Secure comment1
Brakes comment2
I want the defects and the comments to be displayed like this:
Defects: Comments:
Vehicle Secure comment1
Brakes comment2
Since Vehicle Secure is longer than Brakes the comment is being pushed further out. But is there a way to fix the string at a certain position no matter how long first word is?
EDIT
code now looks like this:
string defect = "";
string comment = "";
string aheading = "Defects:";
string bheading = "Comments:";
foreach (var item in chkList.CheckItems)
{
if (item.Defect == true)
{
defect += item.ItemTitle;
comment += item.Comment;
}
}
string result = aheading.PadRight(20, ' ') + bheading.PadRight(20, ' ') + Environment.NewLine +
defect.PadRight(20, ' ') + comment.PadRight(20, ' ') + Environment.NewLine;
But the output looks like this:
Defects: Comments:
Vehicle SecureBrakestest1test2
If you really want to do this with spaces, you need to determine the label with the most characters and how much space you want after that. This creates a total number of characters. From this, you subtract the number of characters of the label to get the number of spaces necessary to line up the value.
However, you could just use a <table> or some other html.
A potential, quick and dirty solution would require you to generate the html as a part of your code. I seriously advise against some homegrown html generator logic. Invariably the data involved in the email becomes more complex. This leads to mixing code that is getting the data for the template and building the html, which is painful to debug. Also there are plenty of html templating solutions out there. You'd really be just reinventing the wheel to take on technical debt and the maintenance of more code.
A better solution would be use something like MvcMailer and build an html template. You then pass the template and a context object to the engine to render the resultant html.
Try and use String padding with ' ' as char
public string PadRight(
int totalWidth,
char paddingChar)
This method would complete the length of the string with the chosen char. by specifying the max length of the string and replacing the remaining length with " " (space). you can always have the strings aligned.
Read more about PadRight or PadLeft
string Defects ="Example"
Defects.PadRight(20," ");
Result: "Example "
Edit : Example Code .Please have a look at this code and check what you are doing wrong
string aheading = "Defects:";
string bheading ="Comments:";
string b = "Vehicle Secure";
string bComment = "My Comment value";
string c = "Brakes";
string cComment = "My Comment value";
string result= aheading.Trim().PadRight(20,' ')+bheading.Trim().PadRight(20,' ')+ Environment.NewLine +
b.Trim().PadRight(20, ' ') + bComment.Trim().PadRight(20, ' ') + Environment.NewLine +
c.Trim().PadRight(20,' ')+cComment.Trim().PadRight(20,' ')+Environment.NewLine ;
Console.WriteLine(result);
Edit:Answer based on the code you Posted
string aheading = "Defects:";
string bheading = "Comments:";
string result = aheading.PadRight(20, ' ') + bheading.PadRight(20, ' ') + Environment.NewLine ;
foreach (var item in chkList.CheckItems)
{
if (item.Defect == true)
{
string result += item.ItemTitle.Trim().PadRight(20,' ') + item.ItemTitle.Trim().PadRight(20,' ') + Environment.NewLine ;
}
}
Console.WriteLine(result);
Related
I have this bit of code run when people close the game to save all their currently selected pets (this is for school don't worry about how I named it "Squirtle", no copyright problems here). The code in question is:
using (StreamWriter sw = File.CreateText(#"..\..\pets.txt"))
{
sw.AutoFlush = true;
foreach (Pet p in petList)
{
sw.Write(p.PetID + ' ');
sw.Write(p.Name + ' ');
sw.Write(p.HP + ' ');
sw.Write(p.Type + ' ');
sw.Write(p.Level + ' ' );
sw.Write(p.Rarity + ' ');
sw.WriteLine(p.Speed);
}
}
the commas were spaces and I just added the autoflush to try and fix the problem, but basically no matter how many times I run it, the first two, next two, and last 3 pieces of data have no spaces between them, example: 32SQUIRTLE 77AQUATIC 41930. this happens every time I run it and am wondering if anyone knows of why it's doing this? I can use any delimiter also if space and comma are notorious with StreamWriter or something.
You are doing Int + Char, The overload for this operation would results in Int + (int) Char which is casting the space into its Unicode code point and doing arithmetic operation
What you want to do is p.PetID.ToString() + " "
right now I am reading some lines from a .txt.
Lets say, a user enters his name and in the .txt will be saved "Logged in {username} on 13/04/2016 at 10:55 am".
(Just an example.)
Now I want to read the .txt and print only specific parts into a textbox.
Meaning, in the textbox shall appear "{Username} - 13/04/2016 - 10:55 am".
So far, I am able to read from the .txt and print the whole line.
private void button_print_results_Click(object sender, RoutedEventArgs e)
{
int counter = 0;
string actual_line;
System.IO.StreamReader file_to_read =
new System.IO.StreamReader("myText.txt");
while ((actual_line = file_to_read.ReadLine()) != null)
{
textBox_results.Text = textBox_results.Text +"\n"+ actual_line;
counter++;
}
file_to_read.Close();
}
Is there a way, to reach this without overwriting the whole file?
And no, I can't change the format how the names etc. are saved.
(I used them here for a better understanding, the actual lines I need to read/check are different and auto-generated).
I don't expect full working code, it would be just great if you could tell me for which commands I need to look. Been a long time since I last worked with c#/wpf and I never worked much with Streamreader...
Thanks
I think regular expressions is the best tool for what you're trying to achieve. You can write something like this:
Regex regex = new Regex("Logged in (?<userName>.+) on (?<loginTime>.+)");
while ((actual_line = file_to_read.ReadLine()) != null)
{
Match match = regex.Match(actual_line);
if (match.Success) {
string loginInfo = string.Format("{0} - {1}", match.Groups["userName"], match.Groups["loginTime"]);
textBox_results.Text = textBox_results.Text +"\n"+ loginInfo;
}
}
There are couple of possible solutions for this. One most straight forward way for your case would be to use Substring and Replace.
Since the earlier string is always Logged in (note the last space) and you simply want to get the rests of the string after the phrase, replacing only the preposition of time words (" on ", " at ") with dash (" - ") you could take advantage on that:
string str = "Logged in {username} on 13/04/2016 at 10:55 am";
string substr = str.Substring(("Logged in ").Length) //note the last space
.Replace(" on ", " - ")
.Replace(" at ", " - ");
In your implementation, this is how it look like:
while ((actual_line = file_to_read.ReadLine()) != null)
{
actual_line = actual_line.Substring(("Logged in ").Length) //note the last space
.Replace(" on ", " - ")
.Replace(" at ", " - ");
textBox_results.Text = textBox_results.Text +"\n"+ actual_line;
counter++;
}
(Note: the solution above assumes the {username} does not contain spaced preposition of time words - which would almost likely be the case for a {username})
You could split the actual_line String so you get an array of Strings. And then fill the Strings you want to show in the TextBox into it.
string[] values = actual_line.Split(' ');
textBox_results.Text = textBox_results.Text + "\n" + values[2] + " " + values[6] + " " + values[7];
The text in the TextBox for example is "{username} 10:55 am"
You can use Regex for better performances as #Dmitry-Rotay suggested in the previous comment, but if you jave a not-so-big file your loop+string manipulations is an acceptable compromise.
Always use Environment.NewLine instead of "\n", it's more portable.
while ((actual_line = file_to_read.ReadLine()) != null)
{
actual_line = actual_line
.Replace(("Logged in "), String.Empty)
.Replace(" on ", " - ")
.Replace(" at ", " - ");
textBox_results.Text = textBox_results.Text
+ System.Environment.NewLine
+ actual_line;
counter++;
}
This question already has answers here:
Removing extra commas from string after using String.Join to convert array to string (C#)
(9 answers)
Closed 8 years ago.
In my C# form I have address field in that i need to fill address that already DoorNo, Street, Area, Location are stored separately in Access Database. I used string concatenation to merge full address.
object row = CBL_Customer_Name.Properties.GetDataSourceRowByKeyValue(CBL_Customer_Name.EditValue) as object;
string getblocation = (row as DataRowView)["BLocation"].ToString();
string getbcity = (row as DataRowView)["BCity"].ToString();
string getbstate = (row as DataRowView)["BState"].ToString();
string getbcountry = (row as DataRowView)["BCountry"].ToString();
TXE_Invoice_Address.Text = (row as DataRowView)["BFlatNo"].ToString() + ", " + (row as DataRowView)["BPremises"].ToString() + "," + System.Environment.NewLine + (row as DataRowView)["BStreet"].ToString() + ", " + getloction(getblocation) + "," + System.Environment.NewLine + (row as DataRowView)["BArea"].ToString() + ", " + getcity(getbcity) + "," + System.Environment.NewLine + getstate(getbstate) + ", " + getcountry(getbcountry) + ".";
If user enter complete address then no problem in this above code. If he doesn't enter location or some other fields then am getting , , or blank space in the end of line.
How to solve this ? I need a perfect address in my address field if user leave 1 or 2 fields also.
Use .replace() to replace empty values by a custom text.
Example
TXE_Invoice_Address.Text = TXE_Invoice_Address.Text.Replace(", ,", ", ")
This code will remove all , , that may cause a strange adress format.
Try this: var newAddress = string.Join(", ",TXE_Invoice_Address.Text.Split(',').Where(x => !string.IsNullOrWhiteSpace(x)));
This will eliminate all empty spaces and rejoin to new a string.
i am running the following code
foreach (ReportObject obj in oSectionObjects)
{
if (obj.Kind == CrystalDecisions.Shared.ReportObjectKind.TextObject)
{
// do stuff
}
}
but i have a problem. i do have multiple text that do contain text AND fields in them.
But crystal return me the field being TextObject which is technically true.
How do i know i ONLY have text in the TextObject and not anything else (aka fields, parameters, formulas) ?
As far as I know the fields in a text box will be recognized by the text pattern. Try to search the text of the text object for {1#xxxxx} where xxxxx is the field name. "{1#" shows the type of the field: 1 is for a database , 2 is for formula, 3 is for parameter. You may try also for {#xxxxx} *(without numeric field identifier)
I searched alot around and found working solution for RAS report but nothing for crystal. Anyhow if someone end up here looking for an answer here's the work around.
Whenever you have to concatenate multiple fields on the report do NOT use TextObject. Instead use a Formula. The formula fields wont bet part of the ReportObjects but instead part of the ReportDocument.DataDefinition.FormulaFields with Kind being CrystalDecisions.Shared.FieldKind.FormulaField and you will want to check the ValueType so it is CrystalDecisions.Shared.FieldValueType.StringField.
then you can manipulate them.
I did need that for translation of report live so here's a parsing method for formulas :
try
{
var sFormula = formula.Text;
string pattern = "\"[\\w ]*\"";
Regex r = new Regex(pattern);
MatchCollection mc = r.Matches(sFormula);
foreach (Match m in mc)
{
var sValue =m.Value;
var sParsedValue = sValue.Substring(1, sValue.Length - 2);
if (sParsedValue.StartsWith("s"))
{
var stest = "\"" + CApplicationData.TranslateStringValue(sParsedValue) + "\"";
sFormula = sFormula.Replace(sValue, stest);
}
}
formula.Text = sFormula;
}
catch{}
this above you will notice i use 's' as a key to know it might be a value to be translated so it's not mandatory. using the above on this formula with Spanish language :
"sPage" + " " + totext(PageNumber) + " " + "sOf" + " " + totext(TotalPageCount)
will modify the formula to :
"Página" + " " + totext(PageNumber) + " " + "de" + " " + totext(TotalPageCount)
giving output of :
Página 1 de 4
I'm trying to create a MailMessage, and I'm getting the following error...
Cannot implicitly convert type 'string' to 'bool'
This is my init statement:
MailMessage msg = new MailMessage("DoNotReply#optoma.com",
myTbl.Rows[i]["Requester"].ToString().Trim(),
subject,
"Dear " + myTbl.Rows[i]["Ship_Attention"].ToString() + ",<br/><br/>" +
body + "<br/>Your ISO ID is " + myTbl.Rows[i]["ISO_ID"].ToString() +
(Convert.ToInt32(myTbl.Rows[i]["EmailType"]) == 1) ?
("<br/>Tracking Number: " + myTbl.Rows[i]["Tracking_No"].ToString()) :
("") + "<br/><br/>Please examine the loaned items for this transaction:<br/><br/>" +
sw.ToString());
I'm trying to add to the string at runtime based on a boolean expression. Why can't I do this? Am I not doing it right?
string + (true | false) ? "somestring" : "anotherstring" + string
the ? : operator has very low precedence. Put it in parenthesis and I think you'll resolve your issue.
((true|false)?"somestring":"anotherstring")
When you have string + (bool)?"somestring":"anotherstring" + string the + gets evaluated before the ?, so you need parentheses:
string + ((bool)?"somestring":"anotherstring") + string
just cleaning it up a wee bit.... and you won't run into operator precedence problems so much
void SendMessage(DataRow row, string subject, string body, string sw)
{
var to = row["Requester"].ToString().Trim();
var isoId = row["ISO_ID"].ToString();
var attention = row["Ship_Attention"].ToString();
var emailType = Convert.ToInt32(row["EmailType"]);
var message = (emailType == 1) ? ("<br/>Tracking Number: " + row["Tracking_No"]) : ("");
MailMessage msg = new MailMessage("DoNotReply#optoma.com",
to,
subject,
string.Format("Dear {0},<br/><br/>{1}<br/>Your ISO ID is {2}{3}<br/><br/>Please examine the loaned items for this transaction:<br/><br/>{4}",
attention, body, isoId, message, sw));
}
The precedence isn't what you expect -- + is being evaluated first. Your code should be in the form:
string + (true|false ? "somestring" : "anotherstring") + string
For your specific example:
MailMessage msg = new MailMessage("DoNotReply#optoma.com", myTbl.Rows[i]["Requester"].ToString().Trim(),
subject, "Dear " + myTbl.Rows[i]["Ship_Attention"].ToString() + ",<br/><br/>" +
body + "<br/>Your ISO ID is " + myTbl.Rows[i]["ISO_ID"].ToString() + (Convert.ToInt32(myTbl.Rows[i]["EmailType"]) == 1 ? ("<br/>Tracking Number: " + myTbl.Rows[i]["Tracking_No"].ToString()) : ("")) + "<br/><br/>Please examine the loaned items for this transaction:<br/><br/>" +
sw.ToString());
Note that this is a very long expression and should probably be broken down into several statements to make it more readable and maintainable.
The additive oprator (+) has higher priority than conditional (?:) as indicated here: http://msdn.microsoft.com/en-us/library/aa691323%28v=vs.71%29.aspx.
Therefore you need to put parenthesis around the whole condition:
string + ((true|false)?"somestring":"anotherstring") + string
I suggest you to divide your code into more lines, introduce some temporary variables and use string.format() to make it look clener. Finding errors in clean code is much easier.