I need to write something to autoscroll a text in a single line TextBox continuously. Do I need to scroll to caret then set it to first char and start over?
So i found a marquee control and modify it a little and used it instead of textbox
public class Marquee : System.Windows.Forms.UserControl
{
private System.ComponentModel.IContainer components;
private System.Windows.Forms.Timer timer1;
private int currentPos = 0;
private bool mBorder;
private string mText;
public string MarqueeText
{
get { return mText; }
set { mText = value; }
}
public bool Border
{
get { return mBorder; }
set { mBorder = value; }
}
public int Interval
{
get { return timer1.Interval * 10; }
set { timer1.Interval = value / 10; }
}
public Marquee()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
// TODO: Add any initialization after the InitForm call
this.Size = new Size(this.Width, this.Font.Height);
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
components.Dispose();
}
base.Dispose(disposing);
}
#region Component 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.timer1 = new System.Windows.Forms.Timer(this.components);
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// Marquee
//
this.Name = "Marquee";
this.Size = new System.Drawing.Size(150, 136);
this.Resize += new System.EventHandler(this.Marquee_Resize);
}
#endregion
private void Marquee_Resize(object sender, System.EventArgs e)
{
this.Height = this.Font.Height;
}
private void timer1_Tick(object sender, System.EventArgs e)
{
this.Invalidate();
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (mBorder)
{
e.Graphics.DrawRectangle(new Pen(this.ForeColor), 0, 0, this.Width - 1, this.Height - 1);
}
float dif = e.Graphics.MeasureString(mText, this.Font).Width- this.Width;
if (this.Width < e.Graphics.MeasureString(mText, this.Font).Width)
{
e.Graphics.DrawString(mText, this.Font, new SolidBrush(this.ForeColor),
currentPos, 0);
e.Graphics.DrawString(mText, this.Font, new SolidBrush(this.ForeColor),
this.Width + currentPos + dif, 0);
currentPos--;
if ((currentPos < 0) && (Math.Abs(currentPos) >= e.Graphics.MeasureString(mText, this.Font).Width))
currentPos = this.Width + currentPos;
}
else
{
e.Graphics.DrawString(mText, this.Font, new SolidBrush(this.ForeColor),-dif/2, 0);
}
}
}
So if the text width is longer than the width of the control the text will be static else the text will auto-scroll
Related
The array in the parent form is updated every 100 milliseconds.
Once the child form is opened with menustrip in parent form, the data is passed to child form
Issue:
Till now, I have had success in passing the array data, but I need to update it periodically in the child form also, and I have some difficulties with setting the timer in child form.
Form1: or Parent Form
string[] ArrayPack1Cells = new string[28];
//All the values are first stored in 2D array `volt_info_array[packidindex, voltage_index]`
//and after scaling it, elements store in 1D array depending on the `packidindex` value
Voltages = ((volt_info_array[packidindex, voltage_index] / 1000));
switch(PackIndexes)
{
case 1:
// if size is 28, then convert to array to be passed to child form.
if(ListPack1Cells.Count == 28)
{
ArrayPack1Cells = ListPack1Cells.ToArray();
}
break;
case 2:
.....
}
private void viewToolStripMenuItem_Click(object sender, EventArgs e)
{
ToolStripMenuItem menu = sender as ToolStripMenuItem;
switch (menu.Name)
{
case "pack1ToolStripMenuItem":
if (Application.OpenForms["Pack1"] is Pack1 pack1)
{
pack1.Focus();
return;
}
pack1 = new Pack1();
pack1.TakeThis(ArrayPack1Cells);
pack1.MdiParent = this;
pack1.Show();
Array.Clear(ArrayPack1Cells, 0, ArrayPack1Cells.Length);// Clear it once send to form2
break;
}
Form2: or Child/Pack1 Form
public void TakeThis(string[] ArrayPack1Cells), method copies all the 28 arrays in the texboxes but only once.
public List<Control> Cell_Volt1 = new List<Control>();
public string[] f_temp = new string[28];
public Pack1()
{
InitializeComponent();
Cell_tbxArray();
if (P1_timer.Enabled == false)
{
P1_timer.Enabled = true;
P1_timer.Tick += new System.EventHandler(this.P1_timer_Tick);
P1_timer.Start();
}
else if (P1_timer.Enabled)
{
1_timer.Stop();
P1_timer.Enabled = true;
P1_timer.Start();
}
}
private void Cell_tbxArray()
{
for (int i = 0; i < tableLayoutPanel1.Controls.Count; i++)
{
if (tableLayoutPanel1.Controls[i].GetType() == typeof(TextBox))
{
Cell_Volt1.Add(tableLayoutPanel1.Controls[i]);
}
}
}
public void TakeThis(string[] ArrayPack1Cells)
{
f_temp = ArrayPack1Cells;
int index = 0;
foreach (string item in f_temp)
{
Cell_Volt1[index].Text += item;
index++;
}
}
private void P1_timer_Tick(object sender, EventArgs e)
{
for (int i = 0; i < Cell_Volt1.Count; i++)
{
Cell_Volt1[i].Text += f_temp[i];
}
}
The private void P1_timer_Tick(object sender, EventArgs e) isnt working at all.
Here is my take.
Parent:
public static class Consts
{
public const int NPACKS = 10, NVOLTS = 28;
}
public partial class ParentForm : Form
{
double[,] data = new double[Consts.NPACKS, Consts.NVOLTS];
double[][] uidata = new double[Consts.NPACKS][];
Dictionary<int, PackForm> forms = new Dictionary<int, PackForm>();
public ParentForm()
{
InitializeComponent();
for (int i = 0; i < Consts.NPACKS; i++)
{
uidata[i] = new double[Consts.NVOLTS];
}
}
// wild guess - not clear how do you update it - all of them or slices
void DataContinuousUpdate(double value, int npack, int nvolt)
{
data[npack, nvolt] = value;
var slice = uidata[npack];
// in case a form is trying to refresh UI
lock (slice)
slice[nvolt] = value;
}
void OpenPack(int npack)
{
// assuming access to this method is serial
if (forms.ContainsKey(npack))
return;
var slice = uidata[npack];
lock (slice)
{
var form = new PackForm(npack, slice);
forms.Add(npack, form);
}
}
}
Pack:
public partial class PackForm : Form
{
public int ID { get; private set; }
public double[] Data { get; private set; }
public double ValueScale { get; set; }
TextBox[] VoltTextBox = new TextBox[Consts.NVOLTS];
Timer timer;
private PackForm()
{
InitializeComponent();
CreateTextBoxes();
ValueScale = 1000.0;
this.FormClosing += PackForm_FormClosing;
}
public PackForm(int iD, double[] data) : this()
{
InitializeComponent();
ID = iD;
Data = data;
StartTimer();
}
private void PackForm_FormClosing(object? sender, FormClosingEventArgs e)
{
StopTimer();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void StartTimer()
{
StopTimer();
timer = new Timer();
timer.Enabled = true;
timer.Interval = 1000;
timer.Tick += Timer_Tick;
}
private void StopTimer()
{
if (timer == null) return;
timer.Enabled = false;
timer.Tick -= Timer_Tick;
}
private void Timer_Tick(object? sender, EventArgs e)
{
if (Data == null) return;
lock(Data)
{
for (int i = 0; i < Data.Length; i++)
{
VoltTextBox[i].Text += Data[i];
}
}
}
}
I have a custom UI element that inherits from System.Windows.Controls.Primitives.ToggleButton. I'm also routing my mouse events through a custom TouchDevice that raises touch events instead.
For some reason, the ManipulationCompleted event never fires. First, the custom TouchDevice can be found here: http://blakenui.codeplex.com/SourceControl/changeset/view/67526#Blake.NUI.WPF/Touch/MouseTouchDevice.cs
Here are the relevant parts of my class:
public class ToggleSwitch: ToggleButton {
private Grid _root;
private readonly IList<int> _activeTouchDevices;
private const double UNCHECKED_TRANSLATION = 0;
private TranslateTransform _backgroundTranslation;
private TranslateTransform _thumbTranslation;
private Grid _root;
private Grid _track;
private FrameworkElement _thumb;
private double _checkedTranslation;
private double _dragTranslation;
private bool _wasDragged;
private bool _isDragging;
public override void OnApplyTemplate()
{
...
MouseTouchDevice.RegisterEvents(_root);
_root.IsManipulationEnabled = true;
_root.TouchDown += OnTouchDown;
_root.TouchUp += OnTouchUp;
_root.GotTouchCapture += OnGotTouchCapture;
_root.LostTouchCapture += OnLostTouchCapture;
_root.ManipulationStarted += OnManipulationStarted;
_root.ManipulationDelta += OnManipulationDelta;
_root.ManipulationCompleted += OnManipulationCompleted;
}
private void OnTouchDown(object sender, TouchEventArgs e)
{
e.TouchDevice.Capture(_root);
}
private void OnGotTouchCapture(object sender, TouchEventArgs e)
{
if (e.TouchDevice.Captured == _root)
{
Manipulation.AddManipulator(_root,e.TouchDevice);
_activeTouchDevices.Add(e.TouchDevice.Id);
}
}
private void OnManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
e.Handled = true;
_isDragging = true;
_dragTranslation = Translation;
ChangeVisualState(true);
Translation = _dragTranslation;
}
private void OnManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
e.Handled = true;
var horizontalChange = e.DeltaManipulation.Translation.X;
var direction = Math.Abs(horizontalChange) >= Math.Abs(e.DeltaManipulation.Translation.Y) ? Orientation.Horizontal : Orientation.Vertical;
if (direction == Orientation.Horizontal && horizontalChange != 0.0)
{
_wasDragged = true;
_dragTranslation += horizontalChange;
Translation = Math.Max(UNCHECKED_TRANSLATION, Math.Min(_checkedTranslation, _dragTranslation));
}
}
private void OnManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
e.Handled = true;
_isDragging = false;
var click = false;
if (_wasDragged)
{
var edge = (IsChecked ?? false) ? _checkedTranslation : UNCHECKED_TRANSLATION;
if (Translation != edge)
{
click = true;
}
}
else
{
click = true;
}
if (click)
{
OnClick();
}
_wasDragged = false;
}
}
The OnManipulationCompleted method is never entered.
I've created GradientButton which changes angle of gradient when mouse cursor is in its' bounds. Unfortunately the graphics is corrupted as there are random flashes during rendering.
To achieve gradient rotation I start a thread upon MouseEnter and stop it at MouseLeave. Doublebuffered set to true, helped a lot but did not solve this fully.
public partial class GradientButton : UserControl {
public Color Color1 { get; set; }
public Color Color2 { get; set; }
public bool Down { get; set; }
public bool MouseOnButton { get; set; }
[Browsable(true)]
public string TextToDraw { get; set; }
public int Angle { get; set; }
public GradientButton() {
InitializeComponent();
Color1 = Color.YellowGreen;
Color2 = Color.LightGreen;
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
var color1 = Color1;
var color2 = Color2;
if (Down) {
var temp = color1;
color1 = color2;
color2 = temp;
}
if (MouseOnButton) {
color1 = ControlPaint.Dark(Color2);
}
using (LinearGradientBrush brush = new LinearGradientBrush(this.ClientRectangle, color1, color2, Angle)) {
e.Graphics.FillRectangle(brush, this.ClientRectangle);
}
Rectangle rect1 = ClientRectangle;
// Create a StringFormat object with the each line of text, and the block
// of text centered on the page.
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
// Draw the text and the surrounding rectangle.
e.Graphics.DrawString(TextToDraw, Font, new SolidBrush(ForeColor), rect1, stringFormat);
}
protected override void OnClick(EventArgs e) {
base.OnClick(e);
}
protected override void OnResize(EventArgs e) {
base.OnResize(e);
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e) {
base.OnMouseDown(e);
Down = true;
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e) {
base.OnMouseUp(e);
Down = false;
Invalidate();
}
protected override void OnMouseEnter(EventArgs e) {
base.OnMouseEnter(e);
MouseOnButton = true;
Thread t = new Thread(Animate);
t.Start();
}
public void Animate() {
while (MouseOnButton) {
Angle += 5;
Thread.Sleep(25);
Invalidate();
}
}
protected override void OnMouseLeave(EventArgs e) {
base.OnMouseLeave(e);
Angle = 0;
MouseOnButton = false;
Invalidate();
}
}
GradientButton.Designer.cs
partial class GradientButton {
/// <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 Component 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.SuspendLayout();
//
// GradientButton
//
this.Name = "GradientButton";
this.Size = new System.Drawing.Size(78, 28);
this.ResumeLayout(false);
}
#endregion
}
Use
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlsStyles.Opaque, true);
to prevent the background from being painted prior to OnPaint processing. This should prevent the flicker inbetween the background erase and the painting.
Update: I am pretty sure i found out the reason why, i will update this question with my findings as soon as i got it for sure. It is related to having 2 usercontrol's placed above each other and i draw on the one behind thats why i don't see the changes! I had to check the hashcode of the timer to figure out that 2 timers are involved.
I am developing a winforms application and i have applied the MVP-pattern to separate the responsibilities and stuff... (applied the passive-view approach, and also fire events to require the corresponding presenter to perform an action).
I have also checked other questions here and many other relevant topics, but nothing helped...
Problem description: I added a UserControl (SubView) into a SplitContainer's panel which is placed inside a Form (MainView). This SubView has its own presenter (SubPresenter) that requires it to switch its background (SwitchBackground(), picturebox) whenever that is triggered by the user from the MainView.
Problem: The SwitchBackground() method gets executed (i debugged that) when that is triggered from the MainView (actually from the MainPresenter), but the changes are not displayed on the SubView. I have also examined (or at least tried to do that correctly :) ) if the method requires switching the context into the GUI thread or something by checking the InvokeRequired.
I would be glad to have any recommendations regarding this issue, because i am stuck there and can't go further with programming...
Here is an example application i wrote to illustrate the problem (for the complete example project, i uploaded it on github: link):
SubView:
public interface ISubView
{
void StartSwitchingBackground();
void StopSwitchingBackground();
}
public partial class SubView : UserControl, ISubView
{
private Bitmap plot;
private Brush brush1;
private Brush brush2;
private int drawCount;
private Timer timer;
public SubView()
{
InitializeComponent();
brush1 = new SolidBrush(Color.Yellow);
brush2 = new SolidBrush(Color.Blue);
timer = new Timer();
timer.Tick += OnTick;
}
private void OnTick(object sender, EventArgs e)
{
SwitchBackground();
}
private void SwitchBackground()
{
if (InvokeRequired)
Console.WriteLine("InvokeRequired"); // never happens, so i assume it is not considered a call from another thread...
if (plot == null || plot.Size != pictureBox.Size)
plot = new Bitmap((int)(pictureBox.Width*0.8), (int)(pictureBox.Height*0.8));
using (Graphics g = Graphics.FromImage(plot))
{
int x = plot.Width / 2;
int y = plot.Height / 2;
int w = plot.Width / 4;
int h = plot.Height / 4;
if (drawCount % 2 == 0)
{
g.Clear(Color.White);
g.FillRectangle(brush1, (x - w) / 2, (y - h) / 2, w, h);
}
else
{
g.Clear(Color.Black);
g.FillRectangle(brush2, (x - w) / 2, (y - h) / 2, w, h);
}
drawCount++;
}
pictureBox.Image = plot;
}
public void StartSwitchingBackground()
{
if (!timer.Enabled)
timer.Start();
Console.WriteLine("started");
}
public void StopSwitchingBackground()
{
if (timer.Enabled) timer.Stop();
Console.WriteLine("stopped");
}
private void btnStartSwitching_Click(object sender, EventArgs e)
{
StartSwitchingBackground();
}
private void btnStopSwitching_Click(object sender, EventArgs e)
{
StopSwitchingBackground();
}
}
SubPresenter:
public class SubPresenter
{
private ISubView view;
public SubPresenter(ISubView view)
{
this.view = view;
}
public void SwitchBackground()
{
view.StartSwitchingBackground();
}
public void StopSwitching()
{
view.StopSwitchingBackground();
}
}
MainView:
public interface IMainView
{
ISubView SubView { get; }
event EventHandler SwitchEventTriggered;
event EventHandler StopSwitchEventTriggered;
}
public partial class MainView : Form, IMainView
{
private SubView subView;
public MainView()
{
InitializeComponent();
subView = new SubView();
splitContainer1.Panel2.Controls.Add(subView);
subView.Dock = DockStyle.Fill;
subView.Anchor = AnchorStyles.Top & AnchorStyles.Left;
splitContainer1.Resize += splitContainer1_Resize;
}
void splitContainer1_Resize(object sender, EventArgs e)
{
subView.Size = splitContainer1.Panel2.Size;
}
private void btnStart_Click(object sender, EventArgs e)
{
StartSwitching();
}
private void StartSwitching()
{
OnStartSwitchingTriggered();
}
private void OnStartSwitchingTriggered()
{
var handler = SwitchEventTriggered;
if (handler == null) return;
handler(this, EventArgs.Empty);
}
private void btnStop_Click(object sender, EventArgs e)
{
StopSwitching();
}
private void StopSwitching()
{
OnStopSwitching();
}
private void OnStopSwitching()
{
var handler = StopSwitchEventTriggered;
if (handler == null) return;
handler(this, EventArgs.Empty);
}
public ISubView SubView { get { return this.subView; } }
public event EventHandler SwitchEventTriggered;
public event EventHandler StopSwitchEventTriggered;
}
MainPresenter:
public class MainPresenter
{
private readonly IMainView mainView;
private readonly SubPresenter subPresenter;
public MainPresenter(IMainView view)
{
this.mainView = view;
this.subPresenter = new SubPresenter(mainView.SubView);
mainView.SwitchEventTriggered += OnSwitchEventTriggerd;
mainView.StopSwitchEventTriggered += OnStopSwitchEventTriggered;
}
private void OnStopSwitchEventTriggered(object sender, EventArgs e)
{
subPresenter.StopSwitching();
}
private void OnSwitchEventTriggerd(object sender, EventArgs e)
{
subPresenter.SwitchBackground();
}
}
Entry Point:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainView mainView = new MainView();
MainPresenter mainPresenter = new MainPresenter(mainView);
Application.Run(mainView);
}
}
You have two instances of SubView in MainView.
Use only subView1, you can delete all occurrences of subView;
The minimum fix is to replace:
public ISubView SubView { get { return this.subView; } }
with:
public ISubView SubView { get { return this.subView1; } }
How to get event for ComboBox inside of Gridview using C# Windows Application... Anyone Tell me the solution of this problem.....
Thanks in Advance...
check this http://www.eggheadcafe.com/community/aspnet/2/10098379/gridview.aspx
I think you are looking at the wrong place. For value change event, you should use your class's property changed event that is bound to that specific column in the GridView. Because, when you change value in the ComboBoxColumn, it will in turn update the value in the object that is bound to that row.
Example:
Designer generated code
`partial class Form1
{
///
/// Required designer variable.
///
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.dataGridView1 = new System.Windows.Forms.DataGridView();
this.Column1 = new System.Windows.Forms.DataGridViewComboBoxColumn();
this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.Column1,
this.Column2});
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dataGridView1.Location = new System.Drawing.Point(0, 0);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.RowTemplate.Height = 24;
this.dataGridView1.Size = new System.Drawing.Size(282, 255);
this.dataGridView1.TabIndex = 0;
//
// Column1
//
this.Column1.DataPropertyName = "Value1";
this.Column1.HeaderText = "Column1";
this.Column1.Name = "Column1";
//
// Column2
//
this.Column2.DataPropertyName = "Value2";
this.Column2.HeaderText = "Column2";
this.Column2.Name = "Column2";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(282, 255);
this.Controls.Add(this.dataGridView1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.DataGridViewComboBoxColumn Column1;
private System.Windows.Forms.DataGridViewTextBoxColumn Column2;
}`
Code Behind
`public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Column1 is
Column1.DataPropertyName = "Value1";
Column1.Items.AddRange(Enumerable.Range(1, 10).Select(i => i.ToString()).ToArray());
Column2.DataPropertyName = "Value2";
dataGridView1.DataError += new DataGridViewDataErrorEventHandler(dataGridView1_DataError);
dataGridView1.DataSource = (from obj in Enumerable.Range(1, 20)
select new Model() { Value1 = obj, Value2 = ("Value2 #" + obj.ToString()) }).ToList();
}
void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.Exception.ToString());
}
}
class Model
{
protected Int32 _value1;
public Int32 Value1
{
get
{
return _value1;
}
set
{
// Here is your property change event
MessageBox.Show(value.ToString());
_value1 = value;
}
}
public String Value2 { get; set; }
}`