.NET: is there a Click-and-drag "Desktop-Like" control? - c#

OK, first for context look at the Windows desktop; You can take items (folders, files) on the desktop and drag them around to different places and they "stay" where you dragged them. This seems to be a pretty useful feature to offer users so as to allow them to create their own "groupings" of items.
My question is thus:
Is there a control in .NET that approximates this behavior with a collection of items?
I'm thinking something like a listview in "LargeIcon" mode, but it allows you to drag the icons around to different places inside the control.

You can do this with a standard ListView control by implementing drag-and-drop. Here's a sample control that does this:
using System;
using System.Drawing;
using System.Windows.Forms;
public class MyListView : ListView {
private Point mItemStartPos;
private Point mMouseStartPos;
public MyListView() {
this.AllowDrop = true;
this.View = View.LargeIcon;
this.AutoArrange = false;
this.DoubleBuffered = true;
}
protected override void OnDragEnter(DragEventArgs e) {
if (e.Data.GetData(typeof(ListViewItem)) != null) e.Effect = DragDropEffects.Move;
}
protected override void OnItemDrag(ItemDragEventArgs e) {
// Start dragging
ListViewItem item = e.Item as ListViewItem;
mItemStartPos = item.Position;
mMouseStartPos = Control.MousePosition;
this.DoDragDrop(item, DragDropEffects.Move);
}
protected override void OnDragOver(DragEventArgs e) {
// Move icon
ListViewItem item = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
if (item != null) {
Point mousePos = Control.MousePosition;
item.Position = new Point(mItemStartPos.X + mousePos.X - mMouseStartPos.X,
mItemStartPos.Y + mousePos.Y - mMouseStartPos.Y);
}
}
}

I think the closest would the ListView control, but even that is more like an explorer window. You might be able to create your own view that does what you want, but you'd need to manually persist icon locations somewhere.

If you are not opposed to using WPF, Josh Smith has created a pretty neat canvas that I am currently using for a project. It allows you to add controls and drag them around the canvas. You would have to handle what is loaded on the canvas and where on the next load of the program, but that is pretty simple.
http://www.codeproject.com/KB/WPF/DraggingElementsInCanvas.aspx

This depends on whether this is a windows application or a web browser based application. In either case you need to have some sort of container to manage the locations of controls. You can manage the position of controls inside of a container with their X and Y coordinates.
You would handle the actual movement using the drag events. So you have drag start, while dragging (you might show a place holder graphic or change the cursor), and finally a drag end (set the control's x and y to the new position). Obviously these aren't the actual event names, but a search for "how to handle drag events" should get you started.
In a web environment, I know jquery has dragging capability built in. So you might want to look at that. The one big thing you'll have to be careful of is maintaining the positions of your controls between postbacks. I'm not sure what would happen in this case.

Windows uses ListView32, an internal control with drag n' drop placeholder features, custom borders...
The icon location can be stored in a XML file, or in the application settings (by putting the XML as string and converting it to file when needed).
You can do, for example:
<icons>
<icon1>
<name>Icon1</name>
<text>My PC</text>
<imageIndex>16</imageIndex>
</icon1>
<icon2>
.....
</icon2>
.....
</icons>
Lorenzo

Related

Add overlay to Window at runtime

I'm writing a simple "tutorial" library that will allow developers to easily add step-by-step tutorials to their existing WPF applications. The tutorials will help first time users of the application find their way around by adding an overlay that highlights a control and explains its purpose. The end result will look something like this:
The regular application:
The overlay explaining the purpose of a control:
My question is this: What's the most reliable and unobtrusive way to inject the overlay view into the current window? The best I've come up with so far is to require the developer to add an attached property to whatever window will be hosting the overlay, and then add the necessary elements on the window's Initialized callback:
public static void IsTutorialOverlayCompatibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((Boolean)e.NewValue == true)
{
if (sender as Window != null)
{
Window window = (Window)sender;
window.Loaded += new RoutedEventHandler((o, eargs) =>
{
Grid newRootElement = new Grid();
newRootElement.Name = "HelpOverlayRoot";
if (window.Content as UIElement != null)
{
UIElement currentContent = (UIElement)window.Content;
window.Content = null;
newRootElement.Children.Add(currentContent);
newRootElement.Children.Add(new HelpOverlayControl());
window.Content = newRootElement;
}
});
}
}
}
This feels like a hack, however, and I'm not sure that there isn't some edge case where this method will break the layout of the application. In addition, it requires that the window's Content property be an instance of type UIElement.
I'd like to avoid forcing developers to change their XAML (i.e, adding a custom overlay UserControl to every window) in order to use my library. What's the best way to add this kind of functionality to an existing WPF application?

Best practice for creating bordered control in WinForm

I am writing WinForm application in C# .NET and I need to add dashed/dotted or any other type of border to any of UI components of application when the user clicks on it. I would like to get something like WinForm GUI editor in Visual Studio.
I am new in .NET so I don't know well what is possible via native methods and properties and what I need to implement myself. I have tried to find something on the net and here but I am not sure what to search, there are different approaches. For example it is possible to draw the border artificially, I mean using graphics. But I guess there should be easier approach.
What can you advice? What is the best practice in this situation? Please provide some portions of code.
Every Control has a Paint event. You have to subscribe to this event and look into the given arguments. The sender is the current control that should be painted. You can cast it within your method to Control. Now you can check the control if it focused by checking control.Focused and if it is true simply do whatever you like within the graphics object of the PaintEventArgs. This can furthermore be encapsulated in an extension method which would make the usage fairly easy.
public static void DrawBorderOnFocused(this Control control)
{
if(control == null) throw new ArgumentNullException("control");
control.Paint += OnControlPaint;
}
public static void OnControlPaint(object sender, PaintEventArgs e)
{
var control = (Control)sender;
if(control.Focused)
{
var graphics = e.Graphics;
var bounds = e.Graphics.ClipBounds;
// ToDo: Draw the desired shape above the current control
graphics.DrawLine(Pens.BurlyWood, new PointF(bounds.Left, bounds.Top), new PointF(bounds.Bottom, bounds.Right));
}
}
The usage within the code would then be something like:
public MyClass()
{
InitializeComponent();
textBox1.DrawBorderOnFocused();
textBox2.DrawBorderOnFocused();
}

drag and drop winform controls

I want to drag and drop a control (label for example) in a winform application. I saw some examples on dragging and dropping text, but this is not what I want. I want to enable the user to move a control around. Can anyone direct me to some resources or examples? Thanks.
you should look at examples on how to make draggable controls.
There are some answers here in SO as well.
See this Move controls when Drag and drop on panel in C#
this is a complete example on how to host the Form Designer:
Tailor Your Application by Building a Custom Forms Designer with .NET
I did something similar in Delphi long time ago, will search the source code, convert it into .NET C# and make a wiki page on that matter, as it is becoming such popular question recently :)
As far as i understand, where you wish to drop a control is called a container, infact any control can act as a container. So first that container, you need to enable the drop property as well as the drag property of the controls which you need to drag.
Then write events (Candrag, candrop, controladded, etc.) for each control where in which, some logic to hold the objects and display them as you may want.
Say, ill take an example where in which, you wish to drag imagetext from combombox into a picturebox and then make the picturebox analyze the text and fine related file name in a directory and load that image into its if its present.
So here, when you start dragging the text from combombox, you have to write some logic in event candrag. Then once you drop, you have to write logic to understand what kinda object was added and get the text related to it (kinda deciphering) in the control where you drop other control.
Sorry, i have no code to give you now, but i hope you got the idea how its done. May be this article can help you? http://vicky4147.wordpress.com/2007/02/04/a-simple-drag-drop-in-winforms/
bool draging = false;
int curPosX, curPosY;
private void label2_MouseDown(object sender, MouseEventArgs e)
{
draging = true;
curPosX = Cursor.Position.X;
curPosY = Cursor.Position.Y;
}
private void label2_MouseMove(object sender, MouseEventArgs e)
{
if (draging)
{
label2.Left += Cursor.Position.X - curPosX;
curPosX = Cursor.Position.X;
label2.Top += Cursor.Position.Y - curPosY;
curPosY = Cursor.Position.Y;
}
}
private void label2_MouseUp(object sender, MouseEventArgs e)
{
draging = false;
}

customizing treeview in winforms

Is it possible to create a treeview in visual studio which resembles the following figure :
The ROOT , CHILD and Sub-Child , all three would be LinkLabels , and on clicking them a new Form would be opened.
You could also try embed WPF user control into WinForm. Customizing WinForms isn't an easy task. In WPF you can do it much easier.
You also can activate Hot tracking for the tree view and then handle the NodeMouseClick event.
This is not practical in Winforms, every Control has a native Windows window associated with it. A window is a very expensive operating system object, create more than 50 of them and your user interface will noticeably start to drag because of the amount of overhead involved in drawing the controls. You very quickly reach that practical upper limit by nesting controls like you are intending to do.
You can customize the appearance of a TreeView by using its DrawMode property and the DrawNode event. The MSDN library article for TreeView.DrawNode has a decent example. It is also a popular component type in 3rd party component vendor collections. They add lots of bells and whistles to their version.
So, people don't like doing it.
The answer, however, is Yes, you can.
TreeView treeView1;
void Initialize_It() {
treeView1 = new TreeView();
treeView1.AfterSelect += new TreeViewEventHandler(treeView1_AfterSelect);
TreeNode Root = treeView1.Nodes.Add("ROOT");
TreeNode Child = Root.Nodes.Add("CHILD");
TreeNode SubChild = Child.Nodes.Add("Sub-Child");
}
void treeView1_AfterSelect(object sender, TreeViewEventArgs e) {
const string FORMAT = "{0} Node Selected. Call your Windows Form from here.";
if (e.Node.Level == 0) {
MessageBox.Show(string.Format(FORMAT, e.Node.Text), e.Node.Text);
} else if (e.Node.Level == 1) {
MessageBox.Show(string.Format(FORMAT, e.Node.Text), e.Node.Text);
} else if (e.Node.Level == 2) {
MessageBox.Show(string.Format(FORMAT, e.Node.Text), e.Node.Text);
}
}

How to implement the Edit -> Copy menu in c#/.net

How do I implement a Copy menu item in a Windows application written in C#/.NET 2.0?
I want to let the user to mark some text in a control and then select the Copy menu item from an Edit menu in the menubar of the application and then do a Paste in for example Excel.
What makes my head spin is how to first determine which child form is active and then how to find the control that contains the marked text that should be copied to the clipboard.
Help, please.
With the aid of some heavy pair programming a colleague of mine and I came up with this, feel free to refactor.
The code is placed in the main form. The copyToolStripMenuItem_Click method handles the Click event on the Copy menu item in the Edit menu.
/// <summary>
/// Recursively traverse a tree of controls to find the control that has focus, if any
/// </summary>
/// <param name="c">The control to search, might be a control container</param>
/// <returns>The control that either has focus or contains the control that has focus</returns>
private Control FindFocus(Control c)
{
foreach (Control k in c.Controls)
{
if (k.Focused)
{
return k;
}
else if (k.ContainsFocus)
{
return FindFocus(k);
}
}
return null;
}
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
{
Form f = this.ActiveMdiChild;
// Find the control that has focus
Control focusedControl = FindFocus(f.ActiveControl);
// See if focusedControl is of a type that can select text/data
if (focusedControl is TextBox)
{
TextBox tb = focusedControl as TextBox;
Clipboard.SetDataObject(tb.SelectedText);
}
else if (focusedControl is DataGridView)
{
DataGridView dgv = focusedControl as DataGridView;
Clipboard.SetDataObject(dgv.GetClipboardContent());
}
else if (...more?...)
{
}
}
Why not extending the control, so the control itself provides the data which should be copied into the clipboard.
Take a look at ApplicationCommands documentation.
To determine which window is open, you can query the Form.ActiveMDIChild property to get a reference to the currently active window. From there, you can do one of two things:
1) If you create your own custom Form class (FormFoo for example) that has a new public member function GetCopiedData(), then inherit all of your application's child forms from that class, you can just do something like this:
((FormFoo)this.ActiveMDIChild).GetCopiedData();
Assuming the GetCopiedData function will have the form-specific implementation to detect what text should be copied to the clipboard.
or
2) You can use inheritance to detect the type of form that is active, and then do something to get the copied data depending on the type of form:
Form f = this.ActiveMDIChild;
if(f is FormGrid)
{
((FormGrid)f).GetGridCopiedData();
} else if(f is FormText) {
((FormText)f).GetTextCopiedData();
}
etc.
That should get you started with finding the active window and how to implement a copy function. If you need more help copying out of a GridView, it may be best to post another question.
If the form is tabbed and the target control is a DataGridView, it's sometimes possible for the Form's TabControl to be returned as the active control, using the above method, when the DataGridView is right clicked upon.
I got around this by implementing the following handler for my DataGridView:-
private void dataGridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
dataGridView.Focus();
dataGridView.CurrentCell = dataGridView[e.ColumnIndex, e.RowIndex];
}
}
It seems to me that you might be better off breaking this into smaller tasks/questions.
You have a few issues you are stuck on from the way it sounds.
You have multiple 'child' windows open. Is this an MDI application?
When an action is performed on one of those child windows, it should fire an event in that window's event handlers. That is your first thing to set up. If this is a datagridview I would suggest a simple test to start. Try trapping the DataGridView.SelectionChanged event. Just throw in something like MessageBox.Show("I copied your datas!"); for now.
This should get you started where you will at least understand how this event will be raised to you.
From here, we will need to know a little more about your datagrid, and the rows and child controls in those rows. Then we can likely create events in the render events that will be raised at the appropriate times, with the appropriate scope.

Categories

Resources