Autoexpand textbox while typing - c#

I am needing an autoexpanding textbox like facebook has for it's status updates. I have code for it but for some reason it's not fully working correctly. It's updating the textbox and expanding it, but it is doing it way too soon. i am wanting it to expand when it gets to the end of the line. But it is doing it after 20 characters are entered! I have two different methods i have tried, they both do the same thing. Any suggestions on changing my code?
function sz(t) {
var therows = 0
var thetext = document.getElementById(t.id).value;
var newtext = thetext.split("\n");
therows += newtext.length
document.getElementById(t.id).rows = therows;
return false;
}
function sz(t)
{
a = t.value.split('\n');
b = 1;
for (x = 0; x < a.length; x++)
{
if (a[x].length >= t.cols)
{
b += Math.floor(a[x].length / t.cols);
}
}
b += a.length;
if (b > t.rows)
{
t.rows = b;
}
}

Check out this fiddle.
I think your problem was using txtbox.id rather than just passing the id.

Related

DGV doesn't update value

I Inerted a DGV called MarksDGV1 into my application while each cell inside of it has a default value of "0". So, after the user changes the value of some of them, when I try to reach the value for the last edited cell it gives me 0 instead of what the user typed even though it's shown correctly
(Please note: the unselected cells -which doesn't appear in Blue color- show value correctly)
How could I fix that?
Here is my code:
MarksDGV1.Refresh();
MessageBox.Show(MarksDGV1.Rows[0].Cells[1].Value.ToString());
And this is How I built the DGV:
using (DataGridViewTextBoxColumn tmp = new DataGridViewTextBoxColumn())
{
tmp.Width = 90;
tmp.ReadOnly = true;
tmp.HeaderText = "פרק מס.";
MarksDGV1.Columns.Add(tmp);
}
for (int i = 1; i <= 30; i++)
{
using (DataGridViewTextBoxColumn tmp = new DataGridViewTextBoxColumn())
{
tmp.Width = 50;
tmp.HeaderText = "שאלה מס." + i;
MarksDGV1.Columns.Add(tmp);
}
}
for (int i = 0; i < 8; i++)
{
using (DataGridViewRow tmp = (DataGridViewRow)MarksDGV1.Rows[i].Clone())
{
tmp.Cells[0].Value = i + 1;
for (int j = 1; j <= 30; j++)
{
tmp.Cells[j].Value = 0;
//tmp.Cells[j].Value = CurrentExam.Psy[i].Answers[j - 1];
}
MarksDGV1.Rows.Add(tmp);
}
}
Update: I tried typing DataGridView.Refresh(); but didn't work!
Update2: I was able to fix this by selecting another cell -different from the one that I'm concerned in- before I get the values. But that's not a solution for me
From the comments, you are using a button that doesn't take the focus away from the grid, so it remains in edit mode. Try it like this:
MarksDGV1.EndEdit();
MessageBox.Show(MarksDGV1.Rows[0].Cells[1].Value.ToString());

Call method with new parameter values for each loop in C#

[HttpPost]
public ActionResult ShowDetailRate(FormCollection form)
{
List<Calculation> finalList = new List<Calculation>();
Calculation calc3 = new Calculation();
double InterestRate = 0;
double guess = 0.01;
double guess2 = 0.03;
for (int i = 0; i < 50; i++)
{
InterestRate = secantInterestRate(guess, guess2, form);
if (radio == "inArrears")
{
radioCalc = 0;
}
else
{
radioCalc = InvoiceAmount;
}
calc3.PeriodStartDate = PeriodStartDate;
calc3.PeriodEndDate = PeriodEndDate;
if (DTC == "365/365")
{
calc3.NumberOfDays = Convert.ToInt32((calc3.PeriodEndDate - calc3.PeriodStartDate).Days) + 1;
}
else if (DTC == "360/360")
{
calc3.NumberOfDays = 30;
}
calc3.InvoiceAmount = InvoiceAmount;
calc3.InterestRate = InterestRate;
calc3.InterestAmount = (PV - radioCalc) * InterestRate / DTCyear * calc3.NumberOfDays;
calc3.Amortization = (calc3.InvoiceAmount - calc3.InterestAmount);
calc3.PresentValue = PV - calc3.Amortization;
calc3.StartValue = PV;
finalList.Add(calc3);
var count = finalList.Count();
if (finalList[count].PresentValue != FV)
{
guess = guess2;
guess2 = calc3.InterestRate;
continue;
}
else
break;
}
return PartialView("ShowDetail", finalList);
}
In my method above I'm using my variable InterestRate to call a method called secantInterestRate with 3 parameters (double, double, FormCollection). The first round for the loop I want the first 2 parameters to be set as they are (0.01, 0.03), but in the second loop-round I want guess = guess 2, and guess2 = calc3.InterestRate. And still be calling the method secantInterestRate in the beginning of the loop but with the new values. I have tried with a small if in the end:
var count = finalList.Count() - 3;
if (finalList[count].PresentValue != FV)
{
guess = guess2;
guess2 = calc3.InterestRate;
continue;
}
else
break;
But this don't work because when the loop starts over guess will be 0.01 and guess2 will be 0.03 again, and not like I want it.
Is it possible to make guess = guess2 and guess2 = calc3.InterestRate for every new round in the loop?
something like this?
if (i==0) {
guess = guess2;
guess2 = calc3.InterestRate;
} else {
// you don't want to change the values after the first time through; do nothing
}
PS: I suggest you factor out the calculation code from the form-processing code, or in some other way make the method more readable. Currently it's really hard to see the logic as there's so many lines of code, and that's probably the main reason it's hard to solve any small problems like this one.
Change your code according to the following:
....
for (int i = 0; i < 50; i++)
{
if (i > 0)
{
guess = guess2;
guess2 = calc3.InterestRate;
}
InterestRate = secantInterestRate(guess, guess2, form);
...

How do I find and use a programatically-created control?

I've created a number of buttons on a form based on database entries, and they work just fine. Here's the code for creating them. As you can see I've given them a tag:
for (int i = 0; i <= count && i < 3; i++)
{
btnAdd.Text = dataTable.Rows[i]["deviceDescription"].ToString();
btnAdd.Location = new Point(x, y);
btnAdd.Tag = i;
this.Controls.Add(btnAdd);
}
I use these buttons for visualising a polling system. For example, I want the button to be green when everything is fine, and red when something is wrong.
So the problem I'm running into is referencing the buttons later so that I can change their properties. I've tried stuff like the following:
this.Invoke((MethodInvoker)delegate
{
// txtOutput1.Text = (result[4] == 0x00 ? "HIGH" : "LOW"); // runs on UI thread
Button foundButton = (Button)Controls.Find(buttonNumber.ToString(), true)[0];
if (result[4] == 0x00)
{
foundButton.BackColor = Color.Green;
}
else
{
foundButton.BackColor = Color.Red;
}
});
But to no avail... I've tried changing around the syntax of Controls.Find() but still have had no luck. Has anyone encountered this problem before or know what to do?
If you name your buttons when you create them then you can find them from the this.controls(...
like this
for (int i = 0; i <= count && i < 3; i++)
{
Button btnAdd = new Button();
btnAdd.Name="btn"+i;
btnAdd.Text = dataTable.Rows[i]["deviceDescription"].ToString();
btnAdd.Location = new Point(x, y);
btnAdd.Tag = i;
this.Controls.Add(btnAdd);
}
then you can find it like this
this.Controls["btn1"].Text="New Text";
or
for (int i = 0; i <= count && i < 3; i++)
{
//**EDIT** I added some exception catching here
if (this.Controls.ContainsKey("btn"+buttonNumber))
MessageBox.Show("btn"+buttonNumber + " Does not exist");
else
this.Controls["btn"+i].Text="I am Button "+i;
}
Put these buttons in a collection and also set the name of the Control rather than using its tag.
var myButtons = new List<Button>();
var btnAdd = new Button();
btnAdd.Text = dataTable.Rows[i]["deviceDescription"].ToString();
btnAdd.Location = new Point(x, y);
btnAdd.Name = i;
myButtons.Add(btnAdd);
To find the button use it.
Button foundButton = myButtons.Where(s => s.Name == buttonNumber.ToString());
Or Simply
Button foundButton = myButtons[buttonNumber];
In your case I would use a simple Dictionary to store and retrieve the buttons.
declaration:
IDictionary<int, Button> kpiButtons = new Dictionary<int, Button>();
usage:
Button btnFound = kpiButtons[i];
#Asif is right, but if you really want to utilize tag you can use next
var button = (from c in Controls.OfType<Button>()
where (c.Tag is int) && (int)c.Tag == buttonNumber
select c).FirstOrDefault();
I'd rather create small helper class with number, button reference and logic and keep collection of it on the form.

WPF TextBox ScrollToLine not updating if visible

I have a Navigation-bar in my program that allows you to navigate the different sections in my TextBox, but the problem I have is that this doesn't work if the Text I am scrolling to is already visible on the screen.
Like in this example, if I try to jump from Section 1 to Section 3, it won't work as it's already visible.
But, in this example if I jump to Section 3, it works fine as it's not already visible.
The scrolling function I use is very simple:
if (nLine > 0 && nLine <= textBox.LineCount)
textBox.ScrollToLine(nLine - 1);
I hope that someone can shed some light on an alternative solution that allows me to scroll even if the text is already visible.
Edit: Added solution.
This is a code snippet from my project.
private static void ScrollToLineCallback(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
var textBox = (TextBox)target;
int newLineValue;
if (Int32.TryParse(e.NewValue.ToString(), out newLineValue))
{
if (newLineValue > 0 && newLineValue <= textBox.LineCount) // Validate
{
textBox.ScrollToLine(newLineValue - 1); // Scroll to Line
// Check and see if we are at the line we want.
if (textBox.GetFirstVisibleLineIndex() <= newLineValue && textBox.GetLastVisibleLineIndex() >= newLineValue)
{
// If not lets move to the desired location
int newLineCorrectionValue = newLineValue - textBox.GetFirstVisibleLineIndex() - 2; // How much further do we need to scroll down?
for (int i = 0; i < newLineCorrectionValue; i++)
{
textBox.LineDown(); // Scroll down
}
}
}
}
}
You could use GetCharacterIndexFromLineIndex to get the index of the beginning of the desired line and then set the CaretIndex to that value.
Because I don't really know, what you are trying to achieve, another possibility is to use LineUp and LineDown in conjunction with GetFirstVisibleLineIndex and GetLastVisibleLineIndex.
private void TextBoxGotoLine(
TextBox textbox1,
int linenum)
{
var target_cpos = textbox1.GetCharacterIndexFromLineIndex(linenum);
var target_char_rect = textbox1.GetRectFromCharacterIndex(target_cpos);
var first_char_rect = textbox1.GetRectFromCharacterIndex(0);
textbox1.ScrollToVerticalOffset(
target_char_rect.Top -
first_char_rect.Top
);
}
I found out if Wrapping is enabled its more complications:
private void TextBoxGotoLine(TextBox textbox1, int linenum)
{
// int Linenum is the Absolute Line, not including
// effect of Textbox Wrapping.
if (textbox1.TextWrapping == TextWrapping.Wrap)
{
// If textbox Wrapping is on, we need to
// Correct the Linenum for Wrapping which adds extra lines
int cidx = 0;
bool found = false;
int ln = 0;
char[] tmp = textbox1.Text.ToCharArray();
for (cidx = 0; cidx < tmp.Length; cidx++)
{
if (tmp[cidx] == '\n')
{
ln++;
}
if (ln == linenum)
{
found = true;
break;
}
}
if (!found)
return;
linenum = textbox1.GetLineIndexFromCharacterIndex(cidx+1);
}
// Non-Wrapping TextBox
var target_cpos = textbox1.GetCharacterIndexFromLineIndex(linenum);
var target_char_rect = textbox1.GetRectFromCharacterIndex(target_cpos);
var first_char_rect = textbox1.GetRectFromCharacterIndex(0);
textbox1.ScrollToVerticalOffset(target_char_rect.Top - first_char_rect.Top);
}

Refactor that code ... Controls.Find method

OK, I have a code (see below):
void M1()
{
for (int i = 1; i < 10; i++)
{
Control[] carr = this.Controls.Find("Number" +
(i - 1).ToString() +
"CheckBox", true);
if ((carr != null) && (carr.Length > 0))
{
CheckBox enableCB = carr[0] as CheckBox;
enableCB.Checked = i % 2 == 0 ? true : false; // or any other value
}
}
}
I don't like iteration with using Controls.Find method. Can I replace it with something easier ?
PS: all the NumberXCheckBox (X>=0 and X<=8) presented on the form.
LINQ enabled, .net 3.5, Visual studio 2008.
Instead of searching by name, can you wrap your CheckBox controls in a container that means you can just iterate through the controls in the container?
I would encourage you to introduce a field in your type to keep references to your checkboxes (an array, a list, a dictionary -- you choose.) This way you'll no longer need to use this non-typed and somewhat ugly find-control-by-key-method.
Anyway, if you're still in .NET 2.0 and prefer to use the Find method, you could simplify a little bit your loop:
for (var i = 0; i <= 8; i++)
{
var controls = Controls.Find("Number" + i + "CheckBox", true);
if (controls.Length > 0)
{
var checkBox = controls[0] as CheckBox;
if (checkBox != null)
checkBox.Checked = i%2 == 0;
}
}
The latest non-nullity test on checkbox can probably be omitted.
If you are using 3.5 or otherwise have LINQ available you could do the following
for ( int i = 0; i < 9; i++) {
var control = this.Controls
.Find(String.Format("Number{0}Checkbox", i))
.Cast<CheckBox>()
.FirstOrDefault();
if ( control != null ) {
control.Checked = (i % 2) != 0;
}
}
More linq-y
for (int i = 0; i < 10; i++) {
var c = (from CheckBox c in this.Controls.Find(String.Format(CultureInfo.InvariantCulture, "Number{0}CheckBox", i-1), true)
select c).FirstOrDefault();
if (c != null) {
c.Checked = i % 2 == 0 ? true : false;
}
}
Here's one without linq, but cleaned up the code a little bit.
for (int i = 1; i < 10; i++)
{
Control[] carr = this.Controls.Find("Number" + (i - 1) + "CheckBox", true);
if (carr.Length <= 0) continue;
CheckBox enableCB = carr[0] as CheckBox;
enableCB.Checked = (i % 2) == 0;
}
[Edit: added the Find(..) code to show why you don't have to check for null]
Here's the frameworks internal code for the Find function. I've added a couple of comments in it
public Control[] Find(string key, bool searchAllChildren)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException("key", SR.GetString("FindKeyMayNotBeEmptyOrNull"));
}
// Will always return an ArrayList with zero or more elements
ArrayList list = this.FindInternal(key, searchAllChildren, this, new ArrayList());
// Will always return an Array of zero or more elements
Control[] array = new Control[list.Count];
list.CopyTo(array, 0);
return array;
}

Categories

Resources