Ah.. I'm a beginner. I cant come up with a method that would generate an array of random numbers on button click. Another click should make a new array an so on.
like..
first click
TheNumbers = new int [3] {1, 2, 3};
second click
TheNumbers2 = new int [3] {4, 5, 7};
etc..
This code should work for you. I assume you're working with WinForms
Read Random Constructors
Form1.cs
using System;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
//https://learn.microsoft.com/en-us/dotnet/api/system.random.-ctor?view=netframework-4.8
// The default seed value is derived from the system clock, which has finite resolution.
// As a result, on the .NET Framework only, different Random objects that are created in
// close succession by a call to the parameterless constructor will have identical default
// seed values and, therefore, will produce identical sets of random numbers. This problem
// can be avoided by using a single Random object to generate all random numbers.
private readonly Random objRandom = new Random();
//Everytime the button is clicked, this array is loaded with 3 random numbers
private int[] theNumbers;
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
theNumbers = GenerateThreeRandomsEachLessThanTen();
//just to demo the creation of the numbers
textBox1.Text = String.Join(Environment.NewLine, theNumbers);
}
private int[] GenerateThreeRandomsEachLessThanTen()
{
return new int[] { objRandom.Next(10), objRandom.Next(10), objRandom.Next(10) };
}
}
}
Form1.Designer.cs
namespace WindowsFormsApp1
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(86, 24);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Go";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.Button1_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(19, 63);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(203, 91);
this.textBox1.TabIndex = 1;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(234, 179);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Name = "Form1";
this.Text = "Randoms";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBox1;
}
}
Output from clicking on "Go" button 3 times
Related
I know how to scroll vertically/horizontally with buttons but I am not able to figure out how to scroll towards Left/Right.
What I want is that when I click the button LeftScrlBtn I should scroll to left and when I click the RightScrlBtn I should scroll to right.
My FlowLayoutPanel's AutoScroll property is set to false because I don't want the scroll bar, only the buttons.
Edit
To make this post more understandable, here is the code:
using System;
using [...];
//rest of the code
private void LeftScrlBtn_Click(object sender, EventArgs e) {
//Code to scroll to Left
}
private void RightScrlBtn_Click(object sender, EventArgs e) {
//Code to scroll to Right
}
//I want to know the code to scroll left and the code to scroll right
Note
I wanted to tell that this question didn't help me.
You can try the following code to scroll the FlowLayoutPanel by using the button.
public Form1()
{
InitializeComponent();
// need to disable AutoScroll, otherwise disabling the horizontal scrollbar doesn't work
flowLayoutPanel.AutoScroll = false;
// disable horizontal scrollbar
flowLayoutPanel.HorizontalScroll.Enabled = false;
}
public int scrollValue = 0;
public int ScrollValue
{
get
{
return scrollValue;
}
set
{
scrollValue = value;
if (scrollValue < flowLayoutPanel1.HorizontalScroll.Minimum)
{
scrollValue = flowLayoutPanel1.HorizontalScroll.Minimum;
}
if (scrollValue > flowLayoutPanel1.HorizontalScroll.Maximum)
{
scrollValue = flowLayoutPanel1.HorizontalScroll.Maximum;
}
flowLayoutPanel1.HorizontalScroll.Value = scrollValue;
flowLayoutPanel1.PerformLayout();
}
}
private void btnleft_Click(object sender, EventArgs e)
{
ScrollValue -= flowLayoutPanel1.HorizontalScroll.LargeChange;
}
private void btnright_Click(object sender, EventArgs e)
{
ScrollValue += flowLayoutPanel1.HorizontalScroll.LargeChange;
}
private void button1_Click(object sender, EventArgs e)
{
flowLayoutPanel1.Controls.Add(new Button() { Width = 67, Height = flowLayoutPanel1.Height});
}
Result:
You could place all your controls in a panel that is transparent and is overflowing over the form's bounds (eg. if form is 500px in width and 600px in height you can make the panel be wider than the form and place controls in there). Leave some space under the panel and add your buttons there.
To the LeftScrlBtn_Click block of code add the following: this.panel1.Left--;
Add this to the RightScrlBtn_Click: this.panel1.Left++;
Of course, you can change the incremention value of the panels so it would scroll faster. Just replace ++ with +=5 or -- with -=5 to scroll 5 pixels on click, per example.
Here is a code sample I did (goes into Form1.cs) :
using System.Collections.Generic;
using System.Windows.Forms;
namespace StackOfAnswer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Scrolling left
this.panel1.Left--;
}
private void button2_Click(object sender, EventArgs e)
{
//Scrolling right
this.panel1.Left++;
}
}
}
Here is the code that goes into Form1.Designer.cs :
namespace StackOfAnswer
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.panel1 = new System.Windows.Forms.Panel();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.Black;
this.panel1.Controls.Add(this.label1);
this.panel1.Location = new System.Drawing.Point(-3, -1);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(904, 422);
this.panel1.TabIndex = 0;
//
// button1
//
this.button1.Location = new System.Drawing.Point(24, 427);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 1;
this.button1.Text = "scroll left";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(713, 427);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 1;
this.button2.Text = "scroll right";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.ForeColor = System.Drawing.Color.White;
this.label1.Location = new System.Drawing.Point(24, 136);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(1561, 13);
this.label1.TabIndex = 0;
this.label1.Text = " example example example example example example example example example example example example example example example example example example example example example example example ";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.panel1);
this.Name = "Form1";
this.Text = "Form1";
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
}
}
This should do it.
I'm trying to create a pop up to notify users of a successful action. It is supposed to be visible for a couple seconds and fade away on its own. To do this, I've created a form that inherits from Form and sets the ShowWithoutActivation property to true, as well as a static class to control its construction and manipulate its opacity.
The problem is that when the new form is created, it has the correct size and initial opacity, but is completely blank. The only child control, a docked (Fill) label does not show. The Background/Foreground Color properties I set in the designer seem to be ignored in favor of default values as well. The Form fades and closes as intended.
The form itself:
public partial class TempForm : Form
{
protected override bool ShowWithoutActivation
{
get { return true; }
}
public TempForm(string message)
{
InitializeComponent();
messageLabel.Text = message;
}
private TempForm() { }
}
The static class that creates it:
public static class FadeAwayNotifier
{
public static void DisplayFadeNotification(Point parentLocation, string message)
{
Task t = Task.Factory.StartNew(() =>
{
int fadeDelay = 2000;
int animationLength = 1000;
int threadRestLength = 20;
Form popUp = buildForm(parentLocation, message);
popUp.Show();
int opacityIncrements = (animationLength / threadRestLength);
double opacityDecrementAmount = popUp.Opacity / opacityIncrements;
Thread.Sleep(fadeDelay);
for (int i = 0; i < opacityIncrements; i++)
{
Thread.Sleep(threadRestLength);
popUp.Opacity -= opacityDecrementAmount;
}
popUp.Close();
});
}
private static Form buildForm(Point startLocation, string text)
{
TempForm returnForm = new TempForm(text);
returnForm.Location = startLocation;
returnForm.messageLabel.Text = text;
returnForm.BackColor = Color.Black;
returnForm.ForeColor = Color.White;
return returnForm;
}
}
And, if it's helpful, here is the designer code for TempForm:
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.messageLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// messageLabel
//
this.messageLabel.BackColor = System.Drawing.Color.Black;
this.messageLabel.Dock = System.Windows.Forms.DockStyle.Fill;
this.messageLabel.Font = new System.Drawing.Font("Cambria", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.messageLabel.ForeColor = System.Drawing.Color.White;
this.messageLabel.Location = new System.Drawing.Point(0, 0);
this.messageLabel.Name = "messageLabel";
this.messageLabel.Size = new System.Drawing.Size(254, 81);
this.messageLabel.TabIndex = 0;
this.messageLabel.Text = "Message";
this.messageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// TempForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 19F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(254, 81);
this.Controls.Add(this.messageLabel);
this.Font = new System.Drawing.Font("Cambria", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.ForeColor = System.Drawing.Color.White;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.Name = "TempForm";
this.Opacity = 0.8D;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "tempForm";
this.TopMost = true;
this.ResumeLayout(false);
}
#endregion
public System.Windows.Forms.Label messageLabel;
For those asking how the method is being called:
private void btnUpdate_Click(object sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
/* Input validation here */
if (cmbBox.SelectedValue != null)
{
updateMethod(a, b....out errorMessage);
if (String.IsNullOrEmpty(errorMessage))
FadeAwayNotifier.DisplayFadeNotification(this.Location, "Rule successfully updated");
}
else
MessageBox.Show("A selection must be made in order to update");
Cursor.Current = Cursors.Default;
}
I've searched around but haven't seen anything that seemed to relate to the situation. I'm happy to be corrected if I missed something, though.
Why is the form that's created completely blank?
Your form is blank because you are trying to show it inside Task.Factory.StartNew().
Task.Factory.StartNew() runs code inside it asynchronous which is for some reason problem for form.Show() method.
Solution for this is to instead of Task t = Task.Factory.StartNew(... use Task t = new Tast(.... and then after you created task you run it with t.RunSynchronously(). This way it will work.
How i am displaying temp forms is:
Create temporary form create new blank winform (through vs solution explorer)
Add code like this:
public partial class TempForm : Form
{
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
double seconds = 3;
public TempForm(int secs, string text)
{
InitializeComponent();
//Custom property to dock it to down right to the screen
Rectangle workingArea = Screen.GetWorkingArea(this);
this.Location = new Point(workingArea.Right - Size.Width, workingArea.Bottom - Size.Height);
t = new System.Windows.Forms.Timer();
this.seconds = (secs != 0) ? secs : this.seconds;
richTextBox1.Text = text;
}
private void TempForm_Load(object sender, EventArgs e)
{
t.Interval = (int)(seconds * 1000);
t.Tick += new EventHandler(CloseForm);
t.Start();
}
private void CloseForm(object sender, EventArgs e)
{
this.Close();
this.Dispose();
}
public static void Show(int seconds, string text)
{
TempForm tf = new TempForm(seconds, text);
tf.Show();
}
}
To call it just use TempForm.Show(10, "SomeText");
Also make it look better (not like standard form) so it looks like this:
a few days back i started reading Head first C#, i use visual c# 2015 for building code and learning C# but however the book is based on visual studio 2010, i never ran into any problem so far while learning until i ran into this exercise when i have to build a typing game, i followed all the procedure as mentioned by the book and built it with no errors. but in the end when i run the code a key press from the keyboard should initialize the game but nothing seems t o start the game not even a mouse click or even from virtual keyboard.
Here is the code
namespace WindowsFormsApplication15{
public partial class Form1 : Form
{
Random random = new Random();
Stats stats = new Stats();
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
listBox1.Items.Add((Keys)random.Next(65, 70));
if (listBox1.Items.Count > 7)
{
listBox1.Items.Clear();
listBox1.Items.Add("Game over");
timer1.Stop();
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (listBox1.Items.Contains(e.KeyCode))
{
listBox1.Items.Remove(e.KeyCode);
listBox1.Refresh();
if (timer1.Interval > 400)
timer1.Interval -= 10;
if (timer1.Interval > 250)
timer1.Interval -= 7;
if (timer1.Interval > 100)
timer1.Interval -= 2;
difficultyProgressBar.Value = 800 - timer1.Interval;
stats.Update(true);
}
else
{
stats.Update(false);
}
correctLabel.Text = "Correct:" + stats.Correct;
missedLabel.Text = "Missed:" + stats.Missed;
totalLabel.Text = "Total:" + stats.Total;
accuracyLabel.Text = "Accuracy:" + stats.Accuracy + "%";
}
}
}
class for the code
namespace WindowsFormsApplication15{
class Stats
{
public int Total = 0;
public int Missed = 0;
public int Correct = 0;
public int Accuracy = 0;
public void Update(bool correctKey)
{
Total++;
if (!correctKey)
{
Missed++;
}
else
{
Correct++;
}
Accuracy = 100 * Correct / (Missed + Correct);
}
}
}
Form designer code
namespace WindowsFormsApplication15{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.listBox1 = new System.Windows.Forms.ListBox();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.correctLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.missedLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.totalLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.accuracyLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
this.difficultyProgressBar = new System.Windows.Forms.ToolStripProgressBar();
this.statusStrip1.SuspendLayout();
this.SuspendLayout();
//
// listBox1
//
this.listBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.listBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 80.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.listBox1.FormattingEnabled = true;
this.listBox1.ItemHeight = 120;
this.listBox1.Location = new System.Drawing.Point(0, 0);
this.listBox1.MultiColumn = true;
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(887, 261);
this.listBox1.TabIndex = 0;
//
// timer1
//
this.timer1.Interval = 800;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.correctLabel,
this.missedLabel,
this.totalLabel,
this.accuracyLabel,
this.toolStripStatusLabel1,
this.difficultyProgressBar});
this.statusStrip1.Location = new System.Drawing.Point(0, 239);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(887, 22);
this.statusStrip1.SizingGrip = false;
this.statusStrip1.TabIndex = 1;
this.statusStrip1.Text = "statusStrip1";
//
// correctLabel
//
this.correctLabel.Name = "correctLabel";
this.correctLabel.Size = new System.Drawing.Size(58, 17);
this.correctLabel.Text = "Correct: 0";
//
// missedLabel
//
this.missedLabel.Name = "missedLabel";
this.missedLabel.Size = new System.Drawing.Size(56, 17);
this.missedLabel.Text = "Missed: 0";
//
// totalLabel
//
this.totalLabel.Name = "totalLabel";
this.totalLabel.Size = new System.Drawing.Size(45, 17);
this.totalLabel.Text = "Total: 0";
//
// accuracyLabel
//
this.accuracyLabel.Name = "accuracyLabel";
this.accuracyLabel.Size = new System.Drawing.Size(78, 17);
this.accuracyLabel.Text = "Accuracy: 0%";
//
// toolStripStatusLabel1
//
this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
this.toolStripStatusLabel1.Size = new System.Drawing.Size(533, 17);
this.toolStripStatusLabel1.Spring = true;
this.toolStripStatusLabel1.Text = "Difficulty";
this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// difficultyProgressBar
//
this.difficultyProgressBar.Name = "difficultyProgressBar";
this.difficultyProgressBar.Size = new System.Drawing.Size(100, 16);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(887, 261);
this.Controls.Add(this.statusStrip1);
this.Controls.Add(this.listBox1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.Text = "Form1";
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.Timer timer1;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripStatusLabel correctLabel;
private System.Windows.Forms.ToolStripStatusLabel missedLabel;
private System.Windows.Forms.ToolStripStatusLabel totalLabel;
private System.Windows.Forms.ToolStripStatusLabel accuracyLabel;
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
private System.Windows.Forms.ToolStripProgressBar difficultyProgressBar;
}
}
I just started learning C# and working with visual studio this month, i don't know much about programming
My guess is the problem lies some where with the KeyDown event
In all of that code I cannot see where timer1 is started - try adding
timer1.Start();
after InitializeComponent();
The problem is simple - your input focus is on the listbox. The guy who wrote the sample probably didn't test it all that much, or you didn't follow the procedure precisely enough :)
To make sure the form receives key press on a child control, you need to set the form's KeyPreview property to true.
Also, as PaulF noted, you never start the timer. The simplest solution is to set Enabled to true.
I'm late to this, but here's what I've got. I'm working through the same book and ran into the same problem, which is that the instructions tell you to set the listbox font at 72pt size. This makes the letters too large to display properly in the listbox on the form, and the Dock Fill property (or some other property, I'm new at C#) causes the ListBox (and its contents) to not display on the form during runtime.
The fix was to reduce ListBox1's font size down to the next size down, at 48pt.
I had the same problem and I had to set the timer to start or enabled and also set the font size to 48pt.
Add one of these lines in Form1.cs underneath InitializeComponent().
this.timer1.Enabled = true;
this.timer1.Start();
In Windows Forms (C#) is there a way to set the tooltip's height and width dynamically (meaning in code). I am working with a DataViewGrid control, so I am having to use the method Show. However, I have noticed (when left to it's own devices) that the tooltip control does not always adjust to the content provided....
An example:
Having a ToolTip control added to a form (called ttText) and then having it first show the text:
ttText.Show("I'm hungry\nand waiting!");
will truncate the next call:
ttText.Show("Well, too bad -- so much for your stamina, you should not be here!\nSo the little bear responds!");
Any thoughts on this?
Keep in mind that a DataGridView requires a mechanism to display ToolTip help hence the use of the Show methods and I've seen this behavior elsewhere in non-DataViewGrids...
Here is an Example of code:
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace TestForm
{
class Form1 : Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.ttText = new System.Windows.Forms.ToolTip(this.components);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
this.dataGridView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Location = new System.Drawing.Point(13, 19);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.Size = new System.Drawing.Size(453, 321);
this.dataGridView1.TabIndex = 0;
this.dataGridView1.CellMouseEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_MouseCellEnter);
//
// ttText
//
this.ttText.AutomaticDelay = 60;
this.ttText.AutoPopDelay = 600000;
this.ttText.InitialDelay = 60;
this.ttText.IsBalloon = true;
this.ttText.ReshowDelay = 60;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(478, 352);
this.Controls.Add(this.dataGridView1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
}
private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.ToolTip ttText;
public Form1()
{
InitializeComponent();
var ds = Sayings().ToList();
dataGridView1.DataSource = ds;
}
public List<dynamic> Sayings()
{
return new List<dynamic>
{
new
{
Human = "I'm hungry\nand waiting!",
BabyBear = "Well, too bad -- so much for your stamina, you should not be here!\nSo the little bear responds!"
}
};
}
private void dataGridView1_MouseCellEnter(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex != -1 && e.RowIndex != -1)
{
var rect = dataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, true);
var left = rect.Left + (int)(rect.Width * .5f);
var top = rect.Top;
Point displayPoint = new Point(left + this.ClientRectangle.Left, top + this.ClientRectangle.Top + 40);
ttText.Show(dataGridView1[e.ColumnIndex, e.RowIndex].Value.ToString(), this, displayPoint);
}
}
}
}
If you hover over the 1st column, then the second, the the tool tip text gets truncated.
OK, it has been several months now since I posted this question. I haven’t really given this problem any thought since then – just accepted the behavior... until tonight.
Since no-one else thought of an answer (or cared to provide an alternative Window Forms idea), it occurred to me to re-look at the general problem. The balloon tool tip seems to be a free-form kind of thing... It takes the previous shape it encounters. It's probably Microsoft's laziness at work. Or better – it's Microsoft's way of pointing developers in a different direction. After all, the only new direction provided was towards wpf...
However, as I stated in the original question, I needed a solution that was ONLY windows forms, not mixing WPF or Silverlight or other technologies into the pot. After all, if you are a WPF programmer, you may want to add Windows Forms controls in to the mix, but for the purest, this won't do.
So here is a bit more to the solution to the puzzle – how to make a balloon resize to the dimensions desired...
I re-looked at the problem and noticed that the balloon would resize each time the mouse pointer entered into the cell, so to that end, the following was derived:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace TestForm
{
class Form1 : Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.ttText = new System.Windows.Forms.ToolTip(this.components);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
this.dataGridView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Location = new System.Drawing.Point(17, 23);
this.dataGridView1.Margin = new System.Windows.Forms.Padding(4);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.Size = new System.Drawing.Size(604, 395);
this.dataGridView1.TabIndex = 0;
this.dataGridView1.CellMouseEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_MouseCellEnter);
this.dataGridView1.MouseLeave += new System.EventHandler(this.dataGridView1_MouseLeave);
this.dataGridView1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.event_MouseMove);
//
// ttText
//
this.ttText.AutomaticDelay = 0;
this.ttText.AutoPopDelay = 0;
this.ttText.InitialDelay = 10;
this.ttText.IsBalloon = true;
this.ttText.OwnerDraw = true;
this.ttText.ReshowDelay = 0;
this.ttText.ShowAlways = true;
this.ttText.UseAnimation = false;
this.ttText.UseFading = false;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(637, 433);
this.Controls.Add(this.dataGridView1);
this.Margin = new System.Windows.Forms.Padding(4);
this.Name = "Form1";
this.Text = "Form1";
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.event_MouseMove);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
}
private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.ToolTip ttText;
public Form1()
{
InitializeComponent();
dataGridView1.ShowCellToolTips = false;
var ds = Sayings().ToList();
dataGridView1.DataSource = ds;
}
public List<dynamic> Sayings()
{
return new List<dynamic>
{
new
{
Human = "I'm hungry\nand waiting!",
BabyBear = "Well, too bad -- so much for your stamina, you should not be here!\nSo the little bear responds!"
},
new
{
Human = "What a selfish bear!\n\n\nAt least you could do is wait for\nothers to join you!",
BabyBear = "Boo Hoo!"
},
new
{
Human = "Oh, I'm sorry!",
BabyBear = "Now, I'm going to eat you!"
},
new
{
Human = "\n\n\n!!!\n\nWhat?????\n\n\n\nI don't think so!\n\n(Human pulls out Honey Jar)",
BabyBear = "Yum!"
},
};
}
private void dataGridView1_MouseCellEnter(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex != -1 && e.RowIndex != -1)
{
this.SuspendLayout();
var rectC = dataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, true);
var left = rectC.Left + (int)(rectC.Width * .5f);
var rectR = dataGridView1.GetRowDisplayRectangle(e.RowIndex, true);
var top = (rectR.Top + (int)(rectR.Height * .5f));
Point displayPoint = new Point(left + this.ClientRectangle.Left, top + this.ClientRectangle.Top + 40);
var column = e.ColumnIndex;
var row = e.RowIndex;
for (int i = 0; i < 5; ++i)
{
ttText.Show(dataGridView1[column, row].Value.ToString(), this, displayPoint);
ttText.Hide(this);
}
ttText.Show(dataGridView1[column, row].Value.ToString(), this, displayPoint);
this.ResumeLayout();
}
}
private void dataGridView1_MouseLeave(object sender, EventArgs e)
{
Rectangle mouseRect = new Rectangle(MousePosition, new Size(1, 1));
var rectC = dataGridView1.GetColumnDisplayRectangle(dataGridView1.Columns.Count - 1, true);
var right = rectC.Right;
var rectR = dataGridView1.GetRowDisplayRectangle(dataGridView1.Rows.Count - 1, true);
var bottom = rectR.Bottom;
var rect = new Rectangle(
dataGridView1.PointToScreen(dataGridView1.Location),
new Size(right, bottom));
if (!rect.IntersectsWith(mouseRect))
ttText.Hide(this);
}
void event_MouseMove(object sender, MouseEventArgs e)
{
dataGridView1_MouseLeave(sender, EventArgs.Empty);
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
I have expanded the narrative in the grid to help demonstrate the general problem.
I know that this is not a completely elegant solution – but that's what encapsulation is all about.
The new problem... Is it possible to have the point of the balloon tool tip be displayed at the mouse point – or am I just living a pipe dream?
Now, as far as a possible solution... I have read a bit about inheriting the Tool Tip object to perform drawing with a custom class. Is it not feasible to use that to determine the size of the text, and then determine which direction the balloon would display and the offset of the text?
On MSDN it mentions using the RenderSize property for this sort of thing but with some caveats.
What worked for me to avoid truncating the tool tip is to set the ToolTip text explicitly. What I think is subtle is that the default ToolTip text uses the same cell content, only the default handler does truncate it as noted in the original question. By overriding the event and setting the ToolTip text (even though it's exactly the same cell text!) now the default length restriction seems to go away.
protected override void OnCellToolTipTextNeeded(DataGridViewCellToolTipTextNeededEventArgs e)
{
if((e.RowIndex >= 0) && (e.ColumnIndex >= 0))
{
// By setting this explicitly we can make the ToolTip show the
// entire length even though the content itself has not changed.
e.ToolTipText = this[e.ColumnIndex, e.RowIndex].Value.ToString();
}
base.OnCellToolTipTextNeeded(e);
}
I have a Winforms ComboBox that contains instances of a custom class. When the items are first added to the Items collection of the ComboBox, the ToString method is call on each of them.
However when the user changes the language the application is running in, the result of the ToString method changes.
Therefore how can I get the ComboBox to call the ToString method on all items again without having to remove all items from the ComboBox and adding them back in?
Thanks svick, RefreshItems() work, however as it is protected (so can only be called by a subclass) I had to do
public class RefreshingComboBox : ComboBox
{
public new void RefreshItem(int index)
{
base.RefreshItem(index);
}
public new void RefreshItems()
{
base.RefreshItems();
}
}
I have just had to do the same for a ToolStripComboBox, however it was a bit harder as you can not subclass the Combro box it contains, I did
public class RefreshingToolStripComboBox : ToolStripComboBox
{
// We do not want "fake" selectedIndex change events etc, subclass that overide the OnIndexChanged etc
// will have to check InOnCultureChanged them selfs
private bool inRefresh = false;
public bool InRefresh { get { return inRefresh; } }
public void Refresh()
{
try
{
inRefresh = true;
// This is harder then it shold be, as I can't get to the Refesh method that
// is on the embebed combro box.
//
// I am trying to get ToString recalled on all the items
int selectedIndex = SelectedIndex;
object[] items = new object[Items.Count];
Items.CopyTo(items, 0);
Items.Clear();
Items.AddRange(items);
SelectedIndex = selectedIndex;
}
finally
{
inRefresh = false;
}
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
if (!inRefresh)
{
base.OnSelectedIndexChanged(e);
}
}
}
I had to do the same trip to stop unwanted events for the normal CombroBox, by overriding OnSelectedValueChanged, OnSelectedItemChanged and OnSelectedIndexChanged, as the code is the same as for the ToolStripComboBox I have not included it here.
You should be able to do this by calling the RefreshItems() method.
I use this extension:
/// <summary>
/// Recreates the items
/// </summary>
public static void RefreshItems(this ComboBox cb)
{
var selectedIndex = cb.SelectedIndex;
cb.SelectedIndex = -1;
MethodInfo dynMethod = cb.GetType().GetMethod("RefreshItems", BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(cb, null);
cb.SelectedIndex = selectedIndex;
}
svick is right. However, as Ian Ringrose mentions, a subclass is necessary.
RefreshItems is a protected method for System.Windows.Forms.ComboBox.
A Forms application below provides an example of the behavior, and the RefreshItems method updating the ComboBox:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public class Form1 : Form
{
private List<HelloWorld> helloWorlds;
#region Form1.Designer.cs
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose( bool disposing )
{
if ( disposing && (components != null) )
{
components.Dispose();
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.comboBox1 = new RefreshingComboBox();
this.comboBox2 = new RefreshingComboBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// comboBox1
//
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point( 76, 12 );
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size( 115, 21 );
this.comboBox1.TabIndex = 0;
//
// comboBox2
//
this.comboBox2.FormattingEnabled = true;
this.comboBox2.Location = new System.Drawing.Point( 250, 12 );
this.comboBox2.Name = "comboBox2";
this.comboBox2.Size = new System.Drawing.Size( 218, 21 );
this.comboBox2.TabIndex = 1;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point( 12, 15 );
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size( 58, 13 );
this.label1.TabIndex = 2;
this.label1.Text = "Language:";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point( 213, 15 );
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size( 31, 13 );
this.label2.TabIndex = 3;
this.label2.Text = "Text:";
//
// button1
//
this.button1.Location = new System.Drawing.Point( 34, 42 );
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size( 75, 23 );
this.button1.TabIndex = 4;
this.button1.Text = "Set All";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler( this.button1_Click );
//
// button2
//
this.button2.Location = new System.Drawing.Point( 116, 42 );
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size( 75, 23 );
this.button2.TabIndex = 5;
this.button2.Text = "Set Random";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler( this.button2_Click );
//
// button3
//
this.button3.Location = new System.Drawing.Point( 393, 42 );
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size( 75, 23 );
this.button3.TabIndex = 6;
this.button3.Text = "Refresh!";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler( this.button3_Click );
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F );
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size( 556, 77 );
this.Controls.Add( this.button3 );
this.Controls.Add( this.button2 );
this.Controls.Add( this.button1 );
this.Controls.Add( this.label2 );
this.Controls.Add( this.label1 );
this.Controls.Add( this.comboBox2 );
this.Controls.Add( this.comboBox1 );
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout( false );
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.ComboBox comboBox2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
#endregion
public Form1()
{
InitializeComponent();
comboBox1.DataSource = new HelloWorld().GetLanguages();
helloWorlds = new List<HelloWorld>();
while ( helloWorlds.Count < 10 )
{
helloWorlds.Add( new HelloWorld() );
}
comboBox2.DataSource = helloWorlds;
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
Application.Run( new Form1() );
}
private void changeAllLanguages()
{
HelloWorld.LanguageValue newLang = (HelloWorld.LanguageValue) comboBox1.SelectedValue;
helloWorlds.ForEach(
delegate( HelloWorld hw )
{
hw.Language = newLang;
} );
}
private void changeRandomLanguage()
{
int index = new Random().Next( helloWorlds.Count );
HelloWorld.LanguageValue newLang = (HelloWorld.LanguageValue) comboBox1.SelectedValue;
helloWorlds[index].Language = newLang;
}
private void button1_Click( object sender, EventArgs e )
{
changeAllLanguages();
}
private void button2_Click( object sender, EventArgs e )
{
changeRandomLanguage();
}
private void button3_Click( object sender, EventArgs e )
{
(comboBox2 as RefreshingComboBox).RefreshItems();
}
}
public class RefreshingComboBox : System.Windows.Forms.ComboBox
{
public new void RefreshItem(int index)
{
base.RefreshItem(index);
}
public new void RefreshItems()
{
base.RefreshItems();
}
}
public class HelloWorld
{
public enum LanguageValue
{
English,
日本語,
Deutsch,
Français,
Český
}
private LanguageValue language;
public LanguageValue Language
{
get
{
return language;
}
set
{
language = value;
}
}
public Array GetLanguages()
{
return Enum.GetValues( typeof( LanguageValue ) );
}
Dictionary<LanguageValue, string> helloWorlds;
public HelloWorld()
{
helloWorlds = new Dictionary<LanguageValue, string>();
helloWorlds[LanguageValue.English] = "Hello, world!";
helloWorlds[LanguageValue.日本語] = "こんにちは、世界!";
helloWorlds[LanguageValue.Deutsch] = "Hallo, Welt!";
helloWorlds[LanguageValue.Français] = "Sallut, monde!";
helloWorlds[LanguageValue.Český] = "Ahoj svět!";
}
public override string ToString()
{
return helloWorlds[language];
}
}
}