c# draw simple workflow diagram and mark current status - c#

I have a C# Winform project and I need to create a very simple linear workflow just to show visually what is the current status of the record.
Here is a sample image of what I want to do:
I will have to be able to draw the border on the item that is the actual status.
Any advice?

If you don't want to have to actually draw on it, you can do as rashfmnb suggested. Here is an example.
The setup:
Form = MainForm
Panel = pnlOuter [Padding = 5]
Panel = pnlInner [Parent = pnlOuter, done by placing it inside the other one; Dock = Fill]
Button = ToggleColor (to trigger the click event handler below)
The code:
public partial class MainForm : Form
{
bool isOn = false;
public MainForm()
{
InitializeComponent();
pnlInner.BackColor = Color.LightGoldenrodYellow;
pnlOuter.BackColor = Color.LightGoldenrodYellow;
}
private void ToggleColor_Click(object sender, EventArgs e)
{
if (isOn)
{
pnlOuter.BackColor = Color.LightGoldenrodYellow;
isOn = false;
}
else
{
pnlOuter.BackColor = Color.Red;
isOn = true;
}
}
}
This simple example just toggles the background of the outer panel. In your case, you would use different values to check what should be set and so forth.

Related

In WPF/C#, how do I access elements of dynamically generated controls or otherwise add click events to them?

I am using a custom control class to build similar-looking controls with different details and OnClick actions. Other than looking pretty, the controls only function is to toggle a yellow button so it looks like a modern togglebutton control (like in Android settings or whatever).
The main output looks like this:
What I'm trying to do is figure out how to bring the "onclick" logic out of the control and into the main file so I can properly respond to it. I originally had it respond to it's own click events on both the rectangle and ellipse like so:
public partial class FixerBox : UserControl
{
Thickness btnDotOn = new Thickness(-60, 0, 0, 0);
Thickness btnDotOff = new Thickness(0, 0, -60, 0);
SolidColorBrush dotOn = new SolidColorBrush(Color.FromRgb(84, 130, 53));
SolidColorBrush dotOff = new SolidColorBrush(Color.FromRgb(207, 178, 76));
SolidColorBrush bkOn = new SolidColorBrush(Color.FromRgb(226, 240, 217));
SolidColorBrush bkOff = new SolidColorBrush(Color.FromRgb(255, 242, 204));
public bool IsOn { get; set; } = false;
public FixerBox(Dictionary<string,string> deets)
{
InitializeComponent();
btnOff();
this.Name = deets["Name"];
this.FixerTitle.Text = deets["Title"];
this.FixerDesc.Text = deets["Description"];
this.FixerTags.Text = deets["Tags"];
this.FixerImg.Source = new BitmapImage(new Uri(deets["Img"], UriKind.Relative));
}
public void btnOn()
{
IsOn = true;
FixBtnBk.Fill = bkOn;
FixBtnBk.Stroke = dotOn;
FixBtnDot.Fill = dotOn;
FixBtnDot.Margin = btnDotOn;
}
public void btnOff()
{
IsOn = false;
FixBtnBk.Fill = bkOff;
FixBtnBk.Stroke = dotOff;
FixBtnDot.Fill = dotOff;
FixBtnDot.Margin = btnDotOff;
}
private void FixBtnBk_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//if (isOn)
//{
// btnOff();
//}
//else
//{
// btnOn();
//}
}
private void FixBtnDot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FixBtnBk_MouseLeftButtonDown(sender, e);
}
}
I've commented out the click events for now so I can try to trigger the same effect from outside:
// The click event I'm trying to build
private void fixClick(object sender, EventArgs e)
{
StatusBox.Text = "CLICK WORKS";
FixerBox whichFix = (FixerBox)sender;
if (whichFix.IsOn)
{
whichFix.btnOff();
}
else
{
whichFix.btnOn();
}
}
// The constructor of my app
public MainWindow()
{
InitializeComponent();
// fixNames is a dictionary containing details of each control
var fixNames = fixers.FixerNames();
foreach (string key in fixNames)
{
var temp = fixers.GetFix(key);
// Be sure to pass this along as well
temp["Name"] = key;
fixerBoxes[key] = new FixerBox(temp);
fixerBoxes[key].FindName("FixBtnBk") = new EventHandler(fixClick);
FixersArea.Children.Add(fixerBoxes[key]);
}
}
Above is my main app constructor where I generate all the controls. The issue is that on the line where I'm setting the event handler, I can't figure out how to actually make it work. FindName should get the specific control, but it doesn't HAVE a click event or mousedown or anything. How can I attach my custom click event to each control?
The reason I'm doing it this way is because along with toggling the button, I want it to actually make system changes and registry updates in response to which control was clicked. I could keep all the responses in a class and include them in the custom control, but that seems sloppy both from a system resources viewpoint and a programming viewpoint.
Instead, if I can figure out how to access the various elements of the dynamic controls and add click events to them (or any equivalent workaround), that seems better.
how do I access elements of dynamically generated controls or otherwise add click events to them. What I'm trying to do is figure out how to bring the "onclick" logic out of the control and into the main file so I can properly respond to it.
As mentioned in my comments above, you could create public events that you could subscribe to and respond to those events as needed.
In your FixerBox class:
Add event: public event RoutedEventHandler MouseLeftBtnDown;
Invoke the event when needed:
private void FixerBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MouseLeftBtnDown?.Invoke(this, new RoutedEventArgs());
}
In your class you want to subscribe to this new event:
foreach (string key in fixNames)
{
var temp = fixers.GetFix(key);
// Be sure to pass this along as well
temp["Name"] = key;
fixerBoxes[key] = new FixerBox(temp);
fixerBoxes[key].MouseLeftBtnDown += fixClick;
FixersArea.Children.Add(fixerBoxes[key]);
}
Your routine signature would need to be changed as well:
private void fixClick(object sender, RoutedEventArgs e)
This should get you started, if you have questions please let me know.

Panel Control and Check panel property is Empty

I want to Check that whether a panel have some form or not.
kindly tell me the best condition.
if panel have some form inside it than bool variable should be true.
the code that i have write is below.Kindly answer this question as soon as possible. thanks.
this is a button click event.
i want to check that when i click on a button its first check these conditions.
1. check if form have existing this form that i want to pass in it than break
it and make bool variable true.
2. if it does't have than clear all form inside the panel and generate click event form inside it.
enter code here
private void btn_dashboard_Click(object sender, EventArgs e)
{
bool isOpen = false;
dash = new Dashboard();
if (panel_window_data.Controls.Equals(dash))
{
isOpen = true;
}
if (isOpen == false)
{
panel_window_data.Controls.Clear();
dash.TopLevel = false;
panel_window_data.Controls.Add(dash);
dash.Height = panel_window_data.Height;
dash.Width = panel_window_data.Width;
dash.Show();
}
}
I'm using this code in every single btn, and actually works.
/*------------------------------------------------------------------*/
// to show other form inside panel in main form
users objuser = new users();
pnlobjform.Controls.Clear();
objuser.TopLevel = false;
pnlobjform.Controls.Add(objuser);
objuser.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
objuser.Dock = DockStyle.Fill;
objuser.Show();
/*---------------------------------------------------------------*/

use a control in a different form C#

i'm working on a project for school and have some logical errors.
I have 2 different forms: frmOrders and frmCustomers. frmOrders is the main form and when i click a button here, frmCustomers will show. There is a datagrid named txtTable in frmCustomers.
Now, what i want to do is when I double click a row, some of the info goes in some textboxes in frmOrders then frmCustomers closes. Also, i want the rest of the controls in frmCustomers to be disabled. (I have set the access modifiers for the controls in frmCustomers as public but it does't seem to work.) How do I do that?
Currently this is my code:
public partial class frmOrders : Office2007Form
{
public frmOrders()
{
InitializeComponent();
}
private void frmOrders_Load(object sender, EventArgs e)
{
}
private void btnCustomer_Click(object sender, EventArgs e)
{
frmCustomers c = new frmCustomers();
c.ShowDialog();
c.txtAddress.Enabled = false;
c.txtBday.Enabled = false;
c.txtContactNo.Enabled = false;
c.txtFname.Enabled = false;
c.txtLname.Enabled = false;
c.txtMI.Enabled = false;
c.txtSearch.Enabled = false;
c.btnDelete.Enabled = false;
c.btnSave.Enabled = false;
c.btnUpdate.Enabled = false;
}
}
I guess your buttons, textfields, etc. are private fields in your frmCustomers form code (frmCustomers.Designer.cs), so they cannot be accessed from another form. Either you make your controls public (which I do not suggest) or you add a public method to your form (frmCustomers) that sets the properties and can be accessed from frmOrders.
For example (in your frmCustomers code):
public void SetControlsEnabled()
{
txtAddress.Enabled = false;
txtBday.Enabled = false;
txtContactNo.Enabled = false;
...
}
But as long as you invoke your form with ShowDialog() the code below does not execute because it waits for the form to close (and it returns a DialogResult).
So do it this way
frmCustomers c = new frmCustomers();
c.SetControlsEnabled();
c.ShowDialog();
Hope this helps!

Winforms Control

I have a button which I use all the time as a little pick button next to a combobox. When I click the button I open a larger full list. This side of things work well and I do not have a problem with this..
My problem lies when someone said to me can you change that ugly icon you picked to my nice icon.
I went crap, I have hundreds of these buttons on many forms. So I thought I will create a custom control called PickButton (which is a standard button and heap of default proeprties set) and drop these on the form everywhere instead. In the code of the PickButton custom control I set some properties and the image to the customers nice icon.
So I drop the PickButton from my toolbox onto the form, so far things are looking pretty good and I am feeling a bit clever. Now I think to myself I will change back to my nice icon not the crappy one the customer picked and change the code in the PickButton custom control. But I cannot get rid of that customers icon, because the code when the PickButton run happens before the code in the designer file which has the customers icon.
So my aim was to have a PickButton control and be able to change the icon and other properties in one place and all the properties would be set when an instance of the control is created and displayed on the form.
Was I not so clever and went about achieving the task the wrong way???
This is my PickButton custom control class
public class PickButton : Button
{
public PickButton()
{
InitialiseButton();
}
internal void InitialiseButton()
{
this.ImageAlign = ContentAlignment.MiddleCenter;
this.Image = WindowsFormsApplication1.Properties.Resources.Cancel.ToBitmap();
this.Size = new Size( 28, 28 );
this.Dock = DockStyle.Fill;
this.Margin = new Padding( 0, 2, 2, 0 );
this.Text = string.Empty;
}
}
Now I drop one onto my form and the code in the designer is as follows
//
// pickButton1
//
this.pickButton1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pickButton1.Image = ((System.Drawing.Image)(resources.GetObject("pickButton1.Image")));
this.pickButton1.Location = new System.Drawing.Point(0, 0);
this.pickButton1.Margin = new System.Windows.Forms.Padding(0, 2, 2, 0);
this.pickButton1.Name = "pickButton1";
this.pickButton1.Size = new System.Drawing.Size(284, 262);
this.pickButton1.TabIndex = 0;
this.pickButton1.Text = "pickButton1";
this.pickButton1.UseVisualStyleBackColor = true;
Now I want to change the image so I change my PickButton code to use a different icon
this.Image = WindowsFormsApplication1.Properties.Resources.Browse.ToBitmap();
Run the application andd the first icon is still the one being displayed because of this line of code in the designer file
this.pickButton1.Image = ((System.Drawing.Image)(resources.GetObject("pickButton1.Image")));
The concept of setting all the properties in one place was a good idea, it just wasn't implemented quite right. I would make this class inherit from UserControl instead of from Button. By making it a UserControl, you can use the designer to set all the properties you want, like the default Image for the button. Set that in the designer, then just drag and drop your UserControl from the toolbox onto your forms. If you are only using your "PickButton" control with comboboxes, I would put the combobox on the UserControl as well. If you ever want to change your button image in the future (or any other property for that matter), you will be able to change it in ctlPickButton and that will propogate the changes to all the instances used throughout your project(s).
ctlPickButton:
public partial class ctlPickButton : UserControl
{
public event EventHandler pickButtonClicked;
public ctlPickButton()
{
InitializeComponent();
}
//Allows buttons image to be set in code if necessary
public Image Image
{
get
{
return button1.Image;
}
set
{
if (Image != null)
{
button1.Image = value;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
if (pickButtonClicked != null)
{
pickButtonClicked(sender, e);
}
}
}
Demo Form:
public Form1()
{
InitializeComponent();
ctlPickButton1.pickButtonClicked += new EventHandler(ctlPickButton1_pickButtonClicked);
ctlPickButton2.pickButtonClicked += new EventHandler(ctlPickButton2_pickButtonClicked);
}
void ctlPickButton2_pickButtonClicked(object sender, EventArgs e)
{
if (comboBox2.SelectedItem != null)
{
MessageBox.Show(comboBox2.SelectedItem.ToString());
}
}
void ctlPickButton1_pickButtonClicked(object sender, EventArgs e)
{
if (comboBox1.SelectedItem != null)
{
MessageBox.Show(comboBox1.SelectedItem.ToString());
}
}
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.Items.Add("French");
comboBox1.Items.Add("Spanish");
comboBox1.Items.Add("English");
comboBox1.Items.Add("German");
comboBox2.Items.Add("Pizza");
comboBox2.Items.Add("Hamburger");
comboBox2.Items.Add("Potato");
comboBox2.Items.Add("Chicken");
//Shows how the default image set in the designer can be overwritten for a
//specific instance using the "Image" property
ctlPickButton2.Image = Testbed.Properties.Resources.searchIcon2;
}
}
Image of ctlPickButton in designer
I think I've found a simple, clean solution:
In the CustomButton class (which inherits from System.Windows.Forms.Button), override the Refresh() method, and set the image of the button to the one you want to see:
public class CustomButton : Button
{
public override void Refresh()
{
Image = MyResources.HappyFace;
}
}
In the form that will hold an instance of your CustomButton, simply call customButton.Refresh() in the constructor, after InitializeComponent():
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
customButton.Refresh();
}
}
I've put a demo application up on Github.

Emulate ShowDialog for Winforms UserControl

I would like to achieve the same effect like in this article but for windows forms, is it even possible without hosting the control on different Form?
EDIT
I'm more interested in implementing the exact behavior of the control in the article, showing the control on the form and blocking the calling function, but without using other form for this purpose.
You can create a UserControl with the two buttons and the label for the message, then set its visibility to false in the constructor:
public MyDialog()
{
InitializeComponent();
Visible = false;
}
Then you add three variables to the control:
Form _parent;
bool _result;
bool _clicked = false;
the parent Form will be the Form your control is contained in and must be set before using the control, since it has to know what has to be disabled.
public void SetParent(Form f)
{
_parent = f;
}
_result will contain the result of the dialog, and _clicked will be used to determine when to close your dialog. What has to be done when you show your dialog is:
set the label
disable the form (but not the dialog)
make the dialog visible
wait for the user to click one of the buttons
hide the dialog
reenable the parent form
return the result
So you could add this method to enable/disable the parent form:
private void ParentEnabled(bool aBool)
{
if (_parent == null)
return;
foreach (Control c in _parent.Controls)
if (c != this)
c.Enabled = aBool;
}
and use it in the ShowDialog method:
public bool ShowDialog(string msg)
{
if (_parent == null)
return false;
// set the label
msgLbl.Text = msg;
// disable the form
ParentEnabled(false);
// make the dialog visible
Visible = true;
// wait for the user to click a button
_clicked = false;
while (!_clicked)
{
Thread.Sleep(20);
Application.DoEvents();
}
// reenable the form
ParentEnabled(true);
// hide the dialog
Visible = false;
// return the result
return _result;
}
Obviously the buttons have the responsibility to set the _result and _clicked variables:
private void okBtn_Click(object sender, EventArgs e)
{
_result = true;
_clicked = true;
}
private void cancelBtn_Click(object sender, EventArgs e)
{
_result = false;
_clicked = true;
}
How about creating transparent form that in the middle contains text on opaque shape (whatever you like). Then at runtime you would resize this form to have same size as the window over which you want to display it and place it so that it covers it.

Categories

Resources