We've got custom PopupContainerEdit that inherits from DevExpress'es PopupContainerEdit. One of our custom features is another dropdown button (EditorButton with kind = ButtonPredefines.Glyph) that acts like the default one except, it opens different PopupContainerControl. Everything works as intended except button's style coloring. The button acts like default button - that means it doesn't support state coloring (checked/unchecked) when dropdown is visible/hidden. I couldn't find any custom draw event/method for EditorButton.
Is it possible to achieve such behaviour? If so, how?
#edit
Simple example of the above situation.
Default PopupContainerEdit looks like image A. When you click on the
button (triangle like), dropdown shows and button goes into checked
state.
Our PopupContainerEdit (that inherits from default) looks like
B.
C, D is coloring example when you hover the button.
E is checked state coloring for default button (it works like that by
DevExpress'es design).
F is our button behaviour - acts like normal button.
G is what we want - checked state coloring for our button
Our approach to create custom button:
string TheToolTipText = "The text";
string OurButtonTag = "TheButton";
Image TheIcon = new Image(); // just example ...
EditorButton customButton = new EditorButton();
customButton.Width = 16;
customButton.Image = TheIcon;
customButton.ToolTip = TheToolTipText;
customButton.Tag = OurButtonTag;
customButton.Kind = ButtonPredefines.Glyph;
this.Properties.Buttons.Add(customButton);
To be honest there's nothing more to show. We're not aware of any custom Draw event or similar things.
There are two properties in RepositoryItemPopupContainerEdit that are responsible for this behavior. Fisrt one is RepositoryItemPopupBase.ActionButtonIndex property. It's value specifying which editor button will open the editor's dropdown window. The second one is RepositoryItemPopupContainerEdit.PopupControl which sets the control to display in the popup window. So, by manipulating with this two properties, you can achieve the desired behavior.
Here is example:
0. RepositoryItemPopupContainerEdit descendant
Because you need to show two different PopupContainerControl
you can create additional properties for each of your controls in your custom RepositoryItem.
public class RepositoryItemCustomEdit1 : RepositoryItemPopupContainerEdit
{
#region Some default stuff for custom repository item (constructors, registration, etc).
static RepositoryItemCustomEdit1() { RegisterCustomEdit1(); }
public const string CustomEditName = "CustomEdit1";
public RepositoryItemCustomEdit1() { }
public override string EditorTypeName { get { return CustomEditName; } }
public static void RegisterCustomEdit1()
{
Image img = null;
EditorRegistrationInfo.Default.Editors.Add(new EditorClassInfo(
CustomEditName,
typeof(CustomEdit1),
typeof(RepositoryItemCustomEdit1),
//For v13.2 you need to use custom ViewInfo class. So, here is CustomEdit1ViewInfo.
//For v15.1 you can use the base PopupContainerEditViewInfo.
typeof(CustomEdit1ViewInfo),
new ButtonEditPainter(),
true,
img));
}
#endregion
#region Hide base PopupContainerControl properties in designer.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override PopupContainerControl PopupControl
{
get { return base.PopupControl; }
set { base.PopupControl = value; }
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override int ActionButtonIndex
{
get { return base.ActionButtonIndex; }
set { base.ActionButtonIndex = value; }
}
#region
#region First PopupContainerControl properties
public int DefaultActionButtonIndex { get; set; }
public PopupContainerControl DefaultPopupControl { get; set; }
#endregion
#region Another PopupContainerControl properties
public int DifferentActionButtonIndex { get; set; }
public PopupContainerControl DifferentPopupControl { get; set; }
#endregion
public override void Assign(RepositoryItem item)
{
BeginUpdate();
try
{
base.Assign(item);
RepositoryItemCustomEdit1 source = item as RepositoryItemCustomEdit1;
if (source == null) return;
DefaultActionButtonIndex = source.DefaultActionButtonIndex;
DefaultPopupControl = source.DefaultPopupControl;
DifferentPopupControl = source.DifferentPopupControl;
DifferentActionButtonIndex = source.DifferentActionButtonIndex;
}
finally
{
EndUpdate();
}
}
}
You can see new properties in your designer:
1. PopupContainerEdit descendant
Now you can use this properties in your custom Edit class.
public class CustomEdit1 : PopupContainerEdit
{
#region Some default stuff for custom edit (constructors, registration, etc).
static CustomEdit1() { RepositoryItemCustomEdit1.RegisterCustomEdit1(); }
public CustomEdit1() { }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public new RepositoryItemCustomEdit1 Properties { get { return base.Properties as RepositoryItemCustomEdit1; } }
public override string EditorTypeName { get { return RepositoryItemCustomEdit1.CustomEditName; } }
#endregion
protected override bool IsActionButton(EditorButtonObjectInfoArgs buttonInfo)
{
int buttonIndex = Properties.Buttons.IndexOf(buttonInfo.Button);
if (buttonIndex == Properties.DefaultActionButtonIndex ||
buttonIndex == Properties.DifferentActionButtonIndex)
{
//Set the Properties.ActionButtonIndex value according to which button is pressed:
Properties.ActionButtonIndex = buttonIndex;
//Set the Properties.PopupControl according to which button is pressed:
if (buttonIndex == Properties.DefaultActionButtonIndex)
Properties.PopupControl = Properties.DefaultPopupControl;
else
Properties.PopupControl = Properties.DifferentPopupControl;
return true;
}
return false;
}
}
2. PopupContainerEditViewInfo descendant
For v13.2 you need to use custom ViewInfo class for your editor:
public class CustomEdit1ViewInfo : PopupContainerEditViewInfo
{
public CustomEdit1ViewInfo(RepositoryItem item) : base(item) { }
public new RepositoryItemPopupBase Item { get { return base.Item as RepositoryItemCustomEdit1; } }
//Show the pressed state when button is pressed or when popup is open.
protected override bool IsButtonPressed(EditorButtonObjectInfoArgs info)
{
var hitObject = PressedInfo.HitObject as EditorButtonObjectInfoArgs;
return
(hitObject != null && hitObject.Button == info.Button) ||
(IsPopupOpen && Item.ActionButtonIndex == info.Button.Index);
}
}
Result
In the result you will get something like this:
and
Related
I have an ObservableCollection of MySearchFields, on a custom Form, lets say CustomForm I declare it as below:
private ObservableCollection<MySearchFields> _mySearchFields = new ObservableCollection<MySearchFields>();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Category("MyFrameWork")]
public ObservableCollection<MySearchFields> MySearchFields
{
get => _mySearchFields;
}
and then on my Main form where it inherits from CustomForm,
when I'm on the designer view and go to propertygrid window I select my ControlType To be ComboBox and then I select DataSource, ValueMember And Display Member. the issue is it does not set DataSource,ValueMember or DisplayMember.
why does this happen? am I missing something?
public class MySearchFields
{
public enum MyControlTypes
{
MyTextBox,
MyDateTimePicker,
MyLbComboBox
}
private MyControlTypes _myControlType = MyControlTypes.MyTextBox;
public MyControlTypes MyControlType
{
get => _myControlType;
set
{
_myControlType = value;
switch (_myControlType)
{
case MyControlTypes.MyTextBox:
{
MyControl = new TextBox();
break;
}
case MyControlTypes.MyLbComboBox:
{
MyControl = new MyLbComboBox();
break;
}
case MyControlTypes.MyDateTimePicker:
{
MyControl = new DateTimePicker();
break;
}
}
}
}
public Control MyControl { get; set; }
public MySearchFields()
{
MyControl = new Control();
}
}
Your error is that on your case switcher you insert new MyLBcombobox instead of just ComboBox.
try initializing public Control MyControl { get; set; } with the proper setters and getters, as well as a private variable the backs it up,
Furthermore just use the fullprop snippet of Visual studio
just write "fullprop" and the press 2 times TAB, swapping around => and {} is not that nice.
As the Form of System.Windows.Forms inherits from Control, I was wondering if there is a way to create a Custom Form and its Designer with some options (shortcuts) to create a title or somthings like that.
I tried this, but nothings happend, the Form I calles ManagedForm
[Designer(typeof(ManagedFormDesigner))]
public class ManagedForm : Form{
//code here
}
[PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
public class ManagedFormDesigner : ControlDesigner {
private DesignerActionListCollection actionLists;
public override DesignerActionListCollection ActionLists {
get {
if (actionLists == null) {
actionLists = new DesignerActionListCollection();
actionLists.Add(new ManagedFormDesignerActionList(this.Component));
}
return actionLists;
}
}
}
public class ManagedFormDesignerActionList : DesignerActionList {
private ManagedForm managedForm = null;
private DesignerActionUIService designerActionUISvc = null;
public ManagedFormDesignerActionList(IComponent component) : base(component) {
this.managedForm = component as ManagedForm;
this.designerActionUISvc =
GetService(typeof(DesignerActionUIService))
as DesignerActionUIService;
}
public override DesignerActionItemCollection GetSortedActionItems() {
DesignerActionItemCollection items = new DesignerActionItemCollection();
items.Add(new DesignerActionMethodItem(this, "CreateTitle", "Create Title", "Appearence", true));
return items;
}
public void CreateTitle() {
Panel pTitulo = new Panel();
pTitulo.Size= new Size(100,25);
pTitulo.Dock = DockStyle.Top;
(this.Component as ManagedForm).Controls.Add(pTitulo);
}
}
Action list are show when you click on the little arrow on the control inside a form (or on a component on the bottom of the designer if the object is a component).
Other things you can do is to manage verbs.
Verbs Handling is implemented on the ControlDesigner class (ManagedFormDesigner in your case).
You can see verbs clicking right mouse button or on the bottom of the properties (i.e. TabControl ha 2 verbs, add tab and remove tab).
You can implement verbs adding to ControlDesigner (or ComponentDesigner) class something like this
private DesignerVerbCollection _verbs;
public override DesignerVerbCollection Verbs
{
get
{
if (_verbs == null)
{
_verbs = new DesignerVerbCollection();
_verbs.Add(new DesignerVerb("Create Title", new EventHandler(MyCreateTitleHandler)));
}
return _verbs;
}
}
private void MyCreateTitleHandler(object sender, EventArgs e)
{
// Do here something but take care to show things via IUIService service
IUIService uiService = GetService(typeof(IUIService)) as IUIService;
}
I have my Control.When I change the properties of the control. I get this:
this.myLabel1.BorderShadow = true;
this.myLabel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
And I need to get this:
this.myLabel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.myLabel1.BorderShadow = true;
How to do so is done automatically in Form.Desinger.cs ?
If you say Why?
private bool BorderShadow_ = false;
public bool BorderShadow
{
get
{
return BorderShadow_;
}
set
{
if (Border_Style_ == BorderStyle.FixedSingle)
{
BorderShadow_ = value;
}
else
{
throw new ArgumentOutOfRangeException("BorderShadow", "BorderShadow can be true if BorderStyle=FixedSingle");
}
}
}
You could look into the ISupportInitialize interface. It allows you to skip the validity check when initializing your controls. For example (adapted from one of my projects):
public class MyControl : Control, ISupportInitialize
{
private bool _created = true;
public void BeginInit()
{
_created = false;
}
public void EndInit()
{
_created = true;
//check all your properties here too
}
private bool BorderShadow_ = false;
public bool BorderShadow
{
get
{
return BorderShadow_;
}
set
{
BorderShadow_ = value;
if (_created && Border_Style_ != BorderStyle.FixedSingle)
throw new ArgumentOutOfRangeException();
}
}
}
If I remember correctly, the VS designer will automatically add calls to BeginInit and EndInit for you as well.
I think they will appears in the same order as they are defined. So you can override with new old setting:
public new BorderStyle BorderStyle
{
get {return base.BorderStyle;}
set {base.BorderStyle = value;}
}
and then declare your BorderShadow setting.
The designer will always order the properties alphabetically and this can't be changed.
The sense of a property is that it is side effect free and that it can be changed at any time in any order. This means that if you have multiple properties which representing some kind of complex state and not all combinations are making sense, this error should not be reported while switching the property itself.
So to accomplish these problems you have two possibilities:
Like #Andrew already mentioned implement ISupportInitialize and take care if you are within this state.
Within the property setter call a method that checks if all settings currently made are making sense and perform the desired action only in this case:
public class MyControl : Control
{
private bool _BorderShadow;
private BorderStyle _BorderStyle;
public bool BorderShadow
{
get { return _BorderShadow; }
set
{
if(_BorderShadow != value)
{
_BordeShadow = value;
ApplyBorderShadowIfNeeded();
}
}
}
public BorderStyle BorderStyle
{
get { return _BorderStyle; }
set
{
if(_BorderStyle != value)
{
_BorderStyle = value;
ApplyBorderShadowIfNeeded();
}
}
}
private void ApplyBorderShadowIfNeeded()
{
if(_BorderStyle == BorderStyle.FixedSingle
&& _BorderShadow)
{
// ToDo: Apply the shadow to the border.
}
}
}
I have a list of classes, but different children have different properties that need to be displayed.
What I want to achieve is to have a listbox-type control in the gui which enables each child to display it's properties the way it wants to - so not using the same pre-defined columns for every class.
I envisage something like the transmission interface (below), where each class can paint it's own entry, showing some text, progress bar if relevant, etc.
How can this be achieved in C#?
Thanks for any help.
Let your list items implement an interface that provides everything needed for the display:
public interface IDisplayItem
{
event System.ComponentModel.ProgressChangedEventHandler ProgressChanged;
string Subject { get; }
string Description { get; }
// Provide everything you need for the display here
}
The transmission objects should not display themselves. You should not mix domain logic (business logic) and display logic.
Customized ListBox:
In order to do display listbox items your own way, you will have to derive your own listbox control from System.Windows.Forms.ListBox. Set the DrawMode property of your listbox to DrawMode.OwnerDrawFixed or DrawMode.OwnerDrawVariable (if the items are not of the same size) in the constructor. If you use OwnerDrawVariable then you will have to override OnMeasureItem as well, in order to tell the listbox the size of each item.
public class TransmissionListBox : ListBox
{
public TransmissionListBox()
{
this.DrawMode = DrawMode.OwnerDrawFixed;
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
e.DrawBackground();
if (e.Index >= 0 && e.Index < Items.Count) {
var displayItem = Items[e.Index] as IDisplayItem;
TextRenderer.DrawText(e.Graphics, displayItem.Subject, e.Font, ...);
e.Graphics.DrawIcon(...);
// and so on
}
e.DrawFocusRectangle();
}
}
You can let your original transmission class implement IDisplayItem or create a special class for this purpose. You can also have different types of objects in the list, as long as they implement the interface. The point is, that the display logic itself is in the control, the transmission class (or whatever class) only provides the information required.
Example:
Because of the ongoing discussion with Mark, I have decided to include a full example here. Let's define a model class:
public class Address : INotifyPropertyChanged
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
if (_Name != value) {
_Name = value;
OnPropertyChanged("Name");
}
}
}
private string _City;
public string City
{
get { return _City; }
set
{
if (_City != value) {
_City = value;
OnPropertyChanged("City");
OnPropertyChanged("CityZip");
}
}
}
private int? _Zip;
public int? Zip
{
get { return _Zip; }
set
{
if (_Zip != value) {
_Zip = value;
OnPropertyChanged("Zip");
OnPropertyChanged("CityZip");
}
}
}
public string CityZip { get { return Zip.ToString() + " " + City; } }
public override string ToString()
{
return Name + "," + CityZip;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Here is a custom ListBox:
public class AddressListBox : ListBox
{
public AddressListBox()
{
DrawMode = DrawMode.OwnerDrawFixed;
ItemHeight = 18;
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
const TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
if (e.Index >= 0) {
e.DrawBackground();
e.Graphics.DrawRectangle(Pens.Red, 2, e.Bounds.Y + 2, 14, 14); // Simulate an icon.
var textRect = e.Bounds;
textRect.X += 20;
textRect.Width -= 20;
string itemText = DesignMode ? "AddressListBox" : Items[e.Index].ToString();
TextRenderer.DrawText(e.Graphics, itemText, e.Font, textRect, e.ForeColor, flags);
e.DrawFocusRectangle();
}
}
}
On a form, we place this AddressListBox and a button. In the form, we place some initializing code and some button code, which changes our addresses. We do this in order to see, if our listbox is updated automatically:
public partial class frmAddress : Form
{
BindingList<Address> _addressBindingList;
public frmAddress()
{
InitializeComponent();
_addressBindingList = new BindingList<Address>();
_addressBindingList.Add(new Address { Name = "Müller" });
_addressBindingList.Add(new Address { Name = "Aebi" });
lstAddress.DataSource = _addressBindingList;
}
private void btnChangeCity_Click(object sender, EventArgs e)
{
_addressBindingList[0].City = "Zürich";
_addressBindingList[1].City = "Burgdorf";
}
}
When the button is clicked, the items in the AddressListBox are updated automatically. Note that only the DataSource of the listbox is defined. The DataMember and ValueMember remain empty.
yes, if you use WPF it is quite easy to do this. All you have to do is make a different DataTemplate for your different types.
MSDN for data templates
Dr. WPF for Items Control & Data Templates
I have a user-defined button, and it may have a Style property which I choose in properties window a value for it and depending on that value its Image and style will change.
How can I make this property to have some predefined and fixed values in a drop down list in properties window? and selecting a value causes running a method
-details:
this button may gets specified appearance such pause and play styles. so I made a class for styles:
// style of the button; pause, play, reset, etc
public abstract class ButtonStyle
{
public abstract Image GetImage();
}
// inherited classes of class ButtonStyle
public class PauseButtonStyle : ButtonStyle
{
public override Image GetImage()
{
return CustomButtonLibrary.Properties.Resources.PauseButton;
}
}
public class PlayButtonStyle : ButtonStyle
{
public override Image GetImage()
{
return CustomButtonLibrary.Properties.Resources.PlayButton;
}
}
And there is a method in the button for setting the specified style (pause,play,...):
public void SetStyle(ButtonStyle style)
{
button1.Image = style.GetImage();
}
Now how can I have a property for this custom button in properties window that this property has some default values like pause, play,etc and selecting it causes changing the button's style (with running SetStyle method)
I would make an enum and expose that as the Style property. Then, have a internal dictionary that keys off the enum value to choose the appropriate ButtonStyle object to pass to your SetStyle method.
I think all you need to do is inherit the Button class and add your Enum:
public class ButtonEx : Button
{
public enum ButtonStateStyles
{
None,
Pause,
Play,
}
private ButtonStateStyles _ButtonStateStyle = ButtonStateStyles.None;
public ButtonStateStyles ButtonStateStyle
{
get { return _ButtonStateStyle; }
set
{
_ButtonStateStyle = value;
switch (_ButtonStateStyle)
{
case ButtonStateStyles.Pause:
{
base.Image = new PauseButtonStyle().GetImage();
break;
}
case ButtonStateStyles.Play:
{
base.Image = new PlayButtonStyle().GetImage();
break;
}
default:
{
base.Image = null;
break;
}
}
}
}
}