I'm attempting (for reasons) to use a cue banner textbox in place of the standard textbox in a WinForms dropdown item.
I've gotten it to a state where I can add the new control object to the list of dropdown options, but if I do, it locks up the properties menu for not only it, but also any other options on that same dropdown 'list'. It does not have this issue if I use it elsewhere in the form - just when its used in a dropdown.
I'm posting two pieces of code below:
My CueTextBox class (extend TextBox)
My ToolStripCueTextBox class (derive from ToolStripControlHost for designer availability)
**//1 - Class for box**
public class CueTextBox : TextBox
{
private string mCue;
public string Cue
{
get => mCue;
set
{
mCue = value;
Invalidate();
}
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
const int WM_PAINT = 0xF;
if (m.Msg == WM_PAINT)
{
if (!Focused && string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Cue))
{
using (var graphics = CreateGraphics())
{
TextRenderer.DrawText(
dc: graphics,
text: Cue,
font: Font,
bounds: ClientRectangle,
foreColor: SystemColors.GrayText,
backColor: Enabled ? BackColor : SystemColors.Control,
flags: TextFormatFlags.Top | TextFormatFlags.Left);
}
}
}
}
**//2 - Class for toolstrip**
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.All)]
public class ToolStripCueTextBoxItem : ToolStripControlHost
{
public ToolStripCueTextBoxItem() : base(new CueTextBox())
{
}
}
I'm new here, but any help would be greatly appreciated!
Related
private void downloader_Succeeded(object sender, EventArgs e)
{
FileDownloader.FileInfo fi = downloader.CurrentFile;
string name = fi.Path;
foreach (ListViewItem lvw in listView1.Items)
{
if (lvw.Text == name)
lvw.ForeColor = Color.Green;
}
label6.Text = countFilesDownloaded++.ToString();
}
Each time when it's coloring the item it's flickering.
I saw some answers but none of them is working.
I saw this answer:
Flickering answer
And this one
Flickering answer
Maybe i didn't use them right. But they didn't work.
Tried to add this to the form1 at the bottom:
protected override CreateParams CreateParams {
get {
var parms = base.CreateParams;
parms.Style &= ~0x02000000; // Turn off WS_CLIPCHILDREN
return parms;
}
}
Then tried to create instance of this each time a item was coloring inside the event.
I had your problem and after doing some research it appears that the ListView control repaints its entire area whenever you modify a single item. The solution is to subclass the ListView and filter out the WM_ERASEBKGND message. This did the trick for me.
For more information see here:
c# flickering Listview on update
public partial class ListViewNF : ListView
{
public ListViewNF()
{
}
public ListViewNF(IContainer container)
{
container.Add(this);
InitializeComponent();
//Activate double buffering
this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint, true);
//Enable the OnNotifyMessage event so we get a chance to filter out
// Windows messages before they get to the form's WndProc
this.SetStyle(ControlStyles.EnableNotifyMessage, true);
}
protected override void OnNotifyMessage(Message m)
{
//Filter out the WM_ERASEBKGND message
if (m.Msg != 0x14)
{
base.OnNotifyMessage(m);
}
}
}
I am creating a custom control that acts like the TabControl. I want the tab headers to be clickable in design time, just like the TabControl. Using the sample code I found on the Microsoft site, I wrote the following code. It works, but there is one problem.
As for the real TabControl, if you click a tab header when the TabControl has not been selected, the selected tab changes, AND the TabControl gets selected showing the resizing border which has a moving handle and a small button for "TabControl Tasks".
Doing the same thing with my code below only changes the selected tab header; it does not make my control be selected. I think I need to tell the Visual Studio Designer to select my control, somehow. But how?
public class MyDesigner : System.Windows.Forms.Design.ControlDesigner
{
private Adorner MyAdorner;
public override void Initialize(IComponent component)
{
base.Initialize(component);
MyAdorner = new Adorner();
this.BehaviorService.Adorners.Add(MyAdorner);
MyAdorner.Glyphs.Add(new MyGlyph(BehaviorService, (MyTabControl)Control));
}
protected override void Dispose(bool disposing)
{
if (disposing && MyAdorner != null)
{
BehaviorService b = BehaviorService;
if (b != null)
{
b.Adorners.Remove(MyAdorner);
}
}
}
class MyGlyph : Glyph
{
MyTabControl TargetControl;
BehaviorService behaviorSvc;
public MyGlyph(BehaviorService behaviorSvc, MyTabControl targetControl)
:base(new ClickingBehaviour())
{
this.behaviorSvc = behaviorSvc;
this.TargetControl = targetControl;
}
private void OnMouseClick(MouseButtons button, Point adornerPoint)
{
var screenPoint = behaviorSvc.AdornerWindowPointToScreen(adornerPoint);
var targetPoint = TargetControl.PointToClient(screenPoint);
TargetControl.DesignTimeClick(button, targetPoint);
}
public override Rectangle Bounds
{
get
{
Point edge = behaviorSvc.ControlToAdornerWindow(TargetControl);
Size size = TargetControl.Size;
Rectangle bounds = new Rectangle(edge, size);
return bounds;
}
}
public override Cursor GetHitTest(Point p)
{
Cursor handled = null;
if (Bounds.Contains(p))
{
var screenPoint = behaviorSvc.AdornerWindowPointToScreen(p);
var targetPoint = TargetControl.PointToClient(screenPoint);
if(TargetControl.IsHeaderArea(targetPoint))
handled = Cursors.Default;
}
return handled;
}
public override void Paint(PaintEventArgs pe)
{
}
class ClickingBehaviour : Behavior
{
public override bool OnMouseDown(Glyph g, MouseButtons button, Point mouseLoc)
{
MyGlyph myG = g as MyGlyph;
myG.OnMouseClick(button, mouseLoc);
return base.OnMouseDown(g, button, mouseLoc);
}
}
}
}
I could not figure out how to do it with the approach which uses an Adorner as above. So, I resorted to using Win32 message (I tried to avoid using Win32 for interoperability).
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0201 && m.WParam.ToInt32() == 0x0001)
{
var target = (Control as MyTabControl);
if (true) //how to know if focused?
{
var lparam32 = m.LParam.ToInt32();
int lowWord = lparam32 & 0xffff;
int highWord = lparam32 >> 16;
Point p = new Point(lowWord, highWord);
if (target.IsHeaderArea(p))
{
target.DesignTimeClick(MouseButtons.Left, p);
}
}
}
base.WndProc(ref m);
}
It works, but the only minor problem is that the tab index changes at the first click when the tab is not selected. Clicking a tab on a real TabControl when it is not selected does not change the tab but only selects the tab. But I guess I can live with this minor difference.
How can I set XtraForm title text to middle of title bar?
I have tried example from other answer, but it causes window buttons to move few pixels depending on focus.
When I click window title bar window buttons go to one position, when I move mouse over buttons they move to other position few pixels off.
Try the following approach (based on XtraForm - How to center-align a header caption text example). It works to me as far as the solution provided by DevExpress team but does not contains Buttons.CalcButtons method call that can theoretically affect form's buttons position:
public partial class Form1 : XtraForm {
static Form1() {
SkinManager.EnableFormSkins();
}
public Form1() {
InitializeComponent();
}
protected override FormPainter CreateFormBorderPainter() {
return new CustomFormPainter(this, LookAndFeel);
}
}
public class CustomFormPainter : FormPainter {
public CustomFormPainter(Control owner, DevExpress.Skins.ISkinProvider provider)
: base(owner, provider) {
}
protected override void DrawText(DevExpress.Utils.Drawing.GraphicsCache cache) {
string text = Text;
if(text == null || text.Length == 0 || TextBounds.IsEmpty) return;
using(AppearanceObject appearance = new AppearanceObject(GetDefaultAppearance())) {
appearance.TextOptions.Trimming = Trimming.EllipsisCharacter;
appearance.TextOptions.HAlignment = HorzAlignment.Center;
if(AllowHtmlDraw) {
DrawHtmlText(cache, appearance);
return;
}
Rectangle r = RectangleHelper.GetCenterBounds(TextBounds, new Size(TextBounds.Width, CalcTextHeight(cache.Graphics, appearance)));
DrawTextShadow(cache, appearance, r);
cache.DrawString(text, appearance.Font, appearance.GetForeBrush(cache), r, appearance.GetStringFormat());
}
}
}
I need to have 2 groups of controls on the screen: inputs and outputs (so they have 2 states: On or Off). Thus CheckBox seems to be a good choice. Checking any output will set it.
However, when displaying inputs there will be no user interaction with it. User is only allowed to see its value, not to change it.
Question: how to make checkbos visually appears as read-only ?
Could think about possible solutions:
Make CheckBox disabled. Bad: there will be no tooltip (possible to solve it? by fake panel on top?) and visually disabled CheckBox is not nice (and I don't want to make user think it is disabled).
Use different control. Which one? Label doesn't have nice placeholder for the On/Off value. RadioButton look differently, but they usually means there is a single choice out of many, while values of inputs are independent.
Making own component. Drawing the whole CheckBox is a bit overkill (and honestly, I don't know how to do it to have Win7 appearance). Would it be possible to add only ReadOnly appearance to the box part easily?
What do you guys think?
There is a solution that is combination of the existing answers.
checkBox.ForeColor = Color.Gray; // Read-only appearance
checkBox.AutoCheck = false; // Read-only behavior
// Tooltip is possible because the checkbox is Enabled
var toolTip = new ToolTip();
toolTip.SetToolTip(checkBox, "This checkbox is read-only.");
The result is a CheckBox that
appears disabled with gray text
prevents the Checked value from changing when clicked
supports a Tooltip
You have to draw everything yourself. I think you should use some controls with correct layout to mimic it. Here is the demo code for you, note that it does not support AutoSize correctly. Because the drawn stuff is always wider than the default stuff (which the AutoSize works with), implementing the AutoSize is not easy, If you don't care too much about AutoSize, this would be the great control for you:
public class XCheckBox : CheckBox
{
public XCheckBox()
{
SetStyle(ControlStyles.Opaque, false);
ReadOnlyCheckedColor = Color.Green;
ReadOnlyUncheckedColor = Color.Gray;
}
public bool ReadOnly { get; set; }
public bool AlwaysShowCheck { get; set; }
public Color ReadOnlyCheckedColor { get; set; }
public Color ReadOnlyUncheckedColor { get; set; }
protected override void OnPaint(PaintEventArgs pevent)
{
if (ReadOnly)
{
pevent.Graphics.SmoothingMode = SmoothingMode.HighQuality;
pevent.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
if (AlwaysShowCheck || Checked)
{
RenderCheck(pevent.Graphics);
}
RenderText(pevent.Graphics);
}
else base.OnPaint(pevent);
}
private void RenderCheck(Graphics g)
{
float fontScale = Font.Size / 8.25f;
Size glyphSize = CheckBoxRenderer.GetGlyphSize(g, System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal);
glyphSize.Width = (int) (glyphSize.Width * fontScale);
glyphSize.Height = (int)(glyphSize.Height * fontScale);
string checkAlign = CheckAlign.ToString();
using (GraphicsPath gp = new GraphicsPath())
using (Pen pen = new Pen(Checked ? ReadOnlyCheckedColor : ReadOnlyUncheckedColor, 1.5f)
{
LineJoin = LineJoin.Round,
EndCap = LineCap.Round,
StartCap = LineCap.Round
})
{
gp.AddLine(new Point(3, 7), new Point(5, 10));
gp.AddLine(new Point(5, 10), new Point(8, 3));
float dx = checkAlign.EndsWith("Right") ? Math.Max(-4*fontScale, ClientSize.Width - glyphSize.Width - 4 * fontScale) :
checkAlign.EndsWith("Center") ? Math.Max(-4*fontScale, (ClientSize.Width - glyphSize.Width) / 2 - 4 * fontScale) : -4;
float dy = checkAlign.StartsWith("Bottom") ? Math.Max(-4*fontScale, ClientSize.Height - glyphSize.Height - 4*fontScale) :
checkAlign.StartsWith("Middle") ? Math.Max(-4*fontScale, (ClientSize.Height - glyphSize.Height) / 2 - 4*fontScale) : 0;
g.TranslateTransform(dx, dy);
g.ScaleTransform(1.5f*fontScale, 1.5f*fontScale);
g.DrawPath(pen, gp);
g.ResetTransform();
}
}
private void RenderText(Graphics g)
{
Size glyphSize = CheckBoxRenderer.GetGlyphSize(g, System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal);
float fontScale = Font.Size / 8.25f;
glyphSize.Width = (int)(glyphSize.Width * fontScale);
glyphSize.Height = (int)(glyphSize.Height * fontScale);
string checkAlign = CheckAlign.ToString();
using (StringFormat sf = new StringFormat())
{
string alignment = TextAlign.ToString();
sf.LineAlignment = alignment.StartsWith("Top") ? StringAlignment.Near :
alignment.StartsWith("Middle") ? StringAlignment.Center : StringAlignment.Far;
sf.Alignment = alignment.EndsWith("Left") ? StringAlignment.Near :
alignment.EndsWith("Center") ? StringAlignment.Center : StringAlignment.Far;
sf.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip;
Rectangle textRectangle = ClientRectangle;
if (checkAlign.EndsWith("Left"))
{
textRectangle.Width -= glyphSize.Width;
textRectangle.Offset(glyphSize.Width, 0);
}
else if (checkAlign.EndsWith("Right"))
{
textRectangle.Width -= glyphSize.Width;
textRectangle.X = 0;
}
g.DrawString(Text, Font, new SolidBrush(ForeColor), textRectangle, sf);
}
}
bool suppressCheckedChanged;
protected override void OnClick(EventArgs e)
{
if (ReadOnly) {
suppressCheckedChanged = true;
Checked = !Checked;
suppressCheckedChanged = false;
}
base.OnClick(e);
}
protected override void OnCheckedChanged(EventArgs e)
{
if (suppressCheckedChanged) return;
base.OnCheckedChanged(e);
}
}
NOTE: The code is not fully implemented, everything is kept as simple as possible. You can change the AlwaysShowCheck property to choose the ReadOnly unchecked state, it can be a gray tick mark or nothing. You can set the ReadOnly to true to make it Read-only visual.
AlwaysShowCheck is set to true (the ReadOnly unchecked state is indicated by a gray tick mark)
AlwaysShowCheck is set to false (the ReadOnly unchecked state is indicated by nothing)
This is an old post but still can be usefull so here is my solution.
In order to make a read-only behavior:
Disable highlight when the cursor is over the CheckBox
Disable reacting (logically or visibly) to a mouse click
Have tooltips enabled
We can inherit the CheckBox class and disable mouse and keyboard interaction:
public class ReadOnlyCheckBox : CheckBox
{
[System.ComponentModel.Category("Behavior")]
[System.ComponentModel.DefaultValue(false)]
public bool ReadOnly { get; set; } = false;
protected override void OnMouseEnter(EventArgs e)
{
// Disable highlight when the cursor is over the CheckBox
if (!ReadOnly) base.OnMouseEnter(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
// Disable reacting (logically or visibly) to a mouse click
if (!ReadOnly) base.OnMouseDown(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
// Suppress space key to disable checking/unchecking
if (!ReadOnly || e.KeyData != Keys.Space) base.OnKeyDown(e);
}
}
In order to make it visually apparent that the CheckBox is read-only, we can change the ForColor according to the ReadOnly property.
Note: changing the ForColor only changes the text color, the colors of the checkmark can only be changed by overriding the OnPaint method and repainting the CheckBox (as far as I know).
Here is an extended version of the previous code that changes the ForColor according to the ReadOnly property:
public class ReadOnlyCheckBox : CheckBox
{
private bool _readOnly = false;
private Color _readOnlyForeColor = Color.Gray;
private Color _normalForeColor = Color.Black;
[System.ComponentModel.Category("Behavior")]
[System.ComponentModel.DefaultValue(false)]
public bool ReadOnly
{
get => _readOnly;
set
{
if (_readOnly != value)
{
_readOnly = value;
UpdateForColor();
}
}
}
[System.ComponentModel.Category("Appearance")]
[System.ComponentModel.DefaultValue(typeof(Color), "Black")]
public Color NormalForeColor
{
get => _normalForeColor;
set
{
if (_normalForeColor != value)
{
_normalForeColor = value;
UpdateForColor();
}
}
}
[System.ComponentModel.Category("Appearance")]
[System.ComponentModel.DefaultValue(typeof(Color), "Gray")]
public Color ReadOnlyForeColor
{
get => _readOnlyForeColor;
set
{
if (_readOnlyForeColor != value)
{
_readOnlyForeColor = value;
UpdateForColor();
}
}
}
// Hide ForeColor from the editor
[System.ComponentModel.Browsable(false)]
[System.ComponentModel.EditorBrowsable(
System.ComponentModel.EditorBrowsableState.Never)]
public override Color ForeColor
{
get => base.ForeColor;
set => base.ForeColor = value;
}
public ReadOnlyCheckBox()
{
UpdateForColor();
}
private void UpdateForColor()
{
ForeColor = ReadOnly ? ReadOnlyForeColor : NormalForeColor;
}
protected override void OnMouseEnter(EventArgs e)
{
// Disable highlight when the cursor is over the CheckBox
if (!ReadOnly) base.OnMouseEnter(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
// Disable reacting (logically or visibly) to a mouse click
if (!ReadOnly) base.OnMouseDown(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
// Suppress space key to disable checking/unchecking
if (!ReadOnly || e.KeyData != Keys.Space) base.OnKeyDown(e);
}
}
So far the easiest solution (credits go to ShadowWizard) is to set ForeColor = Color.Gray, this makes user think, what CheckBox is disabled.
Compared to Enabled = false, pluses are:
ToolTip is working;
box part looks pretty (it react on mouse hovering and is very clearly seen whenever is checked or unchecked).
No minuses.
It is not necessary to write the entire control, just write a derivative of Checkbox.
A ReadOnly property is added to the control, this causes the control to handle when it can change its value.
public class CheckBoxReadOnly : CheckBox
{
private bool _readOnly = false;
[DefaultValue(false)]
public bool ReadOnly
{
get { return _readOnly; }
set
{
if (_readOnly != value)
{
_readOnly = value;
OnReadOnlyChanged(new EventArgs());
}
}
}
int _flag = 0;
public event EventHandler ReadOnlyChanged;
protected void OnReadOnlyChanged(EventArgs e)
{
ReadOnlyChanged?.Invoke(this, e);
}
protected override void OnCheckedChanged(EventArgs e)
{
if (ReadOnly)
{
_flag++;
if (_flag == 1)
Checked = !Checked;
}
else
{
base.OnCheckedChanged(e);
}
_flag = 0;
}
}
You may provide a listener for an event of clicking on CheckBox, as there's ability to cancel its usual flow at runtime.
In the Property table just make selection mode to none.
Visual studio has now it available under:
Properties -> Properties -> ReadOnly :)
I have created my own radio button class – namely MyRadioButton, as the built in .NET class did not enlarge effectively. (using this for touch screen)
MyRadioButton Class works well, expect for an issue which I do not know How to resolve - When I have multiple MyRdaioButtons on a form, I can select all of them.... They somehow do not work as they should where when one selects one the others are automatically be deselected.
My code is as follows:
public class MyRadioButton : Control
{
public MyRadioButton()
{
}
private string textTowrite;
private bool checkStatus;
private int width;
private int height;
public event EventHandler CheckedChanged;
public delegate void MyHandler1(object sender, EventArgs e);
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
if (Checked)
Checked = false;
else
Checked = true;
Invalidate(true);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
ButtonState btnstate;
Rectangle rRadioButton;
if (checkStatus)
{
btnstate = ButtonState.Checked;
}
else
btnstate = ButtonState.Normal;
rRadioButton = new Rectangle(0, 0, RBWidth, RBHeight);
FontFamily ft = new FontFamily("Tahoma");
Font fnt_radio = new Font(ft, (int)(18), FontStyle.Bold);
ControlPaint.DrawRadioButton(e.Graphics, -2, 10, rRadioButton.Width,
rRadioButton.Height, btnstate);
//RadioButton's text left justified & centered vertically
e.Graphics.DrawString(textTowrite, fnt_radio, new SolidBrush(Color.Black), rRadioButton.Right + 1, 16);
}
protected virtual void OnCheckedChanged(EventArgs e)
{
if (CheckedChanged != null)
{
CheckedChanged(this, e);
}
}
public override string Text
{
get { return textTowrite; }
set { textTowrite = value; }
}
public bool Checked
{
get { return checkStatus; }
set
{
checkStatus = value;
OnCheckedChanged(EventArgs.Empty);
}
}
public int RBWidth
{
get
{
if (width == 0)
{
width = 40;
}
return width;
}
set
{
if (width != value)
{
width = value;
Invalidate();
}
}
}
public int RBHeight
{
get
{
if (height == 0)
{
height = 40;
}
return height;
}
set
{
if (height != value)
{
height = value;
Invalidate();
}
}
}
}
If someone could provide me with a solution it would be greatly appreciated, as I am pulling out my hair
Thanks
Jens
You may also consider inheriting your control directly from RadioButton, giving you access to the RadioButton.GroupName property, or you will need to implement this type of functionality yourself as kbrinley has posted.
Have you considered using images on a RadioButton control instead? According to ButtonBase's documentation (which RadioButton inherits from):
To have the derived button control
display an image, set the Image
property or the ImageList and
ImageIndex properties.
Note that I have no idea how you'd do selected/unselected states with images... I imagine the ImageList is related to this.
Since this is your control, you will have to provide the logic for this to act like a radio button.
First, I'd suggest placing all of your Radio buttons into a Container control.
Then, at the beginning OnClick method of your control, use the GetContainerControl method to retrieve the Container object and iterate over all of the Radio buttons in the container and set the Checked property of them to false.