I want to display a string in a message box with a following format:
Machine : TestMachine
User : UserName
I am doing this:
string strMsg = "Machine :" + "TestMahine" + "\r\n" +
"User :" + "UserName";
MessageBox.Show(strMsg);
When I do this the message box do not display a string as formated above. Colon(") dosen't keep alligned. The above format is also do not work in WPF TextBlock control.
Please help!!
Try something like this:
string strMsg = String.Format("Machine\t: {0}\nUser\t: {1}", "TestMachine", "UserName");
Edited: Gotta have that String.Format there or that lone bracket at the end is sad.
The reason for this is that the message box is displayed in a font where Machine and User may not be the same length.
You could try the following:
"Machine\t:" + "TestMahine" + "\r\n" +
"User\t:" + "UserName";
The \t character will probably correctly align your colons.
In a WPF (or WinForms, or Java, or Qt, or whatever) TextBlock, if you want characters to be aligned, you need to use a fixed font length, in order for every character to have the same length than the others.
i.e. Use a font like "Courier New" or "Monospaced" or "Consolas".
In a MessageBox, you cannot control the font-family. If you really want this feature, did you consider creating a customized Window component ? Like this...
<Window x:Class="WpfApplication1.CustomMessageBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
SizeToContent="WidthAndHeight" MaxWidth="500">
<Grid Margin="10">
<TextBlock FontFamily="Courier New" Text="{Binding Message}" />
</Grid>
</Window>
.
public partial class CustomMessageBox : Window, INotifyPropertyChanged {
private string message;
public string Message {
get { return message; }
set { message = value; RaisePropertyChanged("Message"); }
}
public CustomMessageBox() {
InitializeComponent();
DataContext = this;
}
public static void Show(string title, string message) {
var mbox = new CustomMessageBox();
mbox.Title = title;
mbox.Message = message;
mbox.ShowDialog();
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property) {
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
As a result, you can invoke your new messagebox with:
string strMsg =
"Machine : " + "TestMahine" + "\r\n" +
"User : " + "UserName";
CustomMessageBox.Show("Hello !", strMsg);
Of course, you will need to do some little arrangements to your custom message box view but you got the idea ;-)
I ran into the same problem trying to align data in a MessageBox and after searching for a while I decided to write my own method using TextRenderer.MeasureText to get measurements at the pixel level. The method takes two parameters; the first is the string to format and the second is the longest string to be shown to the left of the colon (the alignment character in this example).
What the method is doing is prepending blank spaces until the string reaches, but does not exceed, the length of the longest string. The method is called as shown below where "Department: " is the longest string.
StringBuilder sb = new StringBuilder();
string longest = "Department: ";
sb.AppendLine(StringLengthFormat("Result(s): ", longest) + results);
The actual method that does the formatting is:
private string StringLengthFormat(string inString, string longest)
{
Size textSizeMax = TextRenderer.MeasureText(longest, System.Drawing.SystemFonts.DefaultFont);
Size textSizeCurrent = TextRenderer.MeasureText(inString, System.Drawing.SystemFonts.DefaultFont);
do
{
inString = " " + inString;
textSizeCurrent = TextRenderer.MeasureText(inString, System.Drawing.SystemFonts.DefaultFont);
} while (textSizeCurrent.Width < textSizeMax.Width);
return inString;
}
Because I can also have one or more lines that do NOT start with the "description" followed by a colon but still need to be aligned I came up with a way to format those lines using the same method. I concatenate that data using the carriage return and tab characters "\r\t" and then replace the tab character "\t" with my method. Note that I include the two blank spaces that follow the colon in this example in order to give the formatting method something to prepend to and that I am trimming the trailing "\r\t" before formatting the string.
The complete code section is shown below followed by a link to the example MessageBox output created by that code.
string results = "";
StringBuilder sb = new StringBuilder();
string longest = "Department: ";
foreach (EncounterInfo enc in lei)
{
results += enc.Description + " " + enc.ResultValue + " " + enc.ResultUnits + "\r\t";
}
results = results.TrimEnd(new char[] { '\r', '\t' });
results = results.Replace("\t", StringLengthFormat(" ", longest));
sb.AppendLine(StringLengthFormat("Result(s): ", longest) + results);
sb.AppendLine(StringLengthFormat("Patient: ", longest) + ei.PatientName);
sb.AppendLine(StringLengthFormat("Accession: ", longest) + ei.AccessionNumber);
sb.AppendLine(longest + ei.CollectionClassDept);
sb.AppendLine();
sb.AppendLine("Continue?");
dr = MessageBox.Show(sb.ToString(), "Add to Encounters", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
Example MessageBox with string length formatting
Based on the approach specified by Terrence Meehan, I rewrote the StringLengthFormat method as follow:
using System.Drawing;
using System.Windows.Forms;
enum Alignment { Left = 0, Right = 1};
static string StringLengthFormat(string inputString, string longestString,
Alignment alignment=Alignment.Left, string margin="")
{
Size textSizeMax = TextRenderer.MeasureText(longestString + margin, SystemFonts.MessageBoxFont);
Size textSizeCurrent = TextRenderer.MeasureText(inputString, SystemFonts.MessageBoxFont);
do
{
if (alignment == Alignment.Left)
{
inputString += " ";
}
else
{
inputString = " " + inputString;
}
textSizeCurrent = TextRenderer.MeasureText(inputString, SystemFonts.MessageBoxFont);
} while (textSizeCurrent.Width < textSizeMax.Width);
return inputString;
}
The differences are as follows:
Instead of System.Drawing.SystemFonts.DefaultFont, I use System.Drawing.SystemFonts.MessageBoxFont;
The parameter margin sets the distance between the columns (by transferring the required number of spaces);
The parameter alignment sets the alignment in the columns (left or right). If desired, the code can be supplemented so that the center alignment option also appears.
tring strMsg = "Machine :" + "TestMahine\t\nUser :" + "UserName";
MessageBox.Show(strMsg);
Related
If I have a TreeView with the font to Segoa UI Emoji. I need to set a TreeView node icon using 2 strings but doesn't work. Also, what value can I use for the unicodeEndStr variable below if the unicode only has 4 digits like 2639 ?
// This code shows emoji icon in treeview node followed by a space and some text
string emoji = "\U0001F608" + " " + "Face Savoring Food";
EmojiTreeView.Nodes.Add(emoji);
// This code does not show emoji icon, just \U0001F608 followed by a space and some text
string unicodeStartStr = "\\U000"; // need double back slashes to compile
string unicodeEndStr = "1F608";
string emojiCodeStr = unicodeStartStr + unicodeEndStr;
string emojiStr = emojiCodeStr + " " + "Face Savoring Food";
EmojiTreeView.Nodes.Add(emojiStr);
First parse your combined Unicode string as hex(16-bit) number.
Then use char.ConverFromUtf32(str).ToString() to generate complete Unicode symbol.
Reference solution: Dynamic generate 8-Digit-Unicode to Character
public Form1()
{
InitializeComponent();
treeView1.Nodes.Add("\U0001F608" + " " + "Face Savoring Food");
// remove \u prefix
string unicodeStartStr = "000";
string unicodeEndStr = "1F608";
string emojiCodeStr = unicodeStartStr + unicodeEndStr;
int value = int.Parse(emojiCodeStr, System.Globalization.NumberStyles.HexNumber);
string result = char.ConvertFromUtf32(value).ToString();
string emojiStr = result + " " + "Face Savoring Food";
treeView1.Nodes.Add(emojiStr);
}
Worked result
I have this method that replaces(in bold) some words in a string and show the changed string in a ritchtextBox.
In the final string I need to replace the # symbol by a newline.
I already tried checked this forum tying several solutions, but nothing worked.
The method I use is
private string bold(string ing)
{
StringBuilder builder = new StringBuilder();
ing = " " + ing + " ";
builder.Append(#"{\rtf1\ansi");
foreach (string word in splitwords)
{
var regex = new Regex(#"(?<![\w])" + word + #"(?![\w])", RegexOptions.IgnoreCase);
ing = regex.Replace(ing, m => #"\b" + m.ToString() + #"\c0");
}
ing = ing.Replace(#"\b", #"\b ");
ing = ing.Replace(#"\c0", #" \b0");
ing = ing.Replace("#", Environment.NewLine);
builder.Append(ing);
builder.Append(#"}");
MessageBox.Show("builder.ToString():" + builder.ToString());
return builder.ToString();
}
When I call the this method and "put it" in the ritchTextBox it doesn´t print the new line
ingred.Rtf = bold(ingd);
How should I solve this??
EDIT:: input string - line1 # line2 # line3
output in the MessageBox
Builder.ToString() : {\rtf1\ansi\b line1\b0
line2
line3
}
output in the ritchTextBox: line1 line2 line3
Instead of
ing = ing.Replace("#", Environment.NewLine);
Try
ing = ing.Replace("#", #"\par\r\n");
Use This Code For Repalce
int startIndex = 0, index;
RichTextBox myRtb = new RichTextBox(); // if have A richtextBox Remove thisline and Use your Richtextbox
myRtb.Rtf = STRRTF;// if have A richtextBox Remove thisline and Use your Richtextbox
while ((index = myRtb.Text.IndexOf("#", startIndex)) != -1)
{
myRtb.Select(index, word.Length);
myRtb.SelectedText ="\n";
startIndex = index + 1;
}
Better use Environment.NewLine for adding new line also Make sure yourRTB.MultiLine property is set to true. assign string to richtext box like this yourRTB.AppendText(t)
Try replacing it with a "\r\n" character sequence?
edit: is MultiLine property of ritchtextBox enabled?
I have a sentence that may contain URL's. I need to take any URL in uppercase that starts with WWW., and append HTTP://. I have tried the following:
private string ParseUrlInText(string text)
{
string currentText = text;
foreach (string word in currentText.Split(new[] { "\r\n", "\n", " ", "</br>" }, StringSplitOptions.RemoveEmptyEntries))
{
string thing;
if (word.ToLower().StartsWith("www."))
{
if (IsAllUpper(word))
{
thing = "HTTP://" + word;
currentText = ReplaceFirst(currentText, word, thing);
}
}
}
return currentText;
}
public string ReplaceFirst(string text, string search, string replace)
{
int pos = text.IndexOf(search);
if (pos < 0)
{
return text;
}
return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
}
private static bool IsAllUpper(string input)
{
return input.All(t => !Char.IsLetter(t) || Char.IsUpper(t));
}
However its only appending multiple HTTP:// to the first URL using the following:
WWW.GOOGLE.CO.ZA
WWW.GOOGLE.CO.ZA WWW.GOOGLE.CO.ZA
HTTP:// WWW.GOOGLE.CO.ZA
there are a lot of domains (This shouldn't be parsed)
to
HTTP:// WWW.GOOGLE.CO.ZA
HTTP:// WWW.GOOGLE.CO.ZA HTTP:// WWW.GOOGLE.CO.ZA
HTTP:// WWW.GOOGLE.CO.ZA
there are a lot of domains (This shouldn't be parsed)
Please could someone show me the proper way to do this
Edit: I need to keep the format of the string (Spaces, newlines etc)
Edit2: A url might have an HTTP:// appended. I've updated the demo.
The issue with your code: you're using a ReplaceFirst method, which does exactly what it's meant to: it replaces the first occurence, which is obviously not always the one you want to replace. This is why only your first WWW.GOOGLE.CO.ZA get all the appending of HTTP://.
One method would be to use a StreamReader or something, and each time you get to a new word, you check if it's four first characters are "WWW." and insert at this position of the reader the string "HTTP://". But it's pretty heavy lenghted for something that can be way shorter...
So let's go Regex!
How to insert characters before a word with Regex
Regex.Replace(input, #"[abc]", "adding_text_before_match$1");
How to match words not starting with another word:
(?<!wont_start_with_that)word_to_match
Which leads us to:
private string ParseUrlInText(string text)
{
return Regex.Replace(text, #"(?<!HTTP://)(WWW\.[A-Za-z0-9_\.]+)",
#"HTTP://$1");
}
I'd go for the following:
1) You don't handle same elements twice,
2) You replace all instances once
private string ParseUrlInText(string text)
{
string currentText = text;
var workingText = currentText.Split(new[] { "\r\n", "\n", " ", "</br>" },
StringSplitOptions.RemoveEmptyEntries).Distinct() // .Distinct() gives us just unique entries!
foreach (string word in workingText)
{
string thing;
if (word.ToLower().StartsWith("www."))
{
if (IsAllUpper(word))
{
thing = "HTTP://" + word;
currentText = currentText.Replace("\r\n" + word, "\r\n" + thing)
.Replace("\n" + word, "\n" + thing)
.Replace(" " + word, " " + thing)
.Replace("</br>" + word, "</br>" + thing)
}
}
}
return currentText;
}
I'm trying to replicate a log window, so the most recent log should appear at the top - most visible. Thus, I need to add a text to the top (no problem) but with multiple colors (problem).
First I store the original text. (it's rtf or text - tried both)
And then I add the new text, with a username and then a message. The username should be one color and the message another. It's always single lined too.
All I get by my method is that when appending the old text or the old RTF text, the latest "log" only shows.
public void AddLog(Log log)
{
try
{
string oldText = this.richTextBox1.Rtf;
this.richTextBox1.Text = log.User + ": " + log.Message + "\n";
this.richTextBox1.Select(0, log.User.Length);
this.richTextBox1.SelectionColor = Color.GreenYellow;
this.richTextBox1.Select(log.User.Length + 2, log.Message.Length);
this.richTextBox1.SelectionColor = Color.White;
this.richTextBox1.DeselectAll();
this.richTextBox1.Rtf += oldText;
}
catch { }
}
Is this even possible? Because it doesn't save the old RTF text and the old RTF text can't be appended after the new text, which means I probably have to add newest text below which isn't what I want.
If I instead of saving the "RTF" text, the format (colors) will disappear and will only show one color.
Not tested but try this
public void AddLog(Log log)
{
try
{
richTextBox1.SelectAll();
string oldText = this.richTextBox1.SelectedRtf;
this.richTextBox1.Text = log.User + ": " + log.Message + "\n";
this.richTextBox1.Select(0, log.User.Length);
this.richTextBox1.SelectionColor = Color.GreenYellow;
this.richTextBox1.Select(log.User.Length + 2, log.Message.Length);
this.richTextBox1.SelectionColor = Color.White;
this.richTextBox1.DeselectAll();
this.richTextBox1.SelectionStart = this.richTextBox1.TextLength;
this.richTextBox1.SelectedRtf = oldText;
this.richTextBox1.DeselectAll();
}
catch { }
}
I would like to click on an item in a listbox and display the attributes that were passed into that listbox to a multiline textbox.
Below is the code I have written on form initialisation
public Form1()
{
InitializeComponent();
ReadFromFile.Read("sample.GED");
foreach (KeyValuePair<int, Individual> kvp in ReadFromFile.individuals)
{
listBox2.Items.Add("ID = " + kvp.Value.id + " Name = " + kvp.Value.name.givenName + " " + kvp.Value.name.surname + " DoB = " + kvp.Value.birth.date);
}
int testIndividual = 94;
string genderOut = "";
if (ReadFromFile.individuals[testIndividual].gender == "M")
{
genderOut = "MALE";
}
else if (ReadFromFile.individuals[testIndividual].gender == "F")
{
genderOut = "FEMALE";
}
try
{
textBox1.AppendText(
"Name = " + ReadFromFile.individuals[testIndividual].name.givenName + " "
+ ReadFromFile.individuals[testIndividual].name.surname
+ Environment.NewLine + "Gender = " + genderOut
+ Environment.NewLine + "Birth date = " + ReadFromFile.individuals[testIndividual].birth.date
+ Environment.NewLine + "Birth place = " + ReadFromFile.individuals[testIndividual].birth.place
+ Environment.NewLine + "Death date = " + ReadFromFile.individuals[testIndividual].death.date
+ Environment.NewLine + "Death place = " + ReadFromFile.individuals[testIndividual].death.place);
}
catch
{
MessageBox.Show("This individual doesnt exist");
}
}
}
I would like to add more so I can click on a listbox item and the details for that item will be shown in the textbox
I get the feeling I may have to override the ToString() method or regex it. Im still quite a novice programmer so go easy on me :) THANK YOU
You need to handle the SelectedIndexChanged event for your listbox.
One way to do this is to bring up Form1.cs[Design] and select the listbox. In the property grid (Alt+Enter) click the icon that looks like this:
Find the event SelectedIndexChanged and double click it. That will hook up an event handler for you in the auto generated Form1.cs.designer file.
Next, replace the code for your Form1 class with the following:
public partial class Form1 : Form
{
private Dictionary<int, Individual> _individuals;
public Form1()
{
InitializeComponent();
ReadFromFile.Read("sample.GED");
_individuals = ReadFromFile.individuals;
listBox1.DataSource = _individuals.Select(individual => individual.Value).ToList();
listBox1.DisplayMember = "name";
listBox1.ValueMember = "id";
}
private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{
textBox1.Clear();
var individual = listBox1.SelectedItem as Individual;
string genderOut = (individual.Gender == "M") ? "MALE" : "FEMALE";
var displayText
= String.Format("Name = {0} {1}\r\n" +
"Gender = {2}\r\n" +
"Birth date = {3}\r\n" +
"Birth place = {4}\r\n" +
"Death date = {5}\r\n" +
"Death place = {6}"
, individual.name.givenName
, individual.name.surname
, genderOut
, individual.birth.date
, individual.birth.place
, individual.death.date
, individual.death.place);
textBox1.AppendText(displayText);
}
}
A few notes about some of the things i've changed.
I've moved the code that was setting the textbox value into the SelectedIndexChanged event handler
I've refactored that code so that it's more readable by using the static String.Format method (all those Environment.NewLine repeats you had were messy).
I've setup the data for the list box using the DataSource property instead of your foreach loop.
Also, one thing you'll notice with this is that the list items in the listbox will not show the correct text. This is because you appear to be using some custom classes or structs for the name, birth and death of an Individual? To fix this, you need to add a new property to the Individual class like this:
public class Individual
{
// ... your code
public string DisplayName
{
get { return String.Format("{0} {1}), name.givenName, name.surname; }
}
// ... the rest of your code
}
Then you will need to change the line in my code above that looks like this:
listBox1.DisplayMember = "name";
to this:
listBox1.DisplayMember = "DisplayName";
Final note: You should probably be using "Upper Camel Case" for your property names. That means that they start with an upper case letter and then the first letter of each word is also upper case. For example, name.givenName should be Name.GivenName. This is a widely used convention.