I want to display message that button is unclickable (I have used Enabled option, button1.Enabled = false/true; ). Does anyone know how to detect if button is clicked, when it is unclickable in order to display error message "Button is unclickable...".
Windows forms, C#
Whenever a standard control doesn't behave in exactly the way that need it to, all we usually have to do is make our own version that inherits the standard control so that we can make it do whatever we want. Your question offers a great reason for doing that because a normally a disabled Button is not going to fire a Click or a MouseDown event.
Here is a guideline example for a custom Button that:
Intercepts the Enabled property by declaring it new.
Leaves the base class button always responsive because it's always enabled.
Paints the control as dimmed if disabled.
Suppresses the firing of the Click event if disabled, and fires DisabledClick instead.
Look in the Title Bar to see when the button is clicked.
ButtonWithDisabledOption class
class ButtonWithDisableOption : Button
{
bool _enabled = true;
public new bool Enabled
{
get => _enabled;
set
{
if (!Equals(_enabled, value))
{
_enabled = value;
OnEnabledChanged(EventArgs.Empty);
}
}
}
protected override void OnEnabledChanged(EventArgs e)
{
base.OnEnabledChanged(e);
if(Enabled)
{
ForeColor = SystemColors.ControlText;
BackColor = SystemColors.Control;
FlatStyle = FlatStyle.Standard;
}
else
{
ForeColor = Color.FromArgb(191, 191, 191);
BackColor = Color.FromArgb(204, 204, 204);
FlatStyle = FlatStyle.Flat;
}
}
protected override void OnClick(EventArgs e)
{
if (Enabled)
{
base.OnClick(e);
}
else
{
DisabledClick?.Invoke(this, EventArgs.Empty);
}
}
public event EventHandler DisabledClick;
}
MainForm.Designer.cs
Be sure to replace Button references with ButtonWithDisabledOption.
private void InitializeComponent()
{
// this.buttonWithDisableOption = new System.Windows.Forms.Button();
this.buttonWithDisableOption = new button_with_disabled_option.ButtonWithDisableOption();
...
}
// private System.Windows.Forms.Button button1;
private button_with_disabled_option.ButtonWithDisableOption buttonWithDisableOption;
TEST
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
buttonWithDisableOption.Enabled = checkBoxButtonEnabled.Checked = true;
// Button events
buttonWithDisableOption.Click += buttonWithDisableOption_Click;
buttonWithDisableOption.DisabledClick += buttonWithDisableOption_DisabledClick;
// CheckBox events
checkBoxButtonEnabled.CheckedChanged += checkBoxButtonEnabled_CheckedChanged;
}
private void checkBoxButtonEnabled_CheckedChanged(object sender, EventArgs e)
{
buttonWithDisableOption.Enabled = checkBoxButtonEnabled.Checked;
}
private void buttonWithDisableOption_Click(object sender, EventArgs e)
{
// Title bar
Text = $"Button Click {_tstcount++} (Enabled)";
}
private void buttonWithDisableOption_DisabledClick(object sender, EventArgs e)
{
// Title bar
Text = $"Button Click {_tstcount++} (Disabled)";
MessageBox.Show("Button is unclickable");
}
int _tstcount = 1;
}
Related
I'm trying to make the mouse cursor disappear after a certain time when the mouse isn't moving. There's already a question on this but the WebBrowser Control form doesn't have Mouse events. I have this code that was mentioned on the question linked above:
public partial class Form1 : Form
{
public TimeSpan TimeoutToHide { get; private set; }
public DateTime LastMouseMove { get; private set; }
public bool IsHidden { get; private set; }
public Form1()
{
InitializeComponent();
TimeoutToHide = TimeSpan.FromSeconds(5);
this.MouseMove += new MouseEventHandler(Form1_MouseMove);
}
void Form1_MouseMove(object sender, MouseEventArgs e)
{
LastMouseMove = DateTime.Now;
if (IsHidden)
{
Cursor.Show();
IsHidden = false;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
TimeSpan elaped = DateTime.Now - LastMouseMove;
if (elaped >= TimeoutToHide && !IsHidden)
{
Cursor.Hide();
IsHidden = true;
}
}
}
The WebBrowserControl doesn't support MouseMove event. Instead you can use MouseMove event of WebBrowser.Document.Body.
Then apply the logic which you are using for showing and hiding cursor. In a timer Tick event check if the last movement was before a specific time, hide the cursor using Cursor.Hide. Also in MouseMove show the cursor using Cursor.Show method.
DateTime? lastMovement;
bool hidden = false;
void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate("http://www.google.com");
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
webBrowser1.Document.MouseMove += Document_MouseMove;
}
void Document_MouseMove(object sender, HtmlElementEventArgs e)
{
lastMovement = DateTime.Now;
if (hidden)
{
Cursor.Show();
hidden = false;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if (!lastMovement.HasValue)
return;
TimeSpan elaped = DateTime.Now - lastMovement.Value;
if (elaped >= TimeSpan.FromSeconds(2) && !hidden)
{
Cursor.Hide();
hidden = true;
}
}
Note
The job of bool hidden is to keep balance between Show and Hide, because as mentioned in documentations:
The Show and Hide method calls must be balanced. For every call to the
Hide method there must be a corresponding call to the Show method.
Subscribe for MouseMove when the document completed, because Document would be null before completing DocumentCompleted event raise.
I checked if lastMovement doesn't have value then didn't hide the cursor, to prevent hiding the cursor at startup before the user moves mouse over the control.
I am new to C#. I am using windows forms.
As shown in screenshot, I have form1 with 4 buttons and 4 user controls.
click show UserControl1 and UserControl1 shows up.
click show UserControl2 and UserControl2 shows up.
click show UserControl3 and UserControl3 shows up.
click show UserControl4 and UserControl4 shows up.
what I want to do is: when I click Show Previous UC (on User Control4) , the previous User Control shows up.
for example:
click show UserControl2 and UserControl2 shows up.
click show UserControl4 and UserControl4 shows up.
and now I want when I click Show Previous UC, UserControl2 shows up (the previous user control).
How Can I show the previous User Control ( the last one which was shown before the current one)?
Please help me, Thank you.
public partial class Form1 : Form
{
UserControl1 UC1 = new UserControl1();
UserControl2 UC2 = new UserControl2();
UserControl3 UC3 = new UserControl3();
UserControl4 UC4 = new UserControl4();
public Form1()
{
InitializeComponent();
Controls.Add(UC1);
Controls.Add(UC2);
Controls.Add(UC3);
Controls.Add(UC4);
}
private void ShowUserControl1_Click(object sender, EventArgs e)
{
UC1.Visible = true;
UC2.Visible = false;
UC3.Visible = false;
UC4.Visible = false;
}
private void ShowUserControl2_Click(object sender, EventArgs e)
{
UC2.Visible = true;
UC1.Visible = false;
UC3.Visible = false;
UC4.Visible = false;
}
private void ShowUserControl3_Click(object sender, EventArgs e)
{
UC3.Visible = true;
UC1.Visible = false;
UC2.Visible = false;
UC4.Visible = false;
}
private void ShowUserControl4_Click(object sender, EventArgs e)
{
UC4.Visible = true;
UC3.Visible = false;
UC2.Visible = false;
UC1.Visible = false;
}
}
You need to keep track of which user control was the previous in the page (and possible also the current, unless you want to iterate the UCs to find out). Use fields for this in the page.
public partial class Form1 : Form
{
UserControl[] userControls = new []{
new UserControl1(),
new UserControl2(),
new UserControl3(),
new UserControl4()
};
UserControl previous;
UserControl current;
public Form1()
{
InitializeComponent();
foreach(var uc in UserControls)
{
uc.Click += ShowPrevControl_Click;
Controls.Add(uc);
}
}
In the event (you only need one)
private void ShowUserControl_Click(object sender, EventArgs e)
{
foreach(UserControl uc in UserControls)
{
if(uc.Name == (string)((Control)sender).Tag)
{
previous = current;
uc.Visible = true;
current = uc;
}
else
{
uc.Visible = false;
}
}
}
private void ShowPrevControl_Click(object sender, EventArgs e)
{
if (previous != null)
{
foreach(var uc in UserControls)
{
uc.Visible = false;
}
var temp = current;
previous.Visible = true;
current = previous;
previous = temp;
}
}
Set the Tag property for each button to hold the name of the UserControl it should control (UserControl1, UserControl2, UserControl3 or UserControl4).
Let all the buttons click events be handled by ShowUserControl_Click.
Create a new public event in your user controls (if all should handle clicks), that that page can handle using your ShowPrevControl_Clickmethod:
public UserControlx : UserControl
{
public event EventHandler Click;
public UserControlx()
{
Button.Click += Button_Click;
}
private void Button_Click(object sender, EventArgs e)
{
if(Click != null)
Click(this, EventArgs.Empty);
}
}
An easy solution is to add a member variable to your class.
So your class would look like:
public partial class Form1 : Form
{
UserControl prevControl;
// Etc...
So when you click the button for, say, UC2, you can set prevControl to UC2.
private void ShowUserControl2_Click(object sender, EventArgs e)
{
UC2.Visible = true;
prevControl = UC2;
UC1.Visible = false;
UC3.Visible = false;
UC4.Visible = false;
}
And on an event handler for the "Show previous control" button:
private void ShowPrevControl_Click(object sender, EventArgs e)
{
if (prevControl != null) prevControl.Visible = true;
}
UserControl is a reference in C#, which makes this possible.
I extended the button control to have also LabelName. When I press the button I need to write the name of the button in the label.
My first idea was using events - easy and simple.
The question is: Is there more elegant way to do it? (I've been asked to bind the button and the label)...
I think that the best way to do it would be to use an action listener and the best way to use the action listener would be to build it into your class that extends the button control so that the user doesn't have to do this on their own. It would look like this.
class Button2 : Button
{
public string LabelName = "";
public Button2()
{
this.Click += this.SetLabelName;
}
private void SetLabelName(object sender, EventArgs e)
{
this.LabelName = "Something?";
}
//You could also do this instead.
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
}
}
If you're talking about changing the Text property of an external Label control, then simply create a property in your Button to hold a reference to a Label. You can set this via the IDE like any other property:
Here's the Button class:
public class MyButton : Button
{
private Label _Label = null;
public Label Label
{
get { return _Label; }
set { _Label = value; }
}
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
if (this.Label != null)
{
this.Label.Text = this.Name;
}
}
}
Here's the Label after I clicked the Button:
I want that when I click on a menu item, display a context menu with items such as "delete", "rename", etc.
How to bind itself a context menu when you right-click on the menu item?
The first idea jumping in my mind was hook up some MouseDown event on the ToolStripMenuItem and show the second ContextMenuStrip at the mouse position in screen coordinates. But it's not such simple. The problem is doing so will require hooking up the event for every items, on that event somehow showing the second ContextMenuStrip will close the current ContextMenuStrip (even we add some Closing event handler and set e.Cancel = true;). It's a little tricky here. We could think of the MouseDown event of the current ContextMenuStrip but in fact this event is hardly fired because all the items lie on top of the ContextMenuStrip. That made me think of the deeper stage where we can catch the WM_RBUTTONDOWN and run code there. We can customize the ContextMenuStrip to catch that message in WndProc or we can use a custom NativeWindow. I would like to use a NativeWindow here. It's time for the code (working perfectly):
public class NativeContextMenuStrip : NativeWindow
{
public class ShowContextMenuEventArgs : EventArgs {
public ToolStripDropDown ContextMenuToShow {get; set;}
}
public delegate void ShowContextMenuEventHandler(ShowContextMenuEventArgs e);
public event ShowContextMenuEventHandler ShowContextMenu;
private Color previousItemBackColor;
public ToolStripItem SourceItem { get; set; }
bool keepOpen;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x204) {//WM_RBUTTONDOWN
OnShowContextMenu(new ShowContextMenuEventArgs());
}
}
protected virtual void OnShowContextMenu(ShowContextMenuEventArgs e)
{
var handler = ShowContextMenu;
if (handler != null)
{
handler(e);
if (e.ContextMenuToShow != null)
{
ContextMenuStrip toolStrip = (ContextMenuStrip)Control.FromHandle(Handle);
Point client = toolStrip.PointToClient(Control.MousePosition);
SourceItem = toolStrip.GetItemAt(client);
previousItemBackColor = SourceItem.BackColor;
SourceItem.BackColor = SystemColors.MenuHighlight;
e.ContextMenuToShow.Closed -= restoreItemState;
e.ContextMenuToShow.Closed += restoreItemState;
keepOpen = true;
e.ContextMenuToShow.Show(Control.MousePosition);
keepOpen = false;
}
}
}
protected override void OnHandleChange()
{
base.OnHandleChange();
ContextMenuStrip toolStrip = Control.FromHandle(Handle) as ContextMenuStrip;
if (toolStrip != null)
{
toolStrip.Closing += toolStripClosing;
}
}
private void restoreItemState(object sender, EventArgs e)
{
SourceItem.BackColor = previousItemBackColor;
SourceItem.Owner.Show();
}
private void toolStripClosing(object sender, ToolStripDropDownClosingEventArgs e)
{
e.Cancel = keepOpen;
}
}
Usage:: The important event is ShowContextMenu, hook up this event and set the ContextMenuStrip you want to show. That's all. Here is the detail:
public partial class Form1 : Form {
public Form1(){
InitializeComponent();
//suppose you have a main ContextMenuStrip and a sub ContextMenuStrip
//try adding some items for both
ContextMenuStrip = new ContextMenuStrip();
ContextMenuStrip.Items.Add("Item 1");
ContextMenuStrip.Items.Add("Item 2");
//sub ContextMenuStrip
var subMenu = new ContextMenuStrip();
subMenu.Items.Add("Delete");
subMenu.Items.Add("Rename");
ContextMenuStrip.HandleCreated += (s,e) => {
nativeMenu.AssignHandle(ContextMenuStrip.Handle);
nativeMenu.ShowContextMenu += (ev) => {
ev.ContextMenuToShow = subMenu;
};
};
}
NativeContextMenuStrip nativeMenu = new NativeContextMenuStrip();
}
To get the item clicking on which shows the sub ContextMenuStrip, you can access the SourceItem of the NativeContextMenuStrip.
I have a class (which extends Framework Element) which contains within it a number of other Elements.
// Click event coverage area
private Rectangle connectorRectangle;
These shapes all have their event handlers, and when the user clicks on them its working well. Now what I want is to be able to 'handle' a right-click on my class from outside the scope of the class.
So I figured the best way to do it is to handle the event internally, and somehow bubble it to the top
private void connectorRectangle_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
MouseButtonEventArgs args = new MouseButtonEventArgs();
//???
e.Handled = true;
}
The problem is that I have no idea how to raise the event. this.OnMouseRightButtonUp doesn't exist, and all the tutorials I'm finding are for raising custom events.
I'm pretty new to silverlight, so bear with me if I missed something obvious.
Try it :
public Rectangle
{
this.Click += new System.EventHandler(Function);
}
private void Function(object sender, System.EventArgs e)
{
if (((MouseEventArgs)e).Button == MouseButtons.Right)
{
//Your code
}
}
Your "exteded Framework Element class" shouldn't handel the mouse event (or if they handel them, set e.Handled to false). Then the event should bubble up automatically (without reraise the event).
EDIT
public class ExtendedFrameworkElement : Grid
{
public ExtendedFrameworkElement()
{
Border b1 = new Border();
b1.Padding = new Thickness(20);
b1.Background = Brushes.Red;
b1.MouseRightButtonUp += b1_MouseRightButtonUp;
Border b2 = new Border();
b2.Padding = new Thickness(20);
b2.Background = Brushes.Green;
b2.MouseRightButtonUp += b2_MouseRightButtonUp;
b1.Child = b2;
this.Children.Add(b1);
}
private void b1_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//DoSomeThing
e.Handled = false;
}
private void b2_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//DoSomeThing
e.Handled = false;
}
}
Xaml:
<Window x:Class="WpfApplicationTest.MainWindow">
<wpfApplicationTest:ExtendedFrameworkElement MouseRightButtonUp="UIElement_OnMouseRightButtonUp"/>
</Window>
Code Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void UIElement_OnMouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
//DoSomeThing
}
}