There might be some workaround for this one - however, I'm not sure what it is at the moment. After setting the MaxLength property of a textbox, I am unable to manually exceed the MaxLength of the textBox. On the other hand, if I were to create a loop which programmatically added characters to the textbox - this loop could exceed the maxLength property.
textBox1.MaxLength = 5; // I am now unable to manually type in more than 5 chars.
for (int i = 0; i < 20; i++)
{
textBox1.AppendText("D");
}
// Textbox now holds 20 chars.
Without having to write more lines of code to take a portion of this data, is there a way to ensure that the maxlength property is not exceeded?
Regards,
Evan
MaxLength: Gets or sets the maximum number of characters the user can type or paste into the text box control. (Forms) http://msdn.microsoft.com/en-us/library/system.windows.forms.textboxbase.maxlength.aspx and Gets or sets the maximum number of characters allowed in the text box. (web) http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.textbox.maxlength.aspx
In other words, that's the point of MaxLength - it's all about controlling user input. Since you own the textbox to begin with, you don't need to set your own hard programmatic restrictions.
So in short, no - you can't change this behavior without overriding some other functionality - for instance on OnChanged - or adding the conditional tests like those shown by Ben and Sres.
From the MSDN docs:
In code, you can set the value of the
Text property to a value that has a
length greater than the value
specified by the MaxLength property.
This property only affects text
entered into the control at run time.
If you want to prevent Text from being longer than MaxLength, some extra code is needed.
How about:
textBox1.MaxLength = 5;
for (int i = 0; i < 20 && i < textBox1.MaxLength; i++)
{
textBox1.AppendText("D");
}
Not sure if that counts as "more lines of code" but it's a pretty simple extra check.
textBox1.MaxLength = 5;
while(textBox1.Text.Length <= textBox1.MaxLength)
textBox1.AppendText ("D");
This should do it I believe
MaxLength property prevent user to type more than n characters. but when you set the Text property programatically,your textbox will show the value of its Text property even if its length exceed the value MaxLength
so you have to check if your loop exceed the maxlength or not.
As far as I know setting the maximum width of a textbox only enforce this restriction to end user who is entering values thorough UI. This restriction doesn't apply on code
MaxLength is used when you don't want the user to be able to input more than the assigned amount. However, programatically, it can be overridden. This is what append text does:
public void AppendText(string text)
{
if (text.Length > 0)
{
int start;
int length;
this.GetSelectionStartAndLength(out start, out length);
try
{
int endPosition = this.GetEndPosition();
this.SelectInternal(endPosition, endPosition, endPosition);
this.SelectedText = text;
}
finally
{
if (base.Width == 0 || base.Height == 0)
{
this.Select(start, length);
}
}
}
}
You could write an extension method, and use it to append text instead of .AppendText()
void Main()
{
var t = new TextBox();
t.MaxLength=5;
t.Text = "123";
t.AppendTextRespectMaxLength("456789");
t.Text.Dump(); // prints 12345
}
public static class ExtensionMethods
{
public static void AppendTextRespectMaxLength(this TextBox textbox,string newText)
{
if(textbox.Text.Length + newText.Length <= textbox.MaxLength)
{
textbox.Text += newText;
}
else
{
var remaining = textbox.MaxLength - textbox.Text.Length;
var subPortion = newText.Substring(0,remaining);
textbox.Text += subPortion;
}
}
}
Related
I need to show a progress bar that have negative values, but when i try to modify the value to a negative number, the c# gets an error (invalid property error). Does anyone knows any method to create a negative value progress bar?
HPHeroi.Maximum = CriacaoDePersonagem.protagonista.status.Vida;
HPHeroi.Minimum = -20;
Does anyone knows any method to create a negative value progress bar?
You cannot. From the documentation:
Exceptions
ArgumentException
The value specified for the property is less than 0.
Instead, what you need to do is offset the entire range of the progress bar to account for the negative value. E.g.:
HPHeroi.Maximum = CriacaoDePersonagem.protagonista.status.Vida + 20;
HPHeroi.Minimum = 0;
Then you need to also account for that when you set the current value of the ProgressBar, e.g.:
HPHeroi.Value = CriacaoDePersonagem.protagonista.status.ActualVida + 20;
The above strategy can be encapsulated in a UserControl that wraps a ProgressBar, exposing the various value-related properties but using an offset to ensure that the actual ProgressBar object doesn't see negative values.
For example:
public partial class ProgressBarWithNegativeValues : UserControl, INotifyPropertyChanged
{
private int _offset;
public ProgressBarWithNegativeValues()
{
InitializeComponent();
}
public int Minimum
{
get => progressBar1.Minimum + _offset;
set
{
int offsetChange = value - _offset;
_offset = value;
progressBar1.Maximum -= offsetChange;
_RaisePropertyChanged();
}
}
public int Maximum
{
get => progressBar1.Maximum + _offset;
set
{
progressBar1.Maximum = value - _offset;
_RaisePropertyChanged();
}
}
public int Value
{
get => progressBar1.Value + _offset;
set
{
progressBar1.Value = value - _offset;
_RaisePropertyChanged();
}
}
public int Step
{
get => progressBar1.Step;
set
{
progressBar1.Step = value;
_RaisePropertyChanged();
}
}
public void Increment(int step) => progressBar1.Increment(step);
public void PerformStep() => progressBar1.PerformStep();
public event PropertyChangedEventHandler PropertyChanged;
private void _RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I've omitted the *.Designer.cs code because that's just a single ProgressBar object dropped onto the UserControl with its Dock property set to Fill.
Note in the above that the ProgressBar.Minimum property is always left at 0, and the other properties offset accordingly, whether the minimum value is negative or positive. This keeps the code nice and simple instead of trying to deal with the negative and positive cases separately.
As Peter have stated, a progress bar can not hold a negative number. Therefore you can not use a Progress bar for this.
What I suggest, is instead of using a progress bar, use a track bar and disable it (set it's Enabled property to false).
Therefore, Imagine HPHeroi is a TrackBar object:
HPHeroi.Maximum = CriacaoDePersonagem.protagonista.status.Vida;
HPHeroi.Minimum = -20;
The code above will not result in a runtime error.
Keep in mind, there might be 2 more runtime errors that will occur when you reach the Maximum and Minimum values. To overcome them, add an if statement before each subtraction and addition of the HPHeroi's value (remember, it is a TrackBar now).
If statement example for subtraction:
if (HPHeroi.Value > HPHeroi.Minimum)
HPHeroi.Value--;
If statement example for addition:
if (HPHeroi.Value < HPHeroi.Maximum)
HPHeroi.Value++;
P.S. If you want, you can add a lable with "0" as content and put it under the line of the value of 0 in the track bar so that the user will know when the value is positive and when it is negative.
ProgressBar has a minimum value of 0, but the maximum can be quite high.
If you need it to represent a negative value, just use an offset.
int Offset = 20;
HPHeroi.Maximum = CriacaoDePersonagem.protagonista.status.Vida + Offset;
HPHeroi.Minimum = 0;
When you set the value of HPHeroi, simply add Offset to the new value
HPHeroi.Value = newvalue + Offset
newvalue can therefore be anything from -20 to CriacaoDePersonagem.protagonista.status.Vida, the range you are trying to specify, and your ProgressBar will show that.
I am creating a calculator app in visual studio. I created some buttons in windows form that will input numbers in a textbox. Since the input did not came from a keyborad, the MaxLength properties is not working for me. I set the textbox to read only so that the user can only input through the buttons. How can I set the character limits (characters because I add "," in thousands, ten thousands etc. I only allow 12 digits + the 3 commas making a total of 15 characters in a textbox) that in a textbox that is filled with buttons?
You can create a custom TextBox that ensures the text is never larger than the MaxLength property.
class RestrictedTextBox : TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (value.Length > MaxLength)
base.Text = value.Substring(0, MaxLength);
else
base.Text = value;
}
}
}
Really need more information as to what type of app your using to build the calculator like WPF/Winforms/Web.
Since your using a UI element, and this is strictly a UI display you could do this in the code behind file for the UI page.
You'll need to check the length of the textbox to determine if the length is under whatever your limit is, and if so then add the button's value to the the text property for that textbox
something like the following
If (textbox.Text.Length < 15)
textbox.Text += Button.Content.Value
As for inserting the commas you'll again need to check the length and can insert a comma at the correct spot when needed.
i.e for instance consider this sentence. "This is my sentence." I want the program to display highlighting first 'This' then 'is' and so on. can this actually be done? should i use a timer ? help with brief explanation is greatly appreciated. Thanks in advance.
A timer is a good option if you don't want the UI to be blocked all the time. A very basic solution for your problem is the following:
Add this to your initialization code:
// index of highlighted text block
var i = 0;
var timer = new Timer()
{
Interval = 300
};
timer.Tick += new EventHandler((sender, e) =>
{
// split the elements to highlight by space character
var textElements = this.richTextBox1.Text
.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries)
.ToArray();
// avoid dividing by zero when using modulo operator
if (textElements.Length > 0)
{
// start all over again when the end of text is reached.
i = i % textElements.Length;
// clear the RichTextBox
this.richTextBox1.Text = string.Empty;
for (var n = 0; n < textElements.Length; n++)
{
// now adding each text block again
// choose color depending on the index
this.richTextBox1.AppendText(textElements[n] + ' ', i == n ? Color.Red : Color.Black);
}
// increment the index for the next run
i++;
}
});
timer.Start();
This solution uses an extension method. To use this, you must add an extension class like this:
static class RichTextBoxExtensions
{
public static void AppendText(this RichTextBox richtTextBox, string text, Color color)
{
richtTextBox.SelectionStart = richtTextBox.TextLength;
richtTextBox.SelectionLength = 0;
richtTextBox.SelectionColor = color;
richtTextBox.AppendText(text);
richtTextBox.SelectionColor = richtTextBox.ForeColor;
}
}
You can get more information about the extension method I used here.
The drawback of this solution is that the RichTextBox is not realy useable while the highlighting is going on. If you want the user to input some text, you should stop the timer first.
we use this two methods to adjust column length based on Column content and header resp.
ListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
ListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
But how to adjust based on both? i.e. adjust to the longest length for header and column content.
lvw.Columns[0].Width = -2
See remarks in MSDN for details:
http://msdn.microsoft.com/en-us/library/system.windows.forms.columnheader.width.aspx
Also note that MSDN says that 'To autosize to the width of the column heading, set the Width property to -2.', but actually it works for column heading AND column contents.
Here is a code to prove that:
lvw.Columns.Add(new String('x', 25)); // short header
lvw.Items.Add(new String('x', 100)); // long content
lvw.Columns[0].Width = -2;
// in result column width will be set to fit content
As answered here, calling both resizing options do the job :
myListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
myListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
This is what I use to adjust column width to both content and header:
public static void autoResizeColumns(ListView lv)
{
lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
ListView.ColumnHeaderCollection cc = lv.Columns;
for (int i = 0; i < cc.Count; i++)
{
int colWidth = TextRenderer.MeasureText(cc[i].Text, lv.Font).Width + 10;
if (colWidth > cc[i].Width)
{
cc[i].Width = colWidth;
}
}
}
Example use:
autoResizeColumns(listView1);
The method isn't that well tested, but at least it works in the context I'm using it in.
It's possible indeed to use MeasureText and then to calculate how much space is left and somehow distribute between all columns. But this is quick-and-dirty approach which I have quickly coded:
/// <summary>
/// Enables autoresizing for specific listview.
/// You can specify how much to scale in columnScaleNumbers array - length of that array
/// should match column count which you have.
/// </summary>
/// <param name="listView">control for which to enable auto-resize</param>
/// <param name="columnScaleNumbers">Percentage or numbers how much each column will be scaled.</param>
private void EnableAutoresize(ListView listView, params int[] columnScaleNumbers)
{
listView.View = View.Details;
for( int i = 0; i < columnScaleNumbers.Length; i++ )
{
if( i >= listView.Columns.Count )
break;
listView.Columns[i].Tag = columnScaleNumbers[i];
}
listView.SizeChanged += lvw_SizeChanged;
DoResize(listView);
}
void lvw_SizeChanged(object sender, EventArgs e)
{
ListView listView = sender as ListView;
DoResize(listView);
}
bool Resizing = false;
void DoResize( ListView listView )
{
// Don't allow overlapping of SizeChanged calls
if (!Resizing)
{
// Set the resizing flag
Resizing = true;
if (listView != null)
{
float totalColumnWidth = 0;
// Get the sum of all column tags
for (int i = 0; i < listView.Columns.Count; i++)
totalColumnWidth += Convert.ToInt32(listView.Columns[i].Tag);
// Calculate the percentage of space each column should
// occupy in reference to the other columns and then set the
// width of the column to that percentage of the visible space.
for (int i = 0; i < listView.Columns.Count; i++)
{
float colPercentage = (Convert.ToInt32(listView.Columns[i].Tag) / totalColumnWidth);
listView.Columns[i].Width = (int)(colPercentage * listView.ClientRectangle.Width);
}
}
}
// Clear the resizing flag
Resizing = false;
}
And depending how many columns you have - you specify each column "percentage" or simply number. For example for 3 columns - call looks like this:
EnableAutoresize(listView1, 6, 3, 1);
This will distribute column sizes as:
6 * 100% / (6 + 3 + 1) = 60% for first column,
30% for next and 10% for remaining.
This is somehow poor man quick implementation. :-)
In my case, I do this through the next steps (for two columns of data):
Creating a ColumnHeader object for each column.
Setting the size by AutoResize based on HeaderSize (on both columns)
Store that value in a Integer variable
Setting the size by AutoResize based on ColumnContent (on both columns)
Updating the value of each Integer variable through the Max criteria between the old value and the new value (for each column).
Setting the column width size for each ColumnHeader object.
In VB.NET:
'Create two header objects as ColumnHeader Class
Dim header1, header2 As ColumnHeader
'Construcción de los objetos header
header1 = New ColumnHeader
header1.Text = "ID"
header1.TextAlign = HorizontalAlignment.Right
header1.Width = 10
header2 = New ColumnHeader
header2.Text = "Combinaciones a Procesar"
header2.TextAlign = HorizontalAlignment.Left
header2.Width = 10
'Add two columns using your news headers objects
ListView.Columns.Add(header1)
ListView.Columns.Add(header2)
'Fill three rows of data, for each column
ListView.Items.Add(New ListViewItem({"A1", "B1"}))
ListView.Items.Add(New ListViewItem({"A2", "B2"}))
ListView.Items.Add(New ListViewItem({"A3", "B3"}))
'Change the size of each column
Dim headsz1, headsz2 As Integer
SelectionInTable.ListView.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.HeaderSize)
SelectionInTable.ListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.HeaderSize)
headsz1 = header1.Width
headsz2 = header2.Width
SelectionInTable.ListView.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.ColumnContent)
SelectionInTable.ListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent)
headsz1 = Math.Max(headsz1, header1.Width)
headsz2 = Math.Max(headsz2, header2.Width)
header1.Width = headsz1
header2.Width = headsz2
Here's a C# solution that can be used for any ListView. It assumes your column count and headers won't change for any given list view. Get rid of the listViewHeaderWidths dictionary if you want to recalculate header widths every time (if headers change, or number of columns changes).
private Dictionary<string, int[]> listViewHeaderWidths = new Dictionary<string, int[]>();
private void ResizeListViewColumns(ListView lv)
{
int[] headerWidths = listViewHeaderWidths.ContainsKey(lv.Name) ? listViewHeaderWidths[lv.Name] : null;
lv.BeginUpdate();
if (headerWidths == null)
{
lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
headerWidths = new int[lv.Columns.Count];
for (int i = 0; i < lv.Columns.Count; i++)
{
headerWidths[i] = lv.Columns[i].Width;
}
listViewHeaderWidths.Add(lv.Name, headerWidths);
}
lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
for(int j = 0; j < lv.Columns.Count; j++)
{
lv.Columns[j].Width = Math.Max(lv.Columns[j].Width, headerWidths[j]);
}
lv.EndUpdate();
}
Anton Kedrov answer is best one but in my case i have a listview with more than 50 columns and i update its data frequently in this case i notice listview's this.AutoResizeColumns performs much faster work so i m writing this solution also
First Method by setting with to -2
public void AutoUpdateColumnWidth(ListView lv)
{
for (int i = 0; i <= lv.Columns.Count - 1; i++) {
lv.Columns(i).Width = -2;
}
}
Second method i used (less flicker on multiple calls)
public void AutoUpdateColumnWidth(ListView lv)
{
ListViewItem nLstItem = new ListViewItem(lv.Columns(0).Text);
for (int i = 1; i <= lv.Columns.Count - 1; i++) {
nLstItem.SubItems.Add(lv.Columns(i).Text);
}
v.Items.Add(nLstItem);
lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
lv.Items.RemoveAt(nLstItem.Index);
}
This is simple (although it took me a while to figure out)...
We know that the width must be at least as great as the column headers, so that we see all of the header text. Beyond that, the width can expand larger to accommodate contents. Hence, we do the following:
Autosize the columns to header.
Iterate through the columns and set the minimum width property for each column to the current column width (which guarantees your columns will never get too small to see the header).
From now on, autosize columns by content.
It is not necessary to track widths separately and reset them as other posters suggest. Setting the minimum width for the column solves the issue until the header text is changed, in which case you set the minimum width to 0, autosize just the modified column, and then set the minimum width to the current width again.
EDIT: My apologies, I forgot that I was not using the standard listview, but instead the 3rd party product BetterListView (a free version is available). The standard listview columns don't appear to support minimum width. I do recommend BetterListView highly as a great alternative (much better feature set and performance).
The incredibly awesome AvalonEdit WPF TextEditor control seems to lack an important feature, or at least i can't figure it out. Given an offset and a length, highlight that portion in the TextDocument with a HighlightColor. Simple, right?
Apprentely not. I've RTFM, and the documentation on "Syntax Highlighting" confused me even more. Someone else asked the same question in the SharpDevelop forums, and i'm afraid i can't make sense of Herr Grunwald's answer.
Here's my attempt, using the DocumentHighlighter class (of course it doesn't work):
textEditor1.Text = "1234567890";
HighlightingColor c = new HighlightingColor() { FontWeight = FontWeights.ExtraBold };
DocumentHighlighter dh = new DocumentHighlighter(textEditor1.Document, new HighlightingRuleSet());
HighlightedLine hl = dh.HighlightLine(1);
hl.Sections.Add(new HighlightedSection() { Color = c, Offset = 1, Length = 3 });
Thank you for helping!
Did you see this in this article - it seems to be exactly what are you asking for:
public class ColorizeAvalonEdit : DocumentColorizingTransformer
{
protected override void ColorizeLine(DocumentLine line)
{
int lineStartOffset = line.Offset;
string text = CurrentContext.Document.GetText(line);
int start = 0;
int index;
while ((index = text.IndexOf("AvalonEdit", start)) >= 0) {
base.ChangeLinePart(
lineStartOffset + index, // startOffset
lineStartOffset + index + 10, // endOffset
(VisualLineElement element) => {
// This lambda gets called once for every VisualLineElement
// between the specified offsets.
Typeface tf = element.TextRunProperties.Typeface;
// Replace the typeface with a modified version of
// the same typeface
element.TextRunProperties.SetTypeface(new Typeface(
tf.FontFamily,
FontStyles.Italic,
FontWeights.Bold,
tf.Stretch
));
});
start = index + 1; // search for next occurrence
} } }
It highlights word AvalonEdit with bold.
Some background info:
AvalonEdit is a code editor, not a rich text editor. There is no such thing as "highlight a portion of the document" - the document only stores plain text.
Highlighting is computed on-demand, only for the lines currently in view. If you want custom highlighting, you need to add a step to the highlighting computation - this is what the ColorizeAvalonEdit class in the example posted by mzabsky is doing.
You need to create a custom ColorizingTransformer to do that. The above example is actually highlighting a specific word. Still, you can change it a little bit to to colorize or highlight a portion.
I used Avalon TextEditor for my Console+ project (which is in a very primitive stage at the moment)
public class OffsetColorizer : DocumentColorizingTransformer
{
public int StartOffset { get; set; }
public int EndOffset { get; set; }
protected override void ColorizeLine(DocumentLine line)
{
if (line.Length == 0)
return;
if (line.Offset < StartOffset || line.Offset > EndOffset)
return;
int start = line.Offset > StartOffset ? line.Offset : StartOffset;
int end = EndOffset > line.EndOffset ? line.EndOffset : EndOffset;
ChangeLinePart(start, end, element => element.TextRunProperties.SetForegroundBrush(Brushes.Red));
}
}
And you can add the colorizer to the editor by adding it to LineTransformers collection.
tbxConsole.TextArea.TextView.LineTransformers.Add(_offsetColorizer);
I know this is a pretty old question, but I thought I would share my solution. I am not sure if this solution has been implemented into AvalonEdit, since this question was originally answered, but I find the OffsetColorizer class doesn't actually select the line: it just changes the line's background colour.
My solution is as follows:
textEditor.SelectionStart = offset;
textEditor.SelectionLength = length;
However, this can be extended further like so:
public void SelectText(int offset, int length)
{
//Get the line number based off the offset.
var line = textEditor.Document.GetLineByOffset(offset);
var lineNumber = line.LineNumber;
//Select the text.
textEditor.SelectionStart = offset;
textEditor.SelectionLength = length;
//Scroll the textEditor to the selected line.
var visualTop = textEditor.TextArea.TextView.GetVisualTopByDocumentLine(lineNumber);
textEditor.ScrollToVerticalOffset(visualTop);
}
I find that this solution works better is that rather than just colouring the line, it actually selects it: meaning it can be copied using Ctrl+C.
I Hope this helps people in the future.