In converting a string to a number I can't seem to be able to use .Value.
I'm using this to build responsive images using Umbraco.
public static IHtmlString GetSrcSet(this IPublishedContent item, int width = 0, int height = 0, string widths = "300,600,768")
{
StringBuilder sb = new StringBuilder(string.Empty);
if (width == 0)
{
width = int.Parse(item.GetProperty("UmbracoWidth").ToString());
}
if (height == 0)
{
height = int.Parse(item.GetProperty("UmbracoHeight").ToString());
}
string[] splitWidths = widths.Split(',');
foreach (string newWidth in splitWidths)
{
. . .
}
return (new HtmlString(sb.ToString()));
}
I'm confident I need to use .Value on these lines
if (width == 0)
{
width = int.Parse(item.GetProperty("UmbracoWidth").Value.ToString());
}
if (height == 0)
{
height = int.Parse(item.GetProperty("UmbracoHeight").Value.ToString());
}
But then I get
Error CS0119 'PublishedElementExtensions.Value(IPublishedElement, string, string, string, Fallback, object)' is a method, which is not valid in the given context
Omitting .Value:
Input string was not in a correct format.
You need to add brackets after the Value. You are currently calling Value like it's a property when you need to call it like a method.
if (width == 0)
{
width = int.Parse(item.GetProperty("UmbracoWidth").Value().ToString());
}
if (height == 0)
{
height = int.Parse(item.GetProperty("UmbracoHeight").Value().ToString());
}
I want to Justify text Like Below Link Image in label there have word justifications not a character currently my code is doing this. And i am using another fonts as well and it is a multi-language application so the text justification is work some times in English language only but i need another fonts too.
MyCode is below, Please check this.
public void Justify(System.Windows.Forms.Label label)
{
string text = label.Text;
string[] lines = text.Split(new[] { "\r\n" }, StringSplitOptions.None).Select(l => l.Trim()).ToArray();
List<string> result = new List<string>();
foreach (string line in lines)
{
result.Add(StretchToWidth(line, label));
}
label.Text = string.Join("\r\n", result);
}
It is call next function
private string StretchToWidth(string text, Label label)
{
if (text.Length < 2)
return text;
// A hair space is the smallest possible non-visible character we can insert
const char hairspace = '\u200A';
// If we measure just the width of the space we might get too much because of added paddings so we have to do it a bit differently
double basewidth = TextRenderer.MeasureText(text, label.Font).Width;
double doublewidth = TextRenderer.MeasureText(text + text, label.Font).Width;
double doublewidthplusspace = TextRenderer.MeasureText(text + hairspace + text, label.Font).Width;
double spacewidth = doublewidthplusspace - doublewidth;
//The space we have to fill up with spaces is whatever is left
double leftoverspace = label.Width - basewidth;
//Calculate the amount of spaces we need to insert
int approximateInserts = Math.Max(0, (int)Math.Floor(leftoverspace / spacewidth));
//Insert spaces
return InsertFillerChar(hairspace, text, approximateInserts);
}
and last is this.
private static string InsertFillerChar(char filler, string text, int inserts)
{
string result = "";
int inserted = 0;
for (int i = 0; i < text.Length; i++)
{
//Add one character of the original text
result += text[i];
//Only add spaces between characters, not at the end
if (i >= text.Length - 1) continue;
//Determine how many characters should have been inserted so far
int shouldbeinserted = (int)(inserts * (i + 1) / (text.Length - 1.0));
int insertnow = shouldbeinserted - inserted;
for (int j = 0; j < insertnow; j++)
result += filler;
inserted += insertnow;
}
return result;
}
I am looking a way to create a HyperLink in a RichTextBox pointing to a line of the text of the same RichTextBox.
I just found how to do that with Internet Links but I don't find a way to do it with the same text inside of the control (It's like Hyperlinks in MS Word pointing to a header or bookmark).
Thanks in Advance. - CCB
No, this will not work unless you code the necessary stuff yourself.
Two suggestions:
A simple workaround with links always starting with www.
The nicer solution with arbitrary link text
Let's have a look at both options..:
Using the built-in functionality of recognizing an URL seems the right way to start, but the link will always have to look like a URL, not like a hyperlink to an anchor.. If you can live with a solution that has, say, links like this: www.goto.234 and anchors like this: #234# this is really rather simple..
A working example can be as simple as this:
private void richTextBox1_LinkClicked(object sender, LinkClickedEventArgs e)
{
var s = e.LinkText.Split('.');
string anchor = s[2];
int a = richTextBox1.Text.IndexOf("#" + anchor + "#" );
if (a >= 0) richTextBox1.SelectionStart = a; else return; // do add more checks!
richTextBox1.SelectionLength = 0;
Text = anchor + " # " + a;
//richTextBox1.ScrollToCaret(); <<--- this crashes on my machine!
// so I take the jump out of the click event and it works:
Timer ttt = new Timer() { Interval = 100 };
ttt.Tick += (ss, ee) => { richTextBox1.ScrollToCaret(); ttt.Stop(); };
}
Option two: If you'd rather have more choice of how the links should read you can do this:
Start by formatting each to
Start with a special character, say a tilde '~'
format it to look blue and underlined if you want to
Either make it one word or replace space by underlines and format those to have the forecolor equal to the backcolor
Now this can do the job:
public string delimiters = " ()[]{}!&?=/\\,;.\r\n";
private void richTextBox2_Click(object sender, EventArgs e)
{
int sstart = -1;
string s = getWordAt(richTextBox2.Text,
richTextBox2.SelectionStart, delimiters, out sstart);
if (s.Length < 3) return;
string char1 = s.Substring(0, 1);
if (char1 == "~")
{
int p = richTextBox2.Text.IndexOf("#" + s.Substring(1));
if (p >= 0) { richTextBox2.SelectionStart = p; richTextBox2.ScrollToCaret(); }
}
}
public static string getWordAt(string text, int cursorPos,
string delimiters, out int selStart)
{
int startPos = 0;
selStart = startPos;
if ((cursorPos < 0) | (cursorPos > text.Length) | (text.Length == 0)) return "";
if ((text.Length > cursorPos) & (delimiters.Contains(text[cursorPos]))) return "";
int endPos = text.Length - 1;
if (cursorPos == text.Length) endPos = text.Length - 1;
else { for (int i = cursorPos; i < text.Length; i++)
{ if (delimiters.Contains(text[i])) { endPos = i - 1; break; } } }
if (cursorPos == 0) startPos = 0;
else { for (int i = cursorPos; i > 0; i--)
{ if (delimiters.Contains(text[i])) { startPos = i + 1; break; } } }
selStart = startPos;
return text.Substring(startPos, endPos - startPos + 1);
}
Here are the two versions side by side, once at the top then after clicking on a link:
Both versions work fine, although both could do with some more checks.
Note that I was too lazy to format the pseudo-links in the second example, so they show their tildes and hashes..
Not hard to write a helper function that can insert the formatting; the search will still work as it searches in the Text, not the Rtf property..
I'm using a System.Windows.Forms.TextBox. According to the docs, the MaxLength property controls the amount of characters enter a user can type or paste into the TextBox (i.e. more than that can be added programmatically by using e.g. the AppendText function or the Text property). The current amount of characters can be got from the TextLength property.
Is there any way to set the maximum amount of characters without making a custom limiter which calls Clear() when the custom limit is reached?
Regardless, what is the absolute maximum it can hold? Is it only limited by memory?
What happens when the maximum is reached / memory is full? Crash? Top x lines is cleared?
What would be the best way to manually clear only the top x lines? Substring operation?
edit: I have tested it to hold more than 600k characters, regardless of MaxLength, at which point I manually stopped the program and asked this question.
Sure. Override / shadow AppendText and Text in a derived class. See code below.
The backing field for the Text property is a plain old string (private field System.Windows.Forms.Control::text). So the maximum length is the max length of a string, which is "2 GB, or about 1 billion characters" (see System.String).
Why don't you try it and see?
It depends on your performance requirements. You could use the Lines property, but beware that every time you call it your entire text will be internally parsed into lines. If you're pushing the limits of content length this would be a bad idea. So that faster way (in terms of execution, not coding) would be to zip through the characters and count the cr / lfs. You of course need to decide what you are considering a line ending.
Code: Enforce MaxLength property even when setting text programmatically:
using System;
using System.Windows.Forms;
namespace WindowsFormsApplication5 {
class TextBoxExt : TextBox {
new public void AppendText(string text) {
if (this.Text.Length == this.MaxLength) {
return;
} else if (this.Text.Length + text.Length > this.MaxLength) {
base.AppendText(text.Substring(0, (this.MaxLength - this.Text.Length)));
} else {
base.AppendText(text);
}
}
public override string Text {
get {
return base.Text;
}
set {
if (!string.IsNullOrEmpty(value) && value.Length > this.MaxLength) {
base.Text = value.Substring(0, this.MaxLength);
} else {
base.Text = value;
}
}
}
// Also: Clearing top X lines with high performance
public void ClearTopLines(int count) {
if (count <= 0) {
return;
} else if (!this.Multiline) {
this.Clear();
return;
}
string txt = this.Text;
int cursor = 0, ixOf = 0, brkLength = 0, brkCount = 0;
while (brkCount < count) {
ixOf = txt.IndexOfBreak(cursor, out brkLength);
if (ixOf < 0) {
this.Clear();
return;
}
cursor = ixOf + brkLength;
brkCount++;
}
this.Text = txt.Substring(cursor);
}
}
public static class StringExt {
public static int IndexOfBreak(this string str, out int length) {
return IndexOfBreak(str, 0, out length);
}
public static int IndexOfBreak(this string str, int startIndex, out int length) {
if (string.IsNullOrEmpty(str)) {
length = 0;
return -1;
}
int ub = str.Length - 1;
int intchr;
if (startIndex > ub) {
throw new ArgumentOutOfRangeException();
}
for (int i = startIndex; i <= ub; i++) {
intchr = str[i];
if (intchr == 0x0D) {
if (i < ub && str[i + 1] == 0x0A) {
length = 2;
} else {
length = 1;
}
return i;
} else if (intchr == 0x0A) {
length = 1;
return i;
}
}
length = 0;
return -1;
}
}
}
The theoretical limit is that of a string, ~2GB. However, in reality, it depends upon the conditions in your running process. It equates to the size of the largest available contiguous section of memory that a string can allocate at any given time. I have a textbox in an application that is erroring at about 450MB.
The Text property of System.Windows.Forms.TextBox is a string, so in theory it can be the max length of a string
Is there any function in c# to shink a file path ?
Input: "c:\users\Windows\Downloaded Program Files\Folder\Inside\example\file.txt"
Output: "c:\users\...\example\file.txt"
Nasreddine answer was nearly correct.
Just specify StringBuilder size, in your case:
[DllImport("shlwapi.dll", CharSet = CharSet.Auto)]
static extern bool PathCompactPathEx(
[Out] StringBuilder pszOut,
string szPath,
int cchMax,
int dwFlags);
static string PathShortener(string path, int length)
{
StringBuilder sb = new StringBuilder(length + 1);
PathCompactPathEx(sb, path, length, 0);
return sb.ToString();
}
Jeff Atwood posted a solution to this on his blog and here it is :
[DllImport("shlwapi.dll", CharSet = CharSet.Auto)]
static extern bool PathCompactPathEx([Out] StringBuilder pszOut, string szPath, int cchMax, int dwFlags);
static string PathShortener(string path, int length)
{
StringBuilder sb = new StringBuilder();
PathCompactPathEx(sb, path, length, 0);
return sb.ToString();
}
It uses the unmanaged function PathCompactPathEx to achieve what you want.
That looks less human readable to me. Anyway, I don't think there is such a function. split it on the \ character and just keep the first two slots and the last two slots and you have it.
Something like this, although that code is not very elegant
string[] splits = path.Split('\\');
Console.WriteLine( splits[0] + "\\" + splits[1] + "\\...\\" + splits[splits.Length - 2] + "\\" + splits[splits.Length - 1]);
If you want, do insert ellipsis dependent on the length of the path string, then use this code:
TextRenderer.MeasureText(path, Font,
new System.Drawing.Size(Width, 0),
TextFormatFlags.PathEllipsis | TextFormatFlags.ModifyString);
It will modify path in-place.
EDIT: Be careful with this method. It breaks the rule, saying that strings in .NET are immutable. In fact, the first parameter of the MeasureText method is not a ref parameter, which means that no new string can be returned. Instead, the existing string is altered. It would be careful to work on a copy created with
string temp = String.Copy(path);
You could use something like:
public string ShrinkPath(string path, int maxLength)
{
List<string> parts = new List<string>(path.Split('\\'));
string start = parts[0] + #"\" + parts[1];
parts.RemoveAt(1);
parts.RemoveAt(0);
string end = parts[parts.Count-1];
parts.RemoveAt(parts.Count-1);
parts.Insert(0, "...");
while(parts.Count > 1 &&
start.Length + end.Length + parts.Sum(p=>p.Length) + parts.Count > maxLength)
parts.RemoveAt(parts.Count-1);
string mid = "";
parts.ForEach(p => mid += p + #"\");
return start+mid+end;
}
Or just use Olivers solution, which is much easier ;-).
private string ShrinkPath(string path, int maxLength)
{
var parts = path.Split('\\');
var output = String.Join("\\", parts, 0, parts.Length);
var endIndex = (parts.Length - 1);
var startIndex = endIndex / 2;
var index = startIndex;
var step = 0;
while (output.Length >= maxLength && index != 0 && index != endIndex)
{
parts[index] = "...";
output = String.Join("\\", parts, 0, parts.Length);
if (step >= 0) step++;
step = (step * -1);
index = startIndex + step;
}
return output;
}
I was just faced with this issue as long paths were becoming a complete eye sore. Here is what I tossed together real quick (mind the sloppiness) but it gets the job done.
private string ShortenPath(string path, int maxLength)
{
int pathLength = path.Length;
string[] parts;
parts = label1.Text.Split('\\');
int startIndex = (parts.Length - 1) / 2;
int index = startIndex;
string output = "";
output = String.Join("\\", parts, 0, parts.Length);
decimal step = 0;
int lean = 1;
do
{
parts[index] = "...";
output = String.Join("\\", parts, 0, parts.Length);
step = step + 0.5M;
lean = lean * -1;
index = startIndex + ((int)step * lean);
}
while (output.Length >= maxLength && index != -1);
return output;
}
EDIT
Below is an update with Merlin2001's corrections.
private string ShortenPath(string path, int maxLength)
{
int pathLength = path.Length;
string[] parts;
parts = path.Split('\\');
int startIndex = (parts.Length - 1) / 2;
int index = startIndex;
String output = "";
output = String.Join("\\", parts, 0, parts.Length);
decimal step = 0;
int lean = 1;
while (output.Length >= maxLength && index != 0 && index != -1)
{
parts[index] = "...";
output = String.Join("\\", parts, 0, parts.Length);
step = step + 0.5M;
lean = lean * -1;
index = startIndex + ((int)step * lean);
}
// result can be longer than maxLength
return output.Substring(0, Math.Min(maxLength, output.Length));
}
If you want to write you own solution to this problem, use build in classes like: FileInfo, Directory, etc... which makes it less error prone.
The following code produces "VS style" shortened path like: "C:\...\Folder\File.ext".
public static class PathFormatter
{
public static string ShrinkPath(string absolutePath, int limit, string spacer = "…")
{
if (string.IsNullOrWhiteSpace(absolutePath))
{
return string.Empty;
}
if (absolutePath.Length <= limit)
{
return absolutePath;
}
var parts = new List<string>();
var fi = new FileInfo(absolutePath);
string drive = Path.GetPathRoot(fi.FullName);
parts.Add(drive.TrimEnd('\\'));
parts.Add(spacer);
parts.Add(fi.Name);
var ret = string.Join("\\", parts);
var dir = fi.Directory;
while (ret.Length < limit && dir != null)
{
if (ret.Length + dir.Name.Length > limit)
{
break;
}
parts.Insert(2, dir.Name);
dir = dir.Parent;
ret = string.Join("\\", parts);
}
return ret;
}
}
Nearly all answers here shorten the path string by counting characters.
But this approach ignores the width of each character.
These are 30 'W' characters:
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
These are 30 'i' characters:
iiiiiiiiiiiiiiiiiiiiiiiiiiiiii
As you see, counting characters is not really useful.
And there is no need to write your own code because the Windows API has this functionaly since Windows 95.
The name of this functionality is "Path Ellipsis".
The Windows API DrawTextW() has a flag DT_PATH_ELLIPSIS which does exactly this.
In the .NET framwork this is available (without the need to use PInvoke) in the TextRenderer class.
There are 2 ways how this can be used:
1.) Drawing the path directly into a Label:
public class PathLabel : Label
{
protected override void OnPaint(PaintEventArgs e)
{
if (AutoSize)
throw new Exception("You must set "+Name+".AutoSize = false in VS "
+ "Designer and assign a fix width to the PathLabel.");
Color c_Fore = Enabled ? ForeColor : SystemColors.GrayText;
TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, c_Fore,
BackColor, TextFormatFlags.PathEllipsis);
}
}
This label requires you to turn AutoEllipsis off in Visual Studio Designer and assign a fix width to the Label (the maximum width that your path should occupy).
You even see the truncated path in Visual Studio Designer.
I entered a long path which does not fit into the label:
C:\WINDOWS\Installer{40BF1E83-20EB-11D8-97C5-0009C5020658}\ARPPRODUCTICON.exe
Even in Visual Studio Designer it is displayed like this:
2.) Shorten the path without drawing it on the screen:
public static String ShortenPath(String s_Path, Font i_Font, int s32_Width)
{
TextRenderer.MeasureText(s_Path, i_Font, new Size(s32_Width, 100),
TextFormatFlags.PathEllipsis | TextFormatFlags.ModifyString);
// Windows inserts a '\0' character into the string instead of shortening the string
int s32_Nul = s_Path.IndexOf((Char)0);
if (s32_Nul > 0)
s_Path = s_Path.Substring(0, s32_Nul);
return s_Path;
}
The flag TextFormatFlags.ModifyString inserts a '\0' character into the string. It is very unusual that a string is modified in C#.
Normally strings are unmutable.
This is because the underlying API DrawTextW() works this way.
But as the string is only shortened and never will become longer there is no risk of a buffer overflow.
The following code
String s_Text = #"C:\WINDOWS\Installer{40BF1E83-20EB-11D8-97C5-0009C5020658}\ARPPRODUCTICON.exe";
s_Text = ShortenPath(s_Text, new Font("Arial", 12), 500);
will result in "C:\WINDOWS\Installer{40BF1E83-20EB-1...\ARPPRODUCTICON.exe"