Windows Forms: How to extend a button? - c#

How can I extend a Button?
I want a Button that has an additional property IsSwitchOffable.
Do I have to write an extra custom control?
EDIT:
I want that the button is usable as a standard WindowsFormsButton.
This includes that I can add the button at design time!

Extending a button control is no different then extending any class in C#. Simply do the following:
class ToggleButton : Button {
// Add your extra code
}

You need to create a class that inherits the System.Windows.Forms.Button class and adds your property and associated behavior.
After compiling your project, your new class will appear in the toolbox.

I know this is old and has been answered - however,
Why make life difficult?
Each control has a Tag property which you can easily set to IsSwitchedOffable - or better English CanBeDisabled
Far easier.

In my puzzle application 2d button's location is to be changed... So i need extra facilities...
My button ButObj extends Button class
Public Class ButObj : Button
{
Point initloc;
Public ButObj(Point loc)
{ this.Location=initloc=loc ; }
Public bool isNearto(ButObj X)
{
if (this.Location.X==X.Location.X || this.Location.Y==X.Location.Y)
return true;
else return false;
}
Public bool isSettled()
{
if(this.Location==initloc)
return true ;
else return false;
}
Public void Replace (ButObj X)
{
Point temp ;
temp=this.Location;
this.Location=X.Location;
X.Location=temp;
}
}
Following code is written in form 1_load ()
ButObj[ ][ ] B=new ButObj[4][4];
char c='A';
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
{ B[i][j]=new ButObj(new Point (i*100+10,j*100+10));
B[j][i].Text = ""+c++;
B[i][j].Font =new Font ("Arial", 24);
this.Controls.Add (B[i][j]);
B[i][j].MouseClick += new MouseEventHandler(MouseClick); }
Coding in mouse click event
private void MouseClick(Object sender, EventArgs e)
{
ButObj b=(ButObj)sender;
if (b.isNearto(B[3][3]))
b.Replace(B[3][3]);
\\ checking after replace
if(AllSolved());\\game over
}
bool AllSolved()
{
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
if (!B[i][j].isSettled)
return false ;
return true;
}

Related

Issue with making an hangman game in UWP

I'm trying to create an hangman game in UWP and I'm not quite sure where to type the button click event of each letter in the code in order to have it recognize all of the variables in MainPage without affecting functionality.
If possible to have the button clicks in a separate class, even better.
Would appreciate if you could help me, thanks in advance!
namespace Hangman
{
public sealed partial class MainPage : Page
{
int _currentIndex;
string _currentWord;
string[] _strArr = { "ant", "bee", "spider", "mosquito" };
int _difficulty = 1;
public MainPage()
{
this.InitializeComponent();
Random rnd = new Random();
_currentIndex = rnd.Next(0, 4);
_currentWord = _strArr[_currentIndex];
foreach (char c in _currentWord)
{
string _hiddenWord = string.Empty;
foreach (char ch in _currentWord)
{
_hiddenWord += "_" + (char)160;
}
_textBl.Text = _hiddenWord;
}
}
private void a_Click(object sender, RoutedEventArgs e)
{
}
}
}
I want to capture Button clicks of buttons on my XML code. I've made a property like so public char Key { get; set; } and had each Button click insert a different value dependant on the letter, for example: on button_a, Key = 'a';
I probably understand what you mean. You have a lot of buttons (like a button that makes up a keyboard). Each time you click the button, you get the button's identity and then type it into the text box.
You can use the Button.Tag property to record your key, like this:
<Button Tag="a" Content="A" Click="Button_Click" />
In code-behind, the Button_Click method has two parameters, where the sender refers to the Button that triggered the event, so you can convert it and get the Tag property.
private void Button_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
string tag = btn.Tag.ToString();
// Do Something
}
In this way, you can bind all the buttons to the same handler, which is very convenient.
Best regards.
You have to go to your XAML file where you design your UI, find the button and then add
<Button Content="Your Button Text" onClick="a_Click" />
there.

WinForms RichTextBox selection issue if there is hidden text

I have a selection problem with RichTextBox control. If the control contains hidden text, the selection behaves strangely.
If I do a selection with the mouse, sometimes the bug is present, sometimes not. Especially if I select more lines the bug seems to disappear.
But the bug is very annoying if the user tries to select the text with the keyboard.
The issue is the following: Let's say my control has this text:
There is the little upgraded control that hopefully will make a
differnce when it is hidden text the reason
Then let's say we hide words upgraded, hopefully, hidden by applying proper RTF tags:
#"{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fni‌​l\fcharset0 Microsoft Sans Serif;}} \viewkind4\uc1\pard\f0\fs17 There is the little \v upgraded \v0 control that \v hopefully \v0 will make a differnce when it is \v hidden \v0 text the reason\par}";
It all looks good, but when the user tries to select the text using the keyboard, selection seems to reset every time a hidden word is reached.
It is crucial for my control to contain that hidden text (some important id's from my objects that are forming the content inside the control are stored as hidden text at special positions, and I can't/don't want to change that).
I am using the following Form, where richTextBox is the RichTextBox in question and RichTextBox_SelectionChanged is the SelectionChanged event handler that we will try to use to fix our issue.
public MainForm()
{
InitializeComponent();
this.richTextBox.Rtf =
#"{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fni‌​l\fcharset0 Microsoft Sans Serif;}}\viewkind4\uc1\pard\f0\fs17 My \v upgraded \v0 control that \v hopefully \v0 will make it\par}";
this.richTextBox.SelectionChanged += RichTextBox_SelectionChanged;
}
Basically, the idea is simple - use SelectionChanged handler to properly Select hidden data alongside the previous selection.
For that we will have to store the previous selection data:
private class SelectionData
{
public static SelectionData FromStartAndEnd(
Int32 start,
Int32 end)
{
return new SelectionData(
start: start,
length: end - start);
}
public SelectionData(TextBoxBase tb)
: this(
start: tb.SelectionStart,
length: tb.SelectionLength)
{ }
public SelectionData(Int32 start, Int32 length)
{
this.Start = start;
this.Length = length;
}
public readonly Int32 Start, Length;
public Int32 End
{
get
{
return this.Start + this.Length;
}
}
}
in some field:
private SelectionData _previousSelection;
And update/fix selection inside the SelectionChanged hanlder
private void RichTextBox_SelectionChanged(object sender, EventArgs e)
{
var newSelection = new SelectionData(this.richTextBox);
this.SelfUpdateSelection(newSelection);
}
SelfUpdateSelection method would be something like:
private Boolean _isSelectionSelfUpdating = false;
private void SelfUpdateSelection(SelectionData newSelection)
{
if (!this.IsKeyBoardSelection())
{
// Or it will use previous selection when we don't need it.
this._previousSelection = null;
return;
}
if (this._isSelectionSelfUpdating)
return;
this._isSelectionSelfUpdating = true;
try
{
var fixedSelection = this.FixSelection(newSelection);
this.richTextBox.Select(
start: fixedSelection.Start,
length: fixedSelection.Length);
this._previousSelection = fixedSelection;
}
finally
{
this._isSelectionSelfUpdating = false;
}
}
IsKeyBoardSelection for simplicity can be something like the following, though properly detecting selection change source will be more difficult:
private bool IsKeyBoardSelection()
{
// It may not be true, but usually close enough.
return Control.ModifierKeys.HasFlag(Keys.Shift);
}
FixSelection method should compare whether newSelection can be a this._previousSelection and create a new SelectionData that will contain both newSelection, this._previousSelection and the hidden data between them.
You can use something like this:
private SelectionData FixSelection(SelectionData newSelection)
{
if (this._previousSelection == null)
return newSelection;
var start = Math.Min(
newSelection.Start,
this._previousSelection.Start);
var end = Math.Max(
newSelection.End,
this._previousSelection.End);
return SelectionData.FromStartAndEnd(
start: start,
end: end);
}
but it:
Will work only with forward(right arrow) selection - can be fixed by adding some additional logic to FixSelection.
Will also require a bit of additional this._previousSelection handling (like resetting it on FocusLost event) - there are some edge cases, but still nothing impossible.
public MainForm()
{
...
this.richTextBox.LostFocus += RichTextBox_LostFocus;
}
private void RichTextBox_LostFocus(object sender, EventArgs e)
{
this._previousSelection = null;
}
P.S.: For simplicity I have implemented everything inside the form with fields and form-level handlers, but with some effort it could be made into something reusable (at worst derived RichTextBox, at best some external component that will provide such handling for RichTextBox).

DevExpress Set XtraTab Selected Page

I was trying to set the XtraTab Selected page in the constructor it self as follows,
public frmInquiryManagement()
{
InitializeComponent();
tabInquiryManagement.SelectedTabPage = xtraTabPage3;
}
But it doesn't work that way. Please help me to do this.
XtraTabControl does not provide this method to directly set a selected page. What i see is, to implement this method, we need to implement a loop internally.
for(int i = 0; i < xtraTabControl1.TabPages.Count; i ++)
if(xtraTabControl1.TabPages[i].Name == "someName"){
xtraTabControl1.SelectedTabPage = xtraTabControl1.TabPages[i];
break;
}
Else this is one of the clear solutions :
tabpage1.Show();
tabpage1.pageVisible=true;
xtraTabControl1.tabPages[0].selected=true;
Hope it helps.
Cheers.
If you want to achieve that you must use PageEnabled property from XtraTabPage component.
xtraTabPage3.PageEnabled = true;
private void Form1_Load(object sender, EventArgs e)
{
SelectTabByTitle("xtraTabPage3",xtraTabControl1);
}
private void SelectTabByTitle(String tabTitle, XtraTabControl tabControl)
{
if (tabControl != null)
{
XtraTabPage pageToSelect = (from curPage in tabControl.TabPages
where curPage.Text == tabTitle
select curPage).FirstOrDefault();
if (pageToSelect != null)
{
tabControl.SelectedTabPage = pageToSelect;
}
}
}
xtraTabControl1.SelectedTabPageIndex = 0;, where 0 is the index of the page you wish to display.
Your code should normally work, but it seems that the problem is that the Form has not loaded yet and the Tabs are not visible yet. Try setting the SelectedTabPage on the Load event, or the Shown event
Use the following code in the Form's Load event handler:
tabInquiryManagement.SelectedTabPage = xtraTabPage3;
tabInquiryManagement.MakePageVisible(xtraTabPage3);

Enable a button to be clicked at design-time in Visual Studio?

My setting:
I've got a C# application (.NET 3.5) in Visual Studio 2008. No chance to switch to WPF or whatsoever :).
My app contains a custom control (a button class derived from Windows.Forms.Button) that acts as a replacement for the Windows.Forms.TabControl. I can associate these buttons with one another and each button can be associated with one control that it is dealing with (usually some sort of Windows.Forms.Panel). It looks something like this:
public class TabButton : System.Windows.Forms.Button
{
// ...
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
this.myAssociatedControl.Visible = true;
this.tellMyBuddiesToHideTheirControls();
}
// ...
}
Basically it is just about clicking a button, showing its bound control and having the controls bound to the associated buttons disappear - just like the TabControl, but the approach is easily designable and I can place the buttons far from their content panels.
The problem:
This works pretty well at runtime, but the usage at design time is arguably odd: With the mouse, find a control that´s belonging to the group and run a series of <Send To Back>s until the desired control is visible.
The question:
Is there a way to tell the VS designer to evaluate the clicks on the buttons at design time like it does with the TabControl so that I can switch the tabs just by clicking them like I would at runtime?
I've been searching for quite a while now. There are some articles here at SO but they only seem to cover adding additional attributes to the properties designer.
Edith says:
By request, an answer to my own question ...
This is the solution that is suitable to my application. It is basically an example from the msdn with some twists to get the custom designer to use a callback on click. Hope it helps anyone :-).
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
public class TabButtonDesigner : System.Windows.Forms.Design.ControlDesigner
{
ShowTabGlyph myGlyph = null;
Adorner myAdorner;
public TabButtonDesigner()
{
}
public override void Initialize(IComponent component)
{
base.Initialize(component);
// Add the custom set of glyphs using the BehaviorService.
// Glyphs live on adornders.
myAdorner = new Adorner();
BehaviorService.Adorners.Add(myAdorner);
myGlyph = new ShowTabGlyph(BehaviorService, Control);
myGlyph.Callback = () =>
{
((MyCustomTabButton)this.Control).ShowMyTab();
};
myAdorner.Glyphs.Add(myGlyph);
}
class ShowTabGlyph : Glyph
{
Control control;
BehaviorService behaviorSvc;
public Action Callback
{
get;
set;
}
public ShowTabGlyph(BehaviorService behaviorSvc, Control control) :
base(new ShowTabBehavior())
{
this.behaviorSvc = behaviorSvc;
this.control = control;
}
public override Rectangle Bounds
{
get
{
// Create a glyph that is 10x10 and sitting
// in the middle of the control. Glyph coordinates
// are in adorner window coordinates, so we must map
// using the behavior service.
Point edge = behaviorSvc.ControlToAdornerWindow(control);
Size size = control.Size;
Point center = new Point(edge.X + (size.Width / 2),
edge.Y + (size.Height / 2));
Rectangle bounds = new Rectangle(
center.X - 5,
center.Y - 5,
10,
10);
return bounds;
}
}
public override Cursor GetHitTest(Point p)
{
// GetHitTest is called to see if the point is
// within this glyph. This gives us a chance to decide
// what cursor to show. Returning null from here means
// the mouse pointer is not currently inside of the glyph.
// Returning a valid cursor here indicates the pointer is
// inside the glyph, and also enables our Behavior property
// as the active behavior.
if (Bounds.Contains(p))
{
return Cursors.Hand;
}
return null;
}
public override void Paint(PaintEventArgs pe)
{
// Draw our glyph. It is simply a blue ellipse.
pe.Graphics.DrawEllipse(Pens.Blue, Bounds);
}
// By providing our own behavior we can do something interesting
// when the user clicks or manipulates our glyph.
class ShowTabBehavior : Behavior
{
public override bool OnMouseUp(Glyph g, MouseButtons button)
{
//MessageBox.Show("Hey, you clicked the mouse here");
//this.
ShowTabGlyph myG = (ShowTabGlyph)g;
if (myG.Callback != null)
{
myG.Callback();
}
return true; // indicating we processed this event.
}
}
}
}
[DesignerAttribute(typeof(TabButtonDesigner))]
public class MyCustomTabButton : System.Windows.Forms.Button
{
// The attribute will assign the custom designer to the TabButton
// and after a rebuild the button contains a centered blue circle
// that acts at design time like the button in runtime does ...
// ...
}

c# WinForm: Remove or Customize the 'Focus Rectangle' for Buttons

Is there a way to disable or better yet draw your own focus rectangle for a regular button control! (that dotted line seems so Windowss 95ish)
I've noticed that the control properties (FOR BUTTONS) does not have a ownerdrawfixed setting (which I don't know if that's even the route to use for the solution, although i've seen it used for customizing other controls).
Getting this right is trickier than it sounds. No doubt one of the reasons that custom button painting isn't overridable. This worked as expected:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
class MyButton : Button {
private VisualStyleRenderer renderer;
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
if (this.Focused && Application.RenderWithVisualStyles && this.FlatStyle == FlatStyle.Standard) {
if (renderer == null) {
VisualStyleElement elem = VisualStyleElement.Button.PushButton.Normal;
renderer = new VisualStyleRenderer(elem.ClassName, elem.Part, (int)PushButtonState.Normal);
}
Rectangle rc = renderer.GetBackgroundContentRectangle(e.Graphics, new Rectangle(0, 0, this.Width, this.Height));
rc.Height--;
rc.Width--;
using (Pen p = new Pen(Brushes.DarkGray)) {
e.Graphics.DrawRectangle(p, rc);
}
}
}
}
A quick and easy way to disable the focus rectangle all together is to subclass the control and include this code:
public class CustomButton : Button
{
protected override bool ShowFocusCues
{
get
{
return false;
}
}
}
Just simple way.
Set
button.FlatStyle = Flat;
button.FlatAppearance.BorderColor = Color.FromArgb(0, 255, 255, 255);
button.FlatAppearance.BorderSize = 0;
button.TabStop = false;
FlatAppearance.BorderColor
set on code cause could not transparent color set in design mode.
Subclass the Button class and override OnPaint. If your override does not call base.OnPaint, nothing will be drawn for the button and you will have complete control (including the focus rectangle).
One quick/dirty solution that I found (for removing the focus rectangle only) was explicitly defining the background color. For the default control color, for ex:
this._dropDownButton.BackColor = System.Drawing.ColorTranslator.FromHtml("#F0F0F0");
EDIT: Apparently this doesn't work. It was being fixed in my case for an unrelated reason. Apologies.
I had the same issue when using BackgroundImage to set an image on the button. When the user pressed 'Tab', my image button got a black rectangle.
The solution that worked for me is:
Call for NotifyDefault(false) for every button I used.
Set the TabStop property to false for every button I used.
Tested on .NET Framework 4.6.2.
Before:
After:
In my case, I have to use both solutions above to make it work.
public class ButtonNoFocus : Button
{
protected override bool ShowFocusCues
{
get
{
return false;
}
}
public override void NotifyDefault(bool value)
{
base.NotifyDefault(false);
}
}
A simple solution to hide the focus frame would be to switch the focus from buttons to a dummy control as soon as the button has been clicked:
public frmMain()
{
...
RemoveControlFocusFrame(this);
}
private void RemoveControlFocusFrame(Control c)
{
if (c.Controls.Count == 0)
{
if (c is Button || c is CheckBox)
c.GotFocus += (o, e) => lblFocusDump.Focus();
return;
}
foreach (Control sub in c.Controls)
RemoveControlFocusFrame(sub);
}
The dummy lblFocusDump label has its Visible set to true and can be hidden in Designer by pushing it to background behind any other control.

Categories