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
Related
Im trying to write a function complex_decode( string str) in c sharp that takes a non-simple repeated encoded string, and returns the original un-encoded string.
for example, "t11h12e14" would return "ttttttttttthhhhhhhhhhhheeeeeeeeeeeeee". I have been successful in decoding strings where the length is less than 10, but unable to work with length for than 10. I am not allowed to use regex, libraries or loops. Only recursions.
This is my code for simple decode which decodes when length less than 10.
public string decode(string str)
{
if (str.Length < 1)
return "";
if(str.Length==2)
return repeat_char(str[0], char_to_int(str[1]));
else
return repeat_char(str[0], char_to_int(str[1]))+decode(str.Substring(2));
}
public int char_to_int(char c)
{
return (int)(c-48);
}
public string repeat_char(char c, int n)
{
if (n < 1)
return "";
if (n == 1)
return ""+c;
else
return c + repeat_char(c, n - 1);
}
This works as intended, for example input "a5" returns "aaaaa", "t1h1e1" returns "the"
Any help is appreciated.
Here is another way of doing this, assuming the repeating string is always one character long and using only recursion (and a StringBuilder object):
private static string decode(string value)
{
var position = 0;
var result = decode_char(value, ref position);
return result;
}
private static string decode_char(string value, ref int position)
{
var next = value[position++];
var countBuilder = new StringBuilder();
get_number(value, ref position, countBuilder);
var result = new string(next, Convert.ToInt32(countBuilder.ToString()));
if (position < value.Length)
result += decode_char(value, ref position);
return result;
}
private static void get_number(string value, ref int position, StringBuilder countBuilder)
{
if (position < value.Length && char.IsNumber(value[position]))
{
countBuilder.Append(value[position++]);
get_number(value, ref position, countBuilder);
}
}
I've refactored your code a bit. I've removed 2 unnecessary methods that you don't actually need. So, the logic is simple and it works like this;
Example input: t3h2e4
Get the first digit. (Which is 2 and has index of 1)
Get the first letter comes after that index, which is our next letter. (Which is "h" and has index of 2)
Slice the string. Start from index 1 and end the slicing on index 2 to get repeat count. (Which is 3)
Repeat the first letter of string for repeat count times and combine it with the result you got from step 5.
Slice the starting from the next letter index we got in second step, to the very end of the string and pass this to recursive method.
public static string Decode(string input)
{
// If the string is empty or has only 1 character, return the string itself to not proceed.
if (input.Length <= 1)
{
return input;
}
// Convert string into character list.
var characters = new List<char>();
characters.AddRange(input);
var firstDigitIndex = characters.FindIndex(c => char.IsDigit(c)); // Get first digit
var nextLetterIndex = characters.FindIndex(firstDigitIndex, c => char.IsLetter(c)); // Get the next letter after that digit
if (nextLetterIndex == -1)
{
// This has only one reason. Let's say you are in the last recursion and you have c2
// There is no letter after the digit, so the index will -1, which means "not found"
// So, it will raise an exception, since we try to use the -1 in slicing part
// Instead, if it's not found, we set the next letter index to length of the string
// With doing that, you either get repeatCount correctly (since remaining part is only digits)
// or you will get empty string in the next recursion, which will stop the recursion.
nextLetterIndex = input.Length;
}
// Let's say first digit's index is 1 and the next letter's index is 2
// str[2..3] will start to slice the string from index 2 and will stop in index 3
// So, it will basically return us the repeat count.
var repeatCount = int.Parse(input[firstDigitIndex..nextLetterIndex]);
// string(character, repeatCount) constructor will repeat the "character" you passed to it for "repeatCount" times
return new string(input[0], repeatCount) + Decode(input[nextLetterIndex..]);
}
Examples;
Console.WriteLine(Decode("t1h1e1")); // the
Console.WriteLine(Decode("t2h3e4")); // tthhheeee
Console.WriteLine(Decode("t3h3e3")); // ttthhheee
Console.WriteLine(Decode("t2h10e2")); // tthhhhhhhhhhee
Console.WriteLine(Decode("t2h10e10")); // tthhhhhhhhhheeeeeeeeee
First you can simplify your repeat_char function, you have to have a clear stop condition:
public static string repeat_char(char c, int resultLength)
{
if(resultLength < 1) throw new ArgumentOutOfRangeException("resultLength");
if(resultLength == 1) return c.ToString();
return c + repeat_char(c, resultLength - 1);
}
See the use of the parameter as equivalent of a counter on a loop.
So you can have something similar on the main function, a parameter that tells when your substring is not an int anymore.
public static string decode(string str, int repeatNumberLength = 1)
{
if(repeatNumberLength < 1) throw new ArgumentOutOfRangeException("length");
//stop condition
if(string.IsNullOrWhiteSpace(str)) return str;
if(repeatNumberLength >= str.Length) repeatNumberLength = str.Length; //Some validation, just to be safe
//keep going until str[1...repeatNumberLength] is not an int
int charLength;
if(repeatNumberLength < str.Length && int.TryParse(str.Substring(1, repeatNumberLength), out charLength))
{
return decode(str, repeatNumberLength + 1);
}
repeatNumberLength--;
//Get the repeated Char.
charLength = int.Parse(str.Substring(1, repeatNumberLength));
var repeatedChar = repeat_char(str[0], charLength);
//decode the substring
var decodedSubstring = decode(str.Substring(repeatNumberLength + 1));
return repeatedChar + decodedSubstring;
}
I used a default parameter, but you can easily change it for a more traditonal style.
This also assumes that the original str is in a correct format.
An excellent exercise is to change the function so that you can have a word, instead of a char before the number. Then you could, for example, have "the3" as the parameter (resulting in "thethethe").
I took more of a Lisp-style head and tail approach (car and cdr if you speak Lisp) and created a State class to carry around the current state of the parsing.
First the State class:
internal class State
{
public State()
{
LastLetter = string.Empty;
CurrentCount = 0;
HasStarted = false;
CurrentValue = string.Empty;
}
public string LastLetter { get; private set; }
public int CurrentCount { get; private set; }
public bool HasStarted { get; private set; }
public string CurrentValue { get; private set; }
public override string ToString()
{
return $"LastLetter: {LastLetter}, CurrentCount: {CurrentCount}, HasStarted: {HasStarted}, CurrentValue: {CurrentValue}";
}
public void AddLetter(string letter)
{
CurrentCount = 0;
LastLetter = letter;
HasStarted = true;
}
public int AddDigit(string digit)
{
if (!HasStarted)
{
throw new InvalidOperationException($"The input must start with a letter, not a digit");
}
if (!int.TryParse(digit, out var num))
{
throw new InvalidOperationException($"Digit passed to {nameof(AddDigit)} ({digit}) is not a number");
}
CurrentCount = CurrentCount * 10 + num;
return CurrentCount;
}
public string GetValue()
{
if (string.IsNullOrEmpty(LastLetter))
{
return string.Empty;
}
CurrentValue = new string(LastLetter[0], CurrentCount);
return CurrentValue;
}
}
You'll notice it's got some stuff in there for debugging (example, the ToString override and the CurrentValue property)
Once you have that, the decoder is easy, it just recurses over the string it's given (along with (initially) a freshly constructed State instance):
private string Decode(string input, State state)
{
if (input.Length == 0)
{
_buffer.Append(state.GetValue());
return _buffer.ToString();
}
var head = input[0];
var tail = input.Substring(1);
var headString = head.ToString();
if (char.IsDigit(head))
{
state.AddDigit(headString);
}
else // it's a character
{
_buffer.Append(state.GetValue());
state.AddLetter(headString);
}
Decode(tail, state);
return _buffer.ToString();
}
I did this in a simple Windows Forms app, with a text box for input, a label for output and a button to crank her up:
const string NotAllowedPattern = #"[^a-zA-Z0-9]";
private static Regex NotAllowedRegex = new Regex(NotAllowedPattern);
private StringBuilder _buffer = new StringBuilder();
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Length == 0 || NotAllowedRegex.IsMatch(textBox1.Text))
{
MessageBox.Show(this, "Only Letters and Digits Allowed", "Bad Input", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
label1.Text = string.Empty;
_buffer.Clear();
var result = Decode(textBox1.Text, new State());
label1.Text = result;
}
Yeah, there's a Regex there, but it's just to make sure that the input is valid; it's not involved in calculating the output.
I have to make a string which consists a string like - AAA0009, and once it reaches AAA0009, it will generate AA0010 to AAA0019 and so on.... till AAA9999 and when it will reach to AAA9999, it will give AAB0000 to AAB9999 and so on till ZZZ9999.
I want to use static class and static variables so that it can auto increment by itself on every hit.
I have tried some but not even close, so help me out thanks.
Thanks for being instructive I was trying as I Said already but anyways you already want to put negatives over there without even knowing the thing:
Code:
public class GenerateTicketNumber
{
private static int num1 = 0;
public static string ToBase36()
{
const string base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var sb = new StringBuilder(9);
do
{
sb.Insert(0, base36[(byte)(num1 % 36)]);
num1 /= 36;
} while (num1 != 0);
var paddedString = "#T" + sb.ToString().PadLeft(8, '0');
num1 = num1 + 1;
return paddedString;
}
}
above is the code. this will generate a sequence but not the way I want anyways will use it and thanks for help.
Though there's already an accepted answer, I would like to share this one.
P.S. I do not claim that this is the best approach, but in my previous work we made something similar using Azure Table Storage which is a no sql database (FYI) and it works.
1.) Create a table to store your running ticket number.
public class TicketNumber
{
public string Type { get; set; } // Maybe you want to have different types of ticket?
public string AlphaPrefix { get; set; }
public string NumericPrefix { get; set; }
public TicketNumber()
{
this.AlphaPrefix = "AAA";
this.NumericPrefix = "0001";
}
public void Increment()
{
int num = int.Parse(this.NumericPrefix);
if (num + 1 >= 9999)
{
num = 1;
int i = 2; // We are assuming that there are only 3 characters
bool isMax = this.AlphaPrefix == "ZZZ";
if (isMax)
{
this.AlphaPrefix = "AAA"; // reset
}
else
{
while (this.AlphaPrefix[i] == 'Z')
{
i--;
}
char iChar = this.AlphaPrefix[i];
StringBuilder sb = new StringBuilder(this.AlphaPrefix);
sb[i] = (char)(iChar + 1);
this.AlphaPrefix = sb.ToString();
}
}
else
{
num++;
}
this.NumericPrefix = num.ToString().PadLeft(4, '0');
}
public override string ToString()
{
return this.AlphaPrefix + this.NumericPrefix;
}
}
2.) Make sure you perform row-level locking and issue an error when it fails.
Here's an oracle syntax:
SELECT * FROM TICKETNUMBER WHERE TYPE = 'TYPE' FOR UPDATE NOWAIT;
This query locks the row and returns an error if the row is currently locked by another session.
We need this to make sure that even if you have millions of users generating a ticket number, it will not mess up the sequence.
Just make sure to save the new ticket number before you perform a COMMIT.
I forgot the MSSQL version of this but I recall using WITH (ROWLOCK) or something. Just google it.
3.) Working example:
static void Main()
{
TicketNumber ticketNumber = new TicketNumber();
ticketNumber.AlphaPrefix = "ZZZ";
ticketNumber.NumericPrefix = "9999";
for (int i = 0; i < 10; i++)
{
Console.WriteLine(ticketNumber);
ticketNumber.Increment();
}
Console.Read();
}
Output:
Looking at your code that you've provided, it seems that you're backing this with a number and just want to convert that to a more user-friendly text representation.
You could try something like this:
private static string ValueToId(int value)
{
var parts = new List<string>();
int numberPart = value % 10000;
parts.Add(numberPart.ToString("0000"));
value /= 10000;
for (int i = 0; i < 3 || value > 0; ++i)
{
parts.Add(((char)(65 + (value % 26))).ToString());
value /= 26;
}
return string.Join(string.Empty, parts.AsEnumerable().Reverse().ToArray());
}
It will take the first 4 characters and use them as is, and then for the remainder of the value if will convert it into characters A-Z.
So 9999 becomes AAA9999, 10000 becomes AAB0000, and 270000 becomes ABB0000.
If the number is big enough that it exceeds 3 characters, it will add more letters at the start.
Here's an example of how you could go about implementing it
void Main()
{
string template = #"AAAA00";
var templateChars = template.ToCharArray();
for (int i = 0; i < 100000; i++)
{
templateChars = IncrementCharArray(templateChars);
Console.WriteLine(string.Join("",templateChars ));
}
}
public static char Increment(char val)
{
if(val == '9') return 'A';
if(val == 'Z') return '0';
return ++val;
}
public static char[] IncrementCharArray(char[] val)
{
if (val.All(chr => chr == 'Z'))
{
var newArray = new char[val.Length + 1];
for (int i = 0; i < newArray.Length; i++)
{
newArray[i] = '0';
}
return newArray;
}
int length = val.Length;
while (length > -1)
{
char lastVal = val[--length];
val[length] = Increment(lastVal);
if ( val[length] != '0') break;
}
return val;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have a string that may contain any letter
string uncompressed = "dacacacd";
I need to compress this string in the format
string compressed = "d3(ac)d";
But also compress any substring if possible ex:
string uncompressed = "dabcabcdabcabc";
string compressed = "2(d2(abc))";
Is there a way to achieve this without any third party library?
Here's an example that will do the compression based on the longest sub-strings first. Maybe not the most efficient or best compression for something like "abababcabc" but should at least get you started.
public class CompressedString
{
private class Segment
{
public Segment(int count, CompressedString value)
{
Count = count;
Value = value;
}
public int Count { get; set; }
public CompressedString Value { get; set; }
}
private List<Segment> segments = new List<Segment>();
private string uncompressible;
private CompressedString(){}
public static CompressedString Compress(string s)
{
var compressed = new CompressedString();
// longest possible repeating substring is half the length of the
// string, so try that first and work down to shorter lengths
for(int len = s.Length/2; len > 0; len--)
{
// look for the substring at each possible index
for(int i = 0; i < s.Length - len - 1; i++)
{
var sub = s.Substring(i, len);
int count = 1;
// look for repeats of the substring immediately after it.
for(int j = i + len; j <= s.Length - len; j += len)
{
// increase the count of times the substring is found
// or stop looking when it doesn't match
if(sub == s.Substring(j, len))
{
count++;
}
else
{
break;
}
}
// if we found repeats then handle the substring before the
// repeats, the repeast, and everything after.
if(count > 1)
{
// if anything is before the repeats then add it to the
// segments with a count of one and compress it.
if (i > 0)
{
compressed.segments.Add(new Segment(1, Compress(s.Substring(0, i))));
}
// Add the repeats to the segments with the found count
// and compress it.
compressed.segments.Add(new Segment(count, Compress(sub)));
// if anything is after the repeats then add it to the
// segments with a count of one and compress it.
if (s.Length - (count * len) > i)
{
compressed.segments.Add(new Segment(1, Compress(s.Substring(i + (count * len)))));
}
// We're done compressing so break this loop and the
// outer by setting len to 0.
len = 0;
break;
}
}
}
// If we failed to find any repeating substrings then we just have
// a single uncompressible string.
if (!compressed.segments.Any())
{
compressed.uncompressible = s;
}
// Reduce the the compression for something like "2(2(ab))" to "4(ab)"
compressed.Reduce();
return compressed;
}
private void Reduce()
{
// Attempt to reduce each segment.
foreach(var seg in segments)
{
seg.Value.Reduce();
// If there is only one sub segment then we can reduce it.
if(seg.Value.segments.Count == 1)
{
var subSeg = seg.Value.segments[0];
seg.Value = subSeg.Value;
seg.Count *= subSeg.Count;
}
}
}
public override string ToString()
{
if(segments.Any())
{
StringBuilder builder = new StringBuilder();
foreach(var seg in segments)
{
if (seg.Count == 1)
builder.Append(seg.Value.ToString());
else
{
builder.Append(seg.Count).Append("(").Append(seg.Value.ToString()).Append(")");
}
}
return builder.ToString();
}
return uncompressible;
}
}
Code example:
using System;
public class Test {
public static void Main() {
int a = 0;
if(a++ == 0){
Console.WriteLine(a);
}
}
}
In this code the Console will write: 1. I can write this code in another way:
public static void Main() {
int a = 0;
if(a == 0){
a++;
Console.WriteLine(a);
}
}
These two examples work exactly the same (from what I know about postfix).
The problem is with this example coming from the Microsoft tutorials:
using System;
public class Document {
// Class allowing to view the document as an array of words:
public class WordCollection {
readonly Document document;
internal WordCollection (Document d){
document = d;
}
// Helper function -- search character array "text", starting
// at character "begin", for word number "wordCount". Returns
//false if there are less than wordCount words. Sets "start" and
//length to the position and length of the word within text
private bool GetWord(char[] text, int begin, int wordCount,
out int start, out int length) {
int end = text.Length;
int count = 0;
int inWord = -1;
start = length = 0;
for (int i = begin; i <= end; ++i){
bool isLetter = i < end && Char.IsLetterOrDigit(text[i]);
if (inWord >= 0) {
if (!isLetter) {
if (count++ == wordCount) {//PROBLEM IS HERE!!!!!!!!!!!!
start = inWord;
length = i - inWord;
return true;
}
inWord = -1;
}
} else {
if (isLetter) {
inWord = i;
}
}
}
return false;
}
//Indexer to get and set words of the containing document:
public string this[int index] {
get
{
int start, length;
if(GetWord(document.TextArray, 0, index, out start,
out length)) {
return new string(document.TextArray, start, length);
} else {
throw new IndexOutOfRangeException();
}
}
set {
int start, length;
if(GetWord(document.TextArray, 0, index, out start,
out length))
{
//Replace the word at start/length with
// the string "value"
if(length == value.Length){
Array.Copy(value.ToCharArray(), 0,
document.TextArray, start, length);
}
else {
char[] newText = new char[document.TextArray.Length +
value.Length - length];
Array.Copy(document.TextArray, 0, newText, 0, start);
Array.Copy(value.ToCharArray(), 0, newText, start, value.Length);
Array.Copy(document.TextArray, start + length, newText,
start + value.Length, document.TextArray.Length - start - length);
document.TextArray = newText;
}
} else {
throw new IndexOutOfRangeException();
}
}
}
public int Count {
get {
int count = 0, start = 0, length = 0;
while (GetWord(document.TextArray, start + length,
0, out start, out length)) {
++count;
}
return count;
}
}
}
// Class allowing the document to be viewed like an array
// of character
public class CharacterCollection {
readonly Document document;
internal CharacterCollection(Document d) {
document = d;
}
//Indexer to get and set character in the containing
//document
public char this[int index] {
get {
return document.TextArray[index];
}
set {
document.TextArray[index] = value;
}
}
//get the count of character in the containing document
public int Count {
get {
return document.TextArray.Length;
}
}
}
//Because the types of the fields have indexers,
//these fields appear as "indexed properties":
public WordCollection Words;
public readonly CharacterCollection Characters;
private char[] TextArray;
public Document(string initialText) {
TextArray = initialText.ToCharArray();
Words = new WordCollection(this);
Characters = new CharacterCollection(this);
}
public string Text {
get {
return new string(TextArray);
}
}
class Test {
static void Main() {
Document d = new Document(
"peter piper picked a peck of pickled peppers. How many pickled peppers did peter piper pick?"
);
//Change word "peter" to "penelope"
for(int i = 0; i < d.Words.Count; ++i){
if (d.Words[i] == "peter") {
d.Words[i] = "penelope";
}
}
for (int i = 0; i < d.Characters.Count; ++i) {
if (d.Characters[i] == 'p') {
d.Characters[i] = 'P';
}
}
Console.WriteLine(d.Text);
}
}
}
If I change the code marked above to this:
if (count == wordCount) {//PROBLEM IS HERE
start = inWord;
length = i - inWord;
count++;
return true;
}
I get an IndexOutOfRangeException, but I don't know why.
Your initial assumption is incorrect (that the two examples work exactly the same). In the following version, count is incremented regardless of whether or not it is equal to wordCount:
if (count++ == wordCount)
{
// Code omitted
}
In this version, count is ONLY incremented when it is equal to wordCount
if (count == wordCount)
{
// Other code omitted
count++;
}
EDIT
The reason this is causing you a failure is that, when you are searching for the second word (when wordCount is 1), the variable count will never equal wordCount (because it never gets incremented), and therefore the GetWord method returns false, which then triggers the else clause in your get method, which throws an IndexOutOfRangeException.
In your version of the code, count is only being incremented when count == wordCount; in the Microsoft version, it's being incremented whether the condition is met or not.
using System;
public class Test {
public static void Main() {
int a = 0;
if(a++ == 0){
Console.WriteLine(a);
}
}
}
Is not quite the same as:
public static void Main() {
int a = 0;
if(a == 0){
a++;
Console.WriteLine(a);
}
}
In the second case a++ is executed only if a == 0. In the first case a++ is executed every time we check the condition.
There is your mistake:
public static void Main() {
int a = 0;
if(a == 0){
a++;
Console.WriteLine(a);
}
}
It should be like this:
public static void Main() {
int a = 0;
if(a == 0){
a++;
Console.WriteLine(a);
}
else
a++;
}
a gets alwasy increased. This means, that in your code example count will get only increased when count == wordCount (In which case the method will return true anyway...). You basicly never increasing count.
I have a Listbox in a SplitterPanel. I have overriden it's MeasureItem() and DrawItem() methods.
What I want to do is, depending on Listbox.Width, return either the entire string or a shortened version of it, like "Dance toni...".
I've browsed SO and found two questions that pertain to my problem. One of the problems is measuring the width of the text, which I am doing with e.Graphics.MeasureString() in DrawItem().
Summary - I have the width of a listbox, and the width, in pixels, of a string. If the string is shorter than the width of a listbox, I want to display the string in entirety. However, if it's longer, I would like to return a version like "Hello every..." that would fit in within the width of the listbox.
So far I have:
private string FitText(string s)
{
int width = (TextRenderer.MeasureText(s, titleFont)).Width;
if (width <= mailList.Width)
{
return s;
}
else if (width > mailList.Width)
{
// What goes here?
}
}
I'm pretty sure it's just simple math, but I still can't figure it out.
i think you would need check if it fits, if so, return the whole string, otherwise modify your code to run a loop that keeps measuring the size of s minus one more character and plus the ellipsis, until it fits or until there are no more characters left, and then return that, or just the ellipsis otherwise.
string EllipsisString = "..."; // you could also just set this as the unicode ellipsis char if that displays properly
private string FitText(string s)
{
bool WidthFound = true;
string TestString = s;
string StringToReturn = s;
int width = (TextRenderer.MeasureText(s, titleFont)).Width;
if (width > mailList.Width)
{
WidthFound = false;
for (int i=1; i < s.Length; ++i)
{
TestString = s.Substring(0, s.Length - i) + EllipsisString;
width = (TextRenderer.MeasureText(TestString, titleFont)).Width;
if (width <= mailList.Width)
{
StringToReturn = TestString;
WidthFound = true;
break;
}
}
}
if (WidthFound)
return StringToReturn;
else
return EllipsisString;
}
[edits: too many to name]
Here's the pseudocode I'd use...
1) Shorten the string in some form (remove the last character/word)
2) Retest the length against width
3) Insert of valid repeat if not
4) If string is too short use some default form
String s = "A long string that you're trying to fit into the button."
while (width > mailList.Width) {
s = s.SubString(0,s.lastIndexOf(" ")-1); //Change this to whatever you'd want to shorten the string by
width = (TextRenderer.MeasureText(s, titleFont)).Width;
if (width < 5) { //Some value indicating it's too short
s = "Button...";
break;
}
}
return s;
http://msdn.microsoft.com/en-us/library/aa904308%28v=vs.71%29.aspx
string ts = s;
while((TextRenderer.MeasureText(ts, titleFont)).Width > mailList.Width + (TextRenderer.MeasureText("...", titleFont)).Width)
{
ts = ts.SubString(0,ts.Length-1);
}
return ts + "..."