Design-Time drag and drop - c#

I'm currently working of a project where my part is to design a Design Surface where the end user can add/remove/move controls at run-time.
I followed this tutorial "Hosting Windows Forms Designers, by Tim Dawson", and almost have implemented all the features I need.
Short story for those who don't want to read the tutorial : I implemented IDesignerHost, IContainer, ISelectionService, IToolboxService and some other interface, to create my design surface. I didn't use the System.ComponentModel.Design.DesignSurface already in the framework, mainly beacause I need a really custom design surface.
Question :
I want to allow user to drag & drop new Control from the IToolboxService to the IDesignerHost/IContainer. In this tutorial, you clic on a Control in the toolbox, the click on the design surface to add the control.
What i've found :
There is a built-in feature that
automagically does drag & drop from
IToolboxService to
System.ComponentModel.Design.DesignSurface but it is clearly not working if you implement IDesignerHost from nothing.
When you use the
Control.DoDragDrop(ToolboxItem)
method, to initiate a drag & drop :
IToolboxService.SerializeToolboxItem(ToolboxItem)
is called to serialize the item
IToolboxService.IsToolboxItem(object)
and
IToolboxService.IsSupported(object)
are called to evaluate if the
serialized ToolboxItem can be allowed
to be droped on the design surface
When you drop the control : IToolboxService.DeserializeToolboxItem(object serializedObject) is called by the design surface to deserialize the controldropped.
IToolboxService.SetCursor() is called to know if you define a custom cursor, or let the standard windows cursor.
Problem :
I implemented all mentionned above, in the "What i've found", but the drag & drop is buggy :
I drag, everything's fine, but when
hovering the design surface, my
cursor blink a little between
standard cursor and the
"DragDropEffects.Copy" style.
When I drop, nothing happens, and when my cursor leave the design surface (after I dropped), then the new Control is created and added where I dropped it.
Has anyone ever tried to do what I'm doing, and if so, how did you manage it ?
Is there anyone that has any pointer/link/good advices ?
Thank you =)

Is there anyone that has any
pointer/link/good advices?
Your issue seems to be addressed by the Microsoft Connect issue Mouse Events Consumed / Not Raised in 2.0 Designers. This issue is all but easy to grasp though, but apparently the upgrade from .NET Framework 1.1 (2003) to 2.0 (2006) implied a change in drag & drop behavior - given that the article you mentioned stems from 2003 this could well be related. Specifically you should scroll ahead to section Issue 2, citation:
You will now notice constant
flickering when dragging over the
form. This is partially caused by the
new drag-drop behavior in 2.0.
I'm unable to dig deeper into this right now myself but you might also be able to figure something from Customize Drag & Drop in the Designer, which addresses changed behavior regarding drag & drop between Visual Studio versions 2003 and 2005; quite likely this might be related and one of the accepted answers does in fact specifically reference the Microsoft Connect issue above, plus it offers more hints towards possible solutions too.

Me to worked on this questions for one day ago. This is my solution that found for my project like yours.
I drag, everything's fine, but when hovering the design surface, my cursor blink a little between standard cursor and the "DragDropEffects.Copy" style.
This is my toolboxservice.
class EasyAccordionToolboxService : AccordionControl, IToolboxService
{
EasyAccordionControlElement _SelectedElement;
public Control DesignPanel { get; set; }
public EasyAccordionToolboxService()
{
AddAccordions();
AllowItemSelection = true;
base.ElementClick += EasyAccordionToolboxService_ElementClick;
}
private void EasyAccordionToolboxService_ElementClick(object sender, ElementClickEventArgs e)
{
if (e.Element.Level == 1) this._SelectedElement = e.Element as EasyAccordionControlElement;
}
public ToolboxItem GetSelectedToolboxItem()
{
if(_SelectedElement != null)
{
var selectedToolboxItem = this._SelectedElement.ToolBoxItem;
this._SelectedElement = null;
return selectedToolboxItem;
}
else
{
return null;
}
}
public bool SetCursor()
{
if(this._SelectedElement == null)
{
this.DesignPanel.Cursor = Cursors.Default;
}
else
{
this.DesignPanel.Cursor = Cursors.Hand;
}
return true;
}
There are "DesignPanel" property and "SetCursor" methods. DesignPanel property is control referred to view of root designer.
When I drop, nothing happens, and when my cursor leave the design surface (after I dropped), then the new Control is created and added where I dropped it.
There is GetSelectedToolboxItem method in EasyAccordionToolBoxService implemented from IToolboxService. GetSelectedToolboxItem is your answer.
Finally,
designer = new EasyDesignSurface(propertyGrid);
var rootForm = (Form)designer.CreateComponent(typeof(Form));
rootForm.Name = "rootForm";
rootForm.Text = "BELGE";
rootForm.TopLevel = false;
rootForm.Size = new Size(600, 600);
designer.ComponentContainer.Add(rootForm);
var view = (Control)designer.View;
view.Dock = DockStyle.Fill;
designPanel.Controls.Add(view);
easyAccordionToolboxService1.DesignPanel = view;
designer.AddService(typeof(IToolboxService), easyAccordionToolboxService1);

Related

C# WPF - Custom Control drag and drop (Visual Studio style)

How do I make my Custom controls draggable and droppable on a grid let's say?
I want to drag a panel(custom control) and drop it somewhere on my screen, in the best case in a grid, for example how it's done in Visual Studio, you can grab the solution explorer let's say and drop it somewhere, but how exactly do I do that?
You need to build your project and then it will be automatically available in the Toolbox when you are in the XAML designer. Just like the common controls.
For Drag and Drop at runtime look and the official WPF documentation. Also I suggest you look at the GongSolutions.WPF.DragDrop library in GitHub it is open source so you can see how they implemented it if the functionality it provides does not do what you want.
I found this post with a very similar conclusion to this one. the difference being scale.
the following example will swap the parent container
int i = 0;
void swapLocations()
{
foreach(var formObject in objList) //objList == a list or array on all objects you want to move from one container to another
{
if (i % 2 == 0)
{
// catch current position
Point moveLocation = new Point(formObject.Location.X + formObject.Parent.Location.X,formObject.Location.Y + formObject.Parent.Location.Y);
// remove this object
formObject.Parent.Controls.Remove(formObject);
// add this object to the form
this.Controls.Add(formObject);
// set location
formObject.Location = moveLocation;
formObject.SendToBack();
}
else
{
formObject.BringToFront();
}
}
++i;
}

Make UserControl "slide out" from a side of a screen?

I'm using following code to inject view into Grid:
private void OnShowNotesRequested(UserControl view)
{
if (view == null) throw new NotSupportedException("View should not be null");
// Skip first GridRow - this is usually Toolbar
if (this.AssociatedObject.RowDefinitions.Count > 1)
{
view.SetValue(Grid.RowSpanProperty, this.AssociatedObject.RowDefinitions.Count - 1);
view.SetValue(Grid.RowProperty, 1);
}
view.SetValue(Grid.ColumnSpanProperty, this.AssociatedObject.ColumnDefinitions.Count == 0 ? 1 : this.AssociatedObject.ColumnDefinitions.Count);
view.Width = 500;
view.HorizontalAlignment = HorizontalAlignment.Right;
this.AssociatedObject.Children.Add(view);
}
Basically, I'm adding view as a child to the Grid. It docks to the right side.
I want to make it look like this view sliding out of right side and stops. I have no idea on how to approach it and what should I do to achieve this visual effect. Any pointers on what and where I need to add? Maybe link to similar effect?
I found some animations code here: http://forums.silverlight.net/t/82441.aspx
It makes sense, however when I hide my view - I completely remove it from visual tree like so: this.AssociatedObject.Children.Remove(view) Not sure how to "wait" and then remove it.
Take a look at Microsofts Expression Blend tool, its been created specifically to create these kind of visual effects.
What you are looking to do can be acheived with a story board and is pretty simple to do!
Essentially, once the storyboard has been created (a case of defining the starting position and the end position - according to time (or frames)) you can trigger the storyboard to play when a particular event is fired.
I know this is not a definitive answer however here are some tutorials to get you moving:
http://www.silverlightbuzz.com/2009/10/12/animating-with-storyboards-in-blend/
http://www.c-sharpcorner.com/uploadfile/mamta_m/creating-and-using-storyboards-in-blendsilverlight-part-i/
http://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0CE4QFjAD&url=http%3A%2F%2Fmsdn.microsoft.com%2Fen-us%2Flibrary%2Fcc295092.aspx&ei=NDRzT42uPNS_8gPrz6xW&usg=AFQjCNGwT_hEkwGBXzS3holaM1g85I0S5Q&sig2=dSDJ6lL0CR3-nIR7WQ739g
Thanks and good luck!
Ben

How to create new components in Visual Studio 2010

Can you tell me how to create new visual component for .net 4.0 in Visual Studio 2010,
i have a book about component creation in Russian Language (Pavel Agurov -Razrabotka Komponentov v MS Visual Studio 2005/2008), but methods in this book covers VS 2005 and 2008. And methods gives some errors in VS 2010.
EDIT:
There is my code
public partial class exComboBox : ComboBox
{
/*public exComboBox()
{
InitializeComponent();
}*/
private System.Collections.Specialized.StringCollection _itemValues = new System.Collections.Specialized.StringCollection();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor("System.Windows.Forms.Design.StringCollectionEditor,System.Editor","System.Drawing.Design.UITypeEditor,System.Drawing")]
public System.Collections.Specialized.StringCollection ItemValues
{
get
{
return _itemValues;
}
set
{
_itemValues = value;
}
}
public object SelectedItemValue
{
get
{
return _itemValues[SelectedIndex];
}
}
}
And when I try to add this component to new form and add values for ItemValues it says
Constructor on type 'System.String' not found.
Right click your project, choose to add a new item. Go to the C# section and select User Control.
This will create a windows control that will appear at the top of the Toolbox when you use the forms designer. Just drag and drop it into your form like any other control.
If you wish to derive it from Combo Box, then just edit the class that is created and change it's base class from a UserControl to a combo box. You might also need to change your constructor top call three base class constructor rather than doing InitialiseComponent for itself.
If you want to use this control in many applications, then you can put the code into a Class Library project, which will make a .dll assembly that other projects can reference to gain access to the control.
Create a Windows Application and then go to Add New Item menu by right clicking on Project in Solution Explorer and you can see there the Component AFAIR.
Assuming you're talking about Winforms...
Deriving from existing controls is probably not something you'll want to do. Especially if you want to change their default behavior or replace their existing properties. Sooner or later you will be facing severe limitations. Believe me, I've been there.
If you want an easy way to repeat some kind of pattern for a ComboBox, I suggest you take a look at IExtenderProvider interface. You can implement it on a Component-derived class that you can drag on the design surface. In this component, you can declare properties that will be attached as extra properties to any comboboxes (or anything else, it's all up to you).
Since the component will know about whatever is attached to it, it will be able to declare event handlers over any attached control / component. For example, if you want your combobox to have items already present, you could handle it's Load event and add the items there.
To learn more about IExtenderProvider, go here.

Interactive Design-Time User Control

I apologise if the title was confusing, it took me nearly 5 minutes to finally think of a title for this one...
Okay, you know how in Visual Studio Express when you add a TabControl to the Form, and you can click on the right-arrow on the top right of the TabControl and it will add a new TabPage, or remove one?
Well, I'm creating a User Control where I need people to be able to switch between Panels (my user control is made up of several Panels). I know this is possible as I've used a Ribbon Control in the past and you could add new buttons etc in the Designer View.
Can somebody please provide any suggestions/advice on how I might go about acheiving this?
Thank you
If I understand your question correctly, you're talking about smart tags.
The process is a little bit involved, so I'm not going to try to post a complete sample. Instead, I'll refer you to this tutorial on the subject. To make a long story short, you have to create a custom designer, and register one or more custom actions. You can use this to create a combo box listing the available panels and switch between them when the selected item is changed.
(Note - the term "smart tags" has two distinct meanings in Visual Studio - I'm specifically talking about the visual designer smart tags, not smart tags in the code editor).
When you make a control that is inherited from Control, you have to make use of a couple of properties such as IsDesignMode, you can then construct event handlers especially for within Design Mode:
if (IsDesignMode){
// Handle the interactivity in Design mode, such as changing a property on the
// Properties toolbox
}
Suppose the control has an event such as MouseClick, you can do this:
private void control_MouseClick(object sender, MouseEventArgs e){
if (IsDesignMode){
// Do something here depending on the Click event within the Designer
}else{
// This is at run-time...
}
}
Another I can think of is 'ShouldSerialize' followed by a publicly accessible property in order to persist the property to the designer-generated code, suppose for example a Control has a boolean property Foo
public bool Foo{
get{ return this._foo; }
set{ if (this._foo != value){
this._foo = value;
}
}
}
public bool ShouldSerializeFoo(){
return true; // The property will be persisted in the designer-generated code
// Check in Form.Designer.cs...
}
If ShouldSerializeFoo returned false, no property is persisted, its the opposite when true, it will be buried within the Form.Designer.cs code...
Hope this helps,
Best regards,
Tom.

How to put an extended WinForms Control on ToolBox

I plan to add functionalities to TextBox with the following:
public class TextBoxExt : TextBox
{
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
}
}
The question is how can we use this TextBoxExt? Is there anyway to get this class onto the ToolBox so that we can just drag and drop it onto the form? If not, what is the best way to use the TextBoxExt?
Build you project with TextBoxExt, make sure it compiles ok.
With the form that you want TextBoxExt on, open the toolbox, right click and select "choose items"
Browse to you .exe or dll that you compiled in 1)
make sure that TextBoxExt has a tick next to it, press ok
TextBoxExt should appear in the toolbox, drag it onto your form
(There is another way of doing this, opening the designer file and renaming the instances of TextBox to TextBoxExt but manual editing of designer files can be considered hazardous by some)
I know this is super old question, but maybe still useful for someone else that has same problem like me - as it's still on the top Google :)
You might interest to use ToolboxItemAttribute (http://msdn.microsoft.com/en-us/library/system.componentmodel.toolboxitemattribute(v=vs.110).aspx).
I did this at my end to resolve the problem.
[ToolboxItem(true)]
public class PanelTitle : LabelControl {
// Whatever code to override LabelControl here...
}
Rebuild the solution and the extended control should be shown in the toolbox.
Any custom control in your project should show up in the Toolbox automatically. I have found that sometimes the controls won't show until you close a re-open Visual Studio. I assume the issue has something to do with caching of the contents of the Toolbox.
You need to add a constructor to your derived class.
public class TextBoxExt : TextBox
{
public TextBoxExt()
{
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
}
}
Your control should appear in the toolbox for your solution automatically. To have it appear for other projects, you have to do Choose Toolbox items, as others have said.
If you want to provide special design-time functionality, then you will also need to provide some additional designer related attributes and probably your own class derived from ControlDesigner.
I fell into this trap just a couple of hours ago.
I've got a .NET 2.0 Windows Application project with some custom UserControls; it worked fine.
So I decided to order my files in subfolders, to make my project a little bit cleaner.
After that, Visual Studio 2010 designer stopped loading my forms, and ToolBox won't show my controls anymore.
I freaked out, moving back source files in project root, resetting ToolBox, but nothing seemed to work.
After that, I remembered I used ReSharper "Remove Unused References", so I tried to put back unused reference, in particular System.Data: problem solved! :O
I can't say you why, but this worked for me.
Hope my experience can help someone else. :)
Bye,
Nando
I created an empty constructor for my custom implementation of UltraGridBagLayoutPanel. Although david.healed is right it isn't necessary, it is quite useful to put a breakpoint in to check that when the form initialises it is using your class to implement your custom control.
It would have been a lot easier to edit the designer file, but I tried it and changed both the field type for the control and also changed the assignment of the field to a new instance of my custom control.
private Infragistics.Win.Misc.UltraGridBagLayoutPanel ultraGridBagLayoutPanel1;
this.ultraGridBagLayoutPanel1 = new Infragistics.Win.Misc.UltraGridBagLayoutPanel();
to
private Athia.Reports.ultraGridBagLayoutPanel1 ultraGridBagLayoutPanel1;
this.ultraGridBagLayoutPanel1 = new Athia.Reports.ultraGridBagLayoutPanel1();
Doing this destroys Visual Studio every time, and to fix it requires using a text editor to put it back again. Therefore unless anyone can describe what is wrong with my implementation of this approach, perhaps calling the class the same as the control name isn't a great idea, I think the only safe and reliable way to achieve this is as Calanus describes in steps 1 to 5 or as an small deviation from that as Rob Windsor rightly points out restarting VS will bring the control into the Toolbox automatically. Unfortunately for me I then have to change all of the child controls over from the original class to my customised class :-(.
Within the same Solution this should work automatically. However, I have found that if the Target Framework aren't matching the Toolbox does not populate. ( I'm assuming really Reference needs to be of version same or lower than target of Reference. ) ( I did get a warning about non-matching Frameworks )
By making these the same Target Framework, Recompile, Restart VS. the control populated correctly. ( I also added the ToolboxItem(true) Attribute)

Categories