Set display style for all ToolStripItems - c#

I am attempting to create a toolstrip class that inherits from the system.windows.forms.toolstrip class but specifies the styling to make consistent across our applications. The individual buttons that get added to the toolstrip have a displaystyle property that specify if you want to display an imageonly, textonly, or both. Is there a way I can specify the displaystyle for all buttons to be used in my toolstrip? I'd like to set it in my toolstrip class and have it applied across all applications rather than having to set this in every application.

Create a WindowsFormsControlLibrary project in your solution (for example "ConsistentControls"). Define a class (for example "ConsistentToolStripButton"). Define its capabilities like this.
using System;
using System.Windows.Forms;
namespace ConsistentControls
{
public class ConsistentToolStripButton : ToolStripButton
{
public override System.Windows.Forms.ToolStripItemDisplayStyle DisplayStyle
{
get
{
return base.DisplayStyle;
}
set
{
}
}
public ConsistentToolStripButton()
{
base.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
}
}
}
Now you can use this class in, for example "WindowsFormsApplication1", "WindowsFormsApplication2", "WindowsFormsApplication3" and so on...
Here is a screenshot of Design-Time development

Related

Pass properties of parent control to children controls

I am developing a set of custom controls for a specific application. I want to define properties which is universal over the set of controls for appearance purposes, for argument's sake let's make it CustomCtrl.AccentColor
I want to define that same property for my Windows form i.e. Form1.AccentColor and when I change it, all the custom controls' AccentColor should change, exactly like when I change the ForeColor of my form, all labels' and buttons' etc ForeColor changes with it.
Is it at all possible to do this or do I have to settle for the effort of looping through all custom controls and changing it one-by-one?
Short Answer
Since you can have a common base class for all your controls as you mentioned in comments, as an option you can create a base class and then add some properties with behavior like ambient properties (like Font) to the base control class.
Detailed Answer
An ambient property is a property on a control that, if not set, is retrieved from the parent control.
In our implementation, we get the value from parent Form using FindForm method. So in the implementation, when getting the property value, we check if the value equals to default value and if the parent from has the same property, we return the property value of the parent form, otherwise we return the property value of the control itself.
After adding XXXX property, in this scenario we also should implement ShouldSerializeXXXX and ResetXXXX methods to let the designer when serialize the property and how to reset value when you right click on property and choose reset.
MyBaseControl
using System.Drawing;
using System.Windows.Forms;
public class MyBaseControl : Control
{
public MyBaseControl()
{
accentColor = Color.Empty;
}
private Color accentColor;
public Color AccentColor
{
get
{
if (accentColor == Color.Empty && ParentFormHasAccentColor())
return GetParentFormAccentColor();
return accentColor;
}
set
{
if (accentColor != value)
accentColor = value;
}
}
private bool ParentFormHasAccentColor()
{
return this.FindForm() != null &&
this.FindForm().GetType().GetProperty("AccentColor") != null;
}
private Color GetParentFormAccentColor()
{
if (ParentFormHasAccentColor())
return (Color)this.FindForm().GetType()
.GetProperty("AccentColor").GetValue(this.FindForm());
else
return Color.Red;
}
private bool ShouldSerializeAccentColor()
{
return this.AccentColor != GetParentFormAccentColor();
}
private void ResetAccentColor()
{
this.AccentColor = GetParentFormAccentColor();
}
}
MyBaseForm
public class BaseForm : Form
{
[DefaultValue("Red")]
public Color AccentColor { get; set; }
public BaseForm()
{
this.AccentColor = Color.Red;
}
}
Form1
public partial class Form1 : BaseForm
{
public Form1()
{
InitializeComponent();
}
}
i think you can create inherited class from Control class and define your common properties on there then inheriting your custom controls from that class and use parent property to access container (like Form) and get property value from it

Expose a Control of a Master Page via Interface

I have a simple interface like this:
interface IToolbarMaster {
ToolBar Toolbar { get; }
}
I added this Interface to my MasterPage and moved the field declaration of the Toolbar-Control to the Code Behind File:
public partial class Layout : ctrls.MasterPage, IToolbarMaster {
public global::Some.Web.Controls.ToolBar Toolbar;
(...)
}
My pages need to access this Toolbar Control via the Interface (we have a .FindMaster<IToolbarMaster>() Method) - but the code says, Layout doesn't implement IToolbarMaster
I could implement a property like
public ToolBar ToolBar { get { return this.Toolbar; } } // Different name spelling
But this looks really odd in my opinion.
I ran into a similar issue in VB using an auto property with a default value.
Public Property MessagePlaceHolder() As PlaceHolder = Me.phMessage
Apparently that doesn't work. I had to create the property the traditional way.
Public ReadOnly Property MessagePlaceHolder() As PlaceHolder
Get
Return Me.phMessage
End Get
End Property
Wow, I already got the answer, I was very close.
I tried this
public global::Some.Web.Controls.ToolBar Toolbar { get; }
but it didn't work. But as I added the setter everything was fine:
public global::Some.Web.Controls.ToolBar Toolbar { get; set; }
I'm leaving this for future reference, if anyone has this problem too.

How can I add a nested design-time property to a user control?

I have a user control that contains a number of panel controls. The user control has logic to set the visibility of each panel, based on the values of some variables contained in the user control.
I would like to enhance this functionality by adding the following enumeration:
public enum Visibility
{
Default,
Always,
Never
}
where Default would use the current logic to set the panel's visibility, but Always would (obviously) make the panel always visible, and Never would always hide the panel.
I would also like to add a "nested" design-time property named something like PanelVisiblity that the developer could expand, and see the panel names listed below, and allow them to assign a value from the Visibility enumeration for each.
If I add properties like this:
public partial class MyControl : UserControl
{
public Visibility ActivePanel { get; set; }
public Visibility CodePanel { get; set; }
}
the ActivePanel and CodePanel properties appear in the Properties window in Visual Studio, and I can set them to one of the three values in the enum. However, when I refactored my code to try to create a nested property like this:
public partial class MyControl : UserControl
{
public class PanelVisibility
{
public enum Visibility
{
Default,
Always,
Never
}
public Visibility ActivePanel { get; set; }
public Visibility CodePanel { get; set; }
}
}
I do not get an expandable PanelVisiblity property, I get a disabled Visiblity property, where the value is the namespace of class, plus 'PanelVisibility'.
I have Googled a number of variations in phrasing this search, but have not been able to find anything like what I'm looking for.
Any direction would be greatly appreciated.
It seems that you are looking for the same functionality as a DockPanel offers.
I'd suggest you that instead of re-inventing the wheel you should use one the available implementations to you such as :
http://msdn.microsoft.com/en-us/library/system.windows.controls.dockpanel.aspx
http://dockpanel2012.codeplex.com/
https://github.com/dockpanelsuite/dockpanelsuite

Custom Windows Control library in C#

How can I implement small task features in my own custom windows control library like below?
You need to create your own designer for your control. Start that by adding a reference to System.Design. A sample control could look like this:
using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms.Design;
[Designer(typeof(MyControlDesigner))]
public class MyControl : Control {
public bool Prop { get; set; }
}
Note the [Designer] attribute, it sets the custom control designer. To get yours started, derive your own designer from ControlDesigner. Override the ActionLists property to create the task list for the designer:
internal class MyControlDesigner : ControlDesigner {
private DesignerActionListCollection actionLists;
public override DesignerActionListCollection ActionLists {
get {
if (actionLists == null) {
actionLists = new DesignerActionListCollection();
actionLists.Add(new MyActionListItem(this));
}
return actionLists;
}
}
}
Now you need to create your custom ActionListItem, that could look like this:
internal class MyActionListItem : DesignerActionList {
public MyActionListItem(ControlDesigner owner)
: base(owner.Component) {
}
public override DesignerActionItemCollection GetSortedActionItems() {
var items = new DesignerActionItemCollection();
items.Add(new DesignerActionTextItem("Hello world", "Category1"));
items.Add(new DesignerActionPropertyItem("Checked", "Sample checked item"));
return items;
}
public bool Checked {
get { return ((MyControl)base.Component).Prop; }
set { ((MyControl)base.Component).Prop = value; }
}
}
Building the list in the GetSortedActionItems method is the key to creating your own task item panel.
That's the happy version. I should note that I crashed Visual Studio to the desktop three times while working on this example code. VS2008 is not resilient to unhandled exceptions in the custom designer code. Save often. Debugging design time code requires starting another instance of VS that can stop the debugger on the design-time exceptions.
It's called a "Smart Tag". You can find a quick example of it here:
Adding Smart Tags to Windows Forms Controls
Source: How can I implement "small task features" in my own custom windows control library like below? - CodeProject

C# how to implement databinding without Control?

Is there a simple way to implement databinding when neither of both classes is of type Control?
In my case, I would like to bind a variable to a property of a custom ToolStripButton.
EDIT for clarification: when binding to a Control, I can use Control's DataBindings collection. However, I am searching for a way to bind properties regardless of the source and target Type.
EDIT: using winforms
You can probably do this by using Truss.
Truss provides WPF-style databinding for any class that implements INotifyPropertyChanged. It gives you a bit more flexibility in this, since it doesn't restrict the classes to being derived from a specific base class.
I use this Implemetation of IBindableComponent on the ToolStripButton, found here. The BindableToolStripButton allows you to use Databinding like with a normal Control.
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)]
public class BindableToolStripButton : ToolStripButton, IBindableComponent
{
public BindableToolStripButton()
: base() { }
public BindableToolStripButton(String text)
: base(text) { }
public BindableToolStripButton(System.Drawing.Image image)
: base(image) { }
public BindableToolStripButton(String text, System.Drawing.Image image)
: base(text, image) { }
public BindableToolStripButton(String text, System.Drawing.Image image, EventHandler onClick)
: base(text, image, onClick) { }
public BindableToolStripButton(String text, System.Drawing.Image image, EventHandler onClick, String name)
: base(text, image, onClick, name) { }
#region IBindableComponent Members
private BindingContext bindingContext;
private ControlBindingsCollection dataBindings;
[Browsable(false)]
public BindingContext BindingContext
{
get
{
if (bindingContext == null)
{
bindingContext = new BindingContext();
}
return bindingContext;
}
set
{
bindingContext = value;
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ControlBindingsCollection DataBindings
{
get
{
if (dataBindings == null)
{
dataBindings = new ControlBindingsCollection(this);
}
return dataBindings;
}
}
#endregion
}
Assuming you have a class MyClass implementing INotifyPropertyChanged, use it just like you would when binding to a control property:
bindableToolStripButton1.DataBindings.Add("Enabled", myClass1, "MyBooleanProperty");
Use dependency properties (your property in your ToolStripButton should be) and create a property for your variable in your other class and create a binding and set it to the property of your ToolstripButton.
I guess that's about the easiest way to do it.
EDIT: That's only for WPF...
Else implement INotifyPropertyChanged and when your variable changes, it should automatically change in your ToolStripButton.
For similar behaviour like Controls being bound to object properties, for any Type you can implement the same interfaces.
Based on that thought, you can subclass ToolStripButton (or desired Type to have bindings) and implement IBindableComponent for it. This works for all kinds of source and target Types as long as they're not sealed. For example, your tool strip button:
public class BindableToolStripButton : ToolStripButton, IBindableComponent {
//...
This will cause the BindableToolStripButton to have its own .DataBindings property whereas the base ToolStripButton class doesn't have such a propery.
You would need to follow through on filling out implementation details using examples seen here from Microsoft for ISite, IBindableComponent, IComponent and any inherited interfaces.
Then you would add Binding instances to any instance of BindableToolStripButton.
(Note: I only have fragements so will make my first community wiki post - and we'll see how that goes... )
I written some basic databinding stuff through reflection. It works on any object and doesn't need to implement something special (no INotifyPropertyChanged, it just works) it is part of my editor at http://github.com/filipkunc/opengl-editor-cocoa look at HotChocolate/Bindings (like re-implementation of Cocoa KVC, KVO into .NET) folder. You can see it in action in HotChocolateTest project.
There is another quick and simple solution which consists in creating properties in the Form, and bind them:
public MyForm : Form
{
...
public bool CanDelete
{
get { return deleteToolStripButton.Enabled; }
set { deleteToolStripButton.Enabled = value; }
}
public MyForm()
{
...
this.DataBindings.Add("CanDelete", this.MyModel, "DeleteAllowed",
false, DataSourceUpdateMode.Never);
...
}
}
Assuming that MyModel contains a DeleteAllowed property which notifies its changes.

Categories