Custom Winforms Controls (a button specifically) - winforms

I'm trying to create a custom button where the foreColor is always crimson and the backColor is always cyan. Ugly color scheme, but I'm just trying to get it so I can create large amounts of controls with a consistent color scheme without setting each control individually. Here's how I coded the button:
public partial class CustomButton : Button
{
private static Color _defaultForeColor = Color.Crimson;
private static Color _defaultBackColor = Color.Cyan;
public CustomButton()
{
InitializeComponent();
base.ForeColor = _defaultForeColor;
base.BackColor = _defaultBackColor;
}
public AutoScaleMode AutoScaleMode { get; set; }
[DefaultValue(typeof(Color), "Crimson")]
override public Color ForeColor
{
get { return base.ForeColor; }
set
{
base.ForeColor = _defaultForeColor;
}
}
[DefaultValue(typeof(Color), "Cyan")]
public override Color BackColor
{
get { return base.BackColor; }
set
{
base.BackColor = _defaultBackColor;
}
}
}
When I drop the custom button onto my form, the background is the regular button color and the text is crimson. If I run the app it's the same also. Now if I try to modify the forecolor or backcolor in the properties window they go right back to their defaults that I set (crimson, cyan) and then they also show up that way when I run my app. How do I get the controls to show up correctly in the designer and at run time?

The problem exists because UseVisualStyleBackColor is automatically set to true and you can't override it. If you change it to false, you'll notice that your button will work correctly.
One option is to override OnControlAdded of the button like this:
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
UseVisualStyleBackColor = false;
}
First time in the designer, the color won't show, but when you run the application it will work correctly.

I suggest you bind fore and back colors to, for example, application settings (Or settings class specific to your controls). Standard button and bind in designer, or use your own descendant and bind in code. In this case you will have consistent color scheme, and, more important, you can change it without recompilation.
public class CustomButton : Button
{
public CustomButton
{
InitializeComponent();
if (!DesignMode)
{
DataBindings.Add(new Binding("ForeColor", Settings.Default, "ButtonForeColor", true, DataSourceUpdateMode.Never));
DataBindings.Add(new Binding("BackColor", Settings.Default, "ButtonBackColor", true, DataSourceUpdateMode.Never));
}
}
// ...

Related

Style WindowsForms Project

I want to style my forms and some controls on my project, e.g. dataGridView.
I know, I can make a method like this an set it for every dataGridView.
public static void StyleDataGridView(DataGridView dg)
{
dg.BorderStyle = BorderStyle.FixedSingle;
dg.RowHeadersVisible = false;
....
}
My question: is there a possibility to do such style code only once in my project? How?
First step with userControl worked very well.
But how to handle the Click, DoubleClick and the CellMouseDown Event?
My code so far:
public partial class ucGridView : UserControl
{
public object DataSource
{
get { return dataGridView.DataSource; }
set { dataGridView.DataSource = value; }
}
public ucGridView()
{
InitializeComponent();
}
}

How do I retrieve the changed size of the DevExpress GridLookupEdit?

I have a DevExpress GridLookupEdit.
I am able to change the popup's default size to whatever I want via:
theGrid.Properties.PopupFormSize = New Size(mywidth, myHeight)
However, I want to save the height/width for each user.
So I run the winform's program, click it, resize the window and then close the popup'd up control.
Then the CloseUp event fires. I check theGrid.Properties.PopupFormSize and the height and width are the same as my default values.
How do I get the resized values?
I am using DevExpress 13.2
GridLookupEdit uses PopupGridLookUpEditForm object to show popup contents and store it in PopupForm property. But size of this form is not equal to size that you can set through GridLookupEdit.Properties.PopupFormSize property. This form has an EmbeddedControl property and when you are changing GridLookupEdit.Properties.PopupFormSize property, you actually changing the size of this embedded control. So, if you want to save size for each user, you need to save size of this control.
Unfortunately GridLookupEdit.PopupForm property and PopupGridLookUpEditForm.EmbeddedControl property are protected. PopupGridLookUpEditForm.EmbeddedControl actually is GridControl object. For DevExpress 14.1 you can get this object through GridLookupEdit.Properties.View.GridControl property.
So in DevExpress 14.1 GridLookupEdit.Properties.View.GridControl.Size property is what you are looking for.
But if you cannot get GridControlobject in your version then you can use reflection or create descendants.
Here example for reflection:
var popupFormProperty = theGrid.GetType().GetProperty("PopupForm", BindingFlags.NonPublic | BindingFlags.Instance, null, typeof(PopupGridLookUpEditForm), new Type[0], null);
var form = popupFormProperty.GetValue(theGrid);
var embeddedControlProperty = form.GetType().GetProperty("EmbeddedControl", BindingFlags.NonPublic | BindingFlags.Instance);
var embeddedControl = (Control)embeddedControlProperty.GetValue(form);//the size of this control is what you are looking for<
Another way is to create custom GridLookUp editor. According to documentation you need to create Custom Editor Class and Custom Repository Item Class, for example:
[UserRepositoryItem("RegisterCustomGridLookUpEdit")]
public class RepositoryItemCustomGridLookUpEdit : RepositoryItemGridLookUpEdit
{
static RepositoryItemCustomGridLookUpEdit() { RegisterCustomGridLookUpEdit(); }
static public void RegisterCustomGridLookUpEdit()
{
EditorRegistrationInfo.Default.Editors.Add(
new EditorClassInfo(CustomGridLookUpEditName,
typeof(CustomGridLookUpEdit), typeof(RepositoryItemCustomGridLookUpEdit),
typeof(GridLookUpEditBaseViewInfo), new ButtonEditPainter(), true, null));
}
public const string CustomGridLookUpEditName = "CustomGridLookUpEdit";
public override string EditorTypeName { get { return CustomGridLookUpEditName; } }
}
public class CustomGridLookUpEdit : GridLookUpEdit
{
static CustomGridLookUpEdit() { RepositoryItemCustomGridLookUpEdit.RegisterCustomGridLookUpEdit(); }
public override string EditorTypeName { get { return RepositoryItemCustomGridLookUpEdit.CustomGridLookUpEditName; } }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public new RepositoryItemCustomGridLookUpEdit Properties
{
get { return base.Properties as RepositoryItemCustomGridLookUpEdit; }
}
protected override PopupBaseForm CreatePopupForm() { return new CustomPopupGridLookUpEditForm(this); }
protected new CustomPopupGridLookUpEditForm PopupForm { get { return (CustomPopupGridLookUpEditForm)base.PopupForm; } }
public Size PopupFormSize { get { return PopupForm.PopupFormSize; } }
}
public class CustomPopupGridLookUpEditForm : PopupGridLookUpEditForm
{
public CustomPopupGridLookUpEditForm(CustomGridLookUpEdit ownerEdit) : base(ownerEdit) { }
public Size PopupFormSize { get { return EmbeddedControl.Size; } }
}
If you add this CustomGridLookUpEdit to you project then you can use its PopupFormSize property to get the required size.

override the super class methods in wpf Window

I wanna make a customized window base. So I made a custom window which inherits from Window.
For example:
public class MyWindowBase : Window
{
...
...
}
I wanna override the different Brushes of the super class Window for my own purpose.
In my previous experience, to override methods/properties with no abstract or virtual in the super class need the key word "new".
For example:
public new void DoSomething() { ........ base.DoSomething() ....... }
public new string SomeText { get { ... } set {......} }
It works in my previous work.
However, in this time of dealing with WPF Window, it doesn't work.
I tried to override the different Brushes of the super class Window as follows:
public new Brush BorderBrush
{
get { ... }
set { myBorderBrush = value; base.BorderBrush = null }
}
public new Brush Background
{
get { ... }
set { myBackground = value; base.Backgound = null; }
}
.....
.....
.....
I tried the change the value of the above Brushes in MyWindowBase, it just change the value of the super class Window, it doesn't change the value of myBorderBrush and myBackground.
So, how could I override the methods and properties of the super class Window?
Actually, I want to override the base background so that it will be null or transparent forever, but the changed value will be applied on my own custom Background.
Thank you very much!
If you only want to set the value, then you can set it using
this.BorderBrush = Brushes.Blue;
this.Background = Brushes.Red;
If you wish to overwrite the Property Metadata (for things like default value, property changed logic, or validation), you can use OverrideMetadata
Window.BackgroundProperty.OverrideMetadata(
typeof(MyWindowBase), myPropertyMetadata);
If you simply want to add some logic on Changed, you can use a DependencyPropertyDescriptor
var dpd = DependencyPropertyDescriptor.FromProperty(
Window.BackgroundProperty, typeof(Window));
dpd.AddValueChanged(this.Value, new EventHandler(BackgroundChanged));
private void BackgroundChanged(object sender, EventArgs e)
{
//do the code here
}
And if you're looking to override a Method, and not a Property, then you can use the override keyword
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
}

How to make CheckBox focus border appear when calling CheckBox.Focus()?

When the user tabs into a CheckBox to give it focus, a dotted border appears around the CheckBox to indicate that it has focus.
When the CheckBox gets focused by code calling myCheckBox.Focus(), no such indicator appears (even though pressing the space bar toggles the state).
How can I make the CheckBox focus border appear when I have programmatically focused the CheckBox?
The border is intentionally only shown if you are navigating by the keyboard (Tab key). The MSDN page on this topic has further details:
Focus visual styles act only when the
focus action was initiated by the
keyboard. Any mouse action or
programmatic focus change disables the
mode for focus visual styles.
If you want to show a border, you could use a Trigger on the IsFocused- Property to do some visual changes (although you can't set the border with this) or if you actually want a border, you would have to create your own ControlTemplate.
There is also a thread here on SO on a somewhat related topic where the suggestion is to simulate a key press, but I would suggest not to use this solution for your problem.
By editing the KeyboardNavigationEx file from ControlzEx I managed to solve the issue (full credit goes, as always, to punker76).
Just call the KeyboardHelper.Focus method passing the UIElement that shoud be focused (e.g. KeyboardHelper.Focus(myCheckBox))
Here's the KeyboardHelper class:
public sealed class KeyboardHelper
{
private static KeyboardHelper _Instance;
private readonly PropertyInfo _AlwaysShowFocusVisual;
private readonly MethodInfo _ShowFocusVisual;
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static KeyboardHelper()
{
}
private KeyboardHelper()
{
var type = typeof(KeyboardNavigation);
_AlwaysShowFocusVisual = type.GetProperty("AlwaysShowFocusVisual", BindingFlags.NonPublic | BindingFlags.Static);
_ShowFocusVisual = type.GetMethod("ShowFocusVisual", BindingFlags.NonPublic | BindingFlags.Static);
}
internal static KeyboardHelper Instance => _Instance ?? (_Instance = new KeyboardHelper());
internal void ShowFocusVisualInternal()
{
_ShowFocusVisual.Invoke(null, null);
}
internal bool AlwaysShowFocusVisualInternal
{
get { return (bool)_AlwaysShowFocusVisual.GetValue(null, null); }
set { _AlwaysShowFocusVisual.SetValue(null, value, null); }
}
public static void Focus(UIElement element)
{
element?.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
var keybHack = KeyboardHelper.Instance;
var oldValue = keybHack.AlwaysShowFocusVisualInternal;
keybHack.AlwaysShowFocusVisualInternal = true;
try
{
Keyboard.Focus(element);
keybHack.ShowFocusVisualInternal();
}
finally
{
keybHack.AlwaysShowFocusVisualInternal = oldValue;
}
}));
}
}
'initially set chkCheckBox.Appearance = 1
'on Got Focus set appearance = 0 - Flat
Private Sub chkCheckBox_GotFocus()
chkCheckBox.Appearance = 0
End Sub
'on Lost Focus set appearance = 1 - 3D
Private Sub chkCheckBox_LostFocus()
chkCheckBox.Appearance = 1
End Sub

WPF: reverting brush to default/original

I'm a complete newbie at WPF.
At the moment I'm making a usercontrol for form elements called "LabeledTextbox" which contains a label, a textbox and a textblock for errormessages.
When the using code adds an errormessage, I want to put the border of the textbox in red. But, when the errormessage gets removed, I'd like to turn back to the default bordercolor of the textbox.
I feel there must be a very easy way to do this.
My code:
(in public partial class LabeledTextbox : UserControl)
public string ErrorMessage
{
set
{
if (string.IsNullOrEmpty(value))
{
_textbox.BorderBrush = Brushes.Black; //How do I revert to the original color in the most elegant way?
}
else
{
_textbox.BorderBrush = Brushes.Red;
}
_errorMessage.Text = value;
}
}
You could use
_textBox.ClearValue(TextBox.BorderBrushProperty);
That will remove the directly assigned value and go back to the value defined by the style or template.
You can grab the default colours from the class SystemColors
Here is the list of all system colours:
http://msdn.microsoft.com/de-de/library/system.windows.systemcolors.aspx
Default background colour of the client area:
_textbox.Background = SystemColors.WindowBrush;
Default text colour inside the client area:
_textbox.SystemColors.WindowTextBrush
I may be late to the party, but for future readers, you can also use Button.BackgroundProperty.DefaultMetadata.DefaultValue for this purpose. This is especially useful when you're using a Converter where you need to return a value and therefore cannot use ClearValue() call.
Does this work? Setting it to black is better than using the ClearValue method
public string ErrorMessage
{
set
{
if (string.IsNullOrEmpty(value))
{
_textbox.Background = Brushes.Black;
}
else
{
_textbox.Background = Brushes.Red;
}
_errorMessage.Text = value;
}
}
Just store the default settings. Here a code excample.
System.Windows.Media.Brush save;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Store the default background
save = testButton.Background;
}
private void ChangeBackground(){
testButton.Background = Brushes.Red;
}
private void restoreDefaultBackground(){
//Restore default Backgroundcolor
testButton.Background = save;
}

Resources