Drag drop entrant et clipboard : même combat !

Soyez le premier à donner votre avis sur cette source.

Vue 18 479 fois - Téléchargée 703 fois

Description

Le drag and drop permet d'améliorer de façon considérable un interface utilisateur. Cependant, le drag and drop n'est pas seulement interne à un appli, il peut aussi être externe. Un tas de cellules sélectionnées dans Excel par exemple peut très bien attérir sur votre appli. A vous de savoir si vous voulez les gérer ou non.

La récupération des données envoyées lors d'un drag and drop est assez simple. L'application qui fournit les infos peut les envoyer sous plusieurs formes. Par exemple, Excel envoie ses cellules déplacées sous forme d'un XML, de texte, d'image... Il est alors possible de récupérer ces formats (sous la forme d'un tableau de strings), et de dire si oui ou non on peut accepter le drag and drop. Cette opération se fait alors que la souris survole la zone de notre appli, et que le drag and drop n'est pas effectué.

Un fois le drop effectué, c'est à dire quand l'utilisateur termine le drag and drop, on cherche alors à récupérer les données.

Pour vous aider à gérer votre drag and drop entrant, je vous propose cette source. Si vous voulez gérer les infos en provenance d'Excel, par exemple, utiliser mon appli pour y droper des données Excel. Vous pourrez alors voir tous les types de données envoyés par exel, et la plupart du temps leur contenu.

Dans le titre, je parle du presse-papier (clipboard) pour la bonne et simple raison que la donnée y est gérée de la même manière. On récupère un objet implémentant l'interface IDataObject, sur lequel on récupère les formats de données dispos, puis les infos en elles même.

Source / Exemple :


using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace DragDropIn {
	public partial class Form1 : Form {
		/// <summary>
		/// Variable permettant de stocker les données envoyées à notre programme par drag and drop.
		/// </summary>
		private Hashtable Data;

		/// <summary>
		/// Cet évènement survient lorsque la souris arrive sur notre formulaire lors d'une
		/// opération de drag and drop.
		/// On demande alors à l'évènement e (DragEventArgs) quels sont les types de données
		/// que l'on peut récupérer, et on les liste dans le listview de la form.
		/// </summary>
		private void Form1_DragEnter(object sender, DragEventArgs e) {
            ListFormats(e.Data);
            e.Effect = DragDropEffects.All;
		}

		/// <summary>
		/// Cet évènement survient à la fin de l'opération de drag and drop, lorsque la souris est "relachée"
		/// sur notre formulaire.
		/// On récupère alors tous les type des données que l'on a stocké dans notre list view, 
		/// on demande à l'objet e (DragEventArgs) tous les objets possibles, et on
		/// les stocke dans un hash table.
		/// </summary>
		private void Form1_DragDrop(object sender, DragEventArgs e) {
            GetAllData(e.Data);
		}

		/// <summary>
		/// Lorsque l'on clique sur un élément de la liste des types envoyés par le drag and drop,
		/// on affiche l'objet correspondant.
		/// L'objet est affiché dans un propertygrid, et quand c'est possible dans une zone
		/// de texte ou dans un zone d'image.
		/// </summary>
		private void listBox1_SelectedIndexChanged(object sender, EventArgs e) {
			ResetUI();
			try {
				this.propertyGrid1.SelectedObject = Data[this.listBox1.SelectedItem.ToString()];
				
				if(this.propertyGrid1.SelectedObject.GetType() == typeof(Bitmap)) {
					this.pictureBox1.Image = (Bitmap) this.propertyGrid1.SelectedObject;
				}

				if(this.propertyGrid1.SelectedObject.GetType() == typeof(string)) {
					this.textBox1.Text = (string) this.propertyGrid1.SelectedObject;
				}

				if(this.propertyGrid1.SelectedObject.GetType() == typeof(System.IO.MemoryStream)) {
					System.IO.StreamReader reader = new System.IO.StreamReader((System.IO.MemoryStream) this.propertyGrid1.SelectedObject);
					this.textBox1.Text = (string) reader.ReadToEnd();
				}

				if(this.propertyGrid1.SelectedObject.GetType() == typeof(XmlDocument)) {
					this.textBox1.Text = ((XmlDocument) this.propertyGrid1.SelectedObject).InnerXml;
				}
			} catch { }
		}

		/// <summary>
		/// Méthode permettant de réinitialiser la zone de visualisation d'image et de texte.
		/// </summary>
		private void ResetUI() {
			this.pictureBox1.Image = null;
			this.textBox1.Text = string.Empty;
		}

		/// <summary>
		/// Lorsqu'un nouvel objet est chargé dans le propertygrid, on en affiche le type
		/// au bas de la form.
		/// </summary>
		private void propertyGrid1_SelectedObjectsChanged(object sender, EventArgs e) {
			this.toolStripStatusLabel1.Text = "L'objet en cours de visualisation est de type : " + this.propertyGrid1.SelectedObject.GetType().ToString();
		}

		/// <summary>
		/// Constructeur du formulaire.
		/// </summary>
		public Form1() {
			InitializeComponent();
		}

        /// <summary>
        /// Survient lorsque l'utilisateur souhaite consulter le contenu du presse-papier.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            ListFormats(Clipboard.GetDataObject());
            GetAllData(Clipboard.GetDataObject());
        }

        /// <summary>
        /// Permet de lister les formats disponibles dans l'objet Data.
        /// </summary>
        /// <param name="data"></param>
        private void ListFormats(IDataObject data)
        {
            ResetUI();
            this.listBox1.Items.Clear();
            string[] formats = data.GetFormats();

            foreach (string s in formats)
            {
                this.listBox1.Items.Add(s);
            }
        }

        /// <summary>
        /// Permet de récupérer toutes les données stockées dans l'objet Data.
        /// </summary>
        /// <param name="data"></param>
        private void GetAllData(IDataObject data)
        {
            ResetUI();
            Data = new Hashtable();
            foreach (string key in this.listBox1.Items)
            {
                Data.Add(key, data.GetData(key));
            }
        }
	}
}

Conclusion :


- Je posterais certainement une source sur le drag and drop sortant et l'implémentation de l'interface IDataObject.
- Cette source est en .net 2

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

cs_yoannd
Messages postés
305
Date d'inscription
lundi 7 janvier 2002
Statut
Membre
Dernière intervention
10 août 2011
4
oui, je vois mieux ce que tu veux dire.
En gros, tu ne veux pas simplement déplacer un élément d'une liste à l'autre, mais prendre un élément de la liste 1 et "l'associer" à un élément de la liste 2.
Ta logique de vouloir mettre un évènement DragEnter sur un élément de la liste plutôt que sur la liste en elle-même est légitime, mais comme tu le vois, ce n'est à priori pas possible.
L'autre solution serait de récupérer l'emplacement de la souris au moment de cet évènement (cette info doit certainement se trouver dans les params de l'évènement DragEnter), et par ce biais, voir s'il n'y a pas une méthode pour savoir quel élément de la liste se trouve au niveau de ce point.
Essaye peut-être de chercher dans ce sens. Si tu le souhaites, je veux bien y regarder plus concrètement dimanche prochain ou la semaine prochaine. D'ici-là, je n'aurais malheureusement pas le temps de m'y attarder plus...
Bon coding !

a+
tibo76530
Messages postés
24
Date d'inscription
mercredi 6 juin 2007
Statut
Membre
Dernière intervention
15 octobre 2008

merci pour ta réponse. mais ca ne réponds pas totalement à ce que je veux.
je vais essayer de mieux expliquer.
j'ai déjà implémenter les dragenter et drag drop.
j'ai ce code la:
this.listViewTarget.DragDrop += new System.Windows.Forms.DragEventHandler(this.listViewTarget_DragDrop);
this.listViewTarget.DragEnter += new System.Windows.Forms.DragEventHandler(this.listViewTarget_DragEnter);
seulement, je ne veux pas pouvoir deposer mon élément saisi dans ma 1ere list dans ma 2eme list, mais SUR un éléments de ma 2eme liste.
j'ai essayé de mettre mes 2 fonctions sur
this.listViewTarget.Items.DragDrop

mais ca ne marche pas.
j'espère que tu as compris ce que je voulais faire, et vois tu une solution?
merci de tes conseils.
cs_yoannd
Messages postés
305
Date d'inscription
lundi 7 janvier 2002
Statut
Membre
Dernière intervention
10 août 2011
4
Je ne sais pas si ce que je vais te dire va t'aider, mais voici comment je vois le principe :
Tout d'abor, tu as une classe, qui hérite de l'interface IDataObject (je crois que c'est son nom). C'est une interface définie dans le framework .net. Comme c'est une interface, tu dois redéfinir dans ta classe les méthodes de l'interface.
Une fois que c'est fait, tu remplis ta liste normallement avec tes données, qui doivent correspondre à des instances de ta classe qui implémente IDataObject.

Maintenant, tu dois gérer deux évènements sur tes listview :
- Sur ta liste 1 : L'évènement DragOut. Autrement dit, ce qui se passe quand l'utilisateur prend un élément de cette liste pour l'emener ailleurs. Sur cette évènement, tu peux définir le DataObject qui sera "transporté" d'un composant à l'autre. Et le DataObject en question, c'est le (ou les) instances des classes qui se trouvent derrière chaque élément sélectionné du listview. Pour voir si ton évènement DragOut fonctionne, tu peux utiliser le code présent sur cette page. Il te suffit, si tout se passe bien, de lancer ton projet, et de faire un drag&drop de ta liste 1 vers mon appli, et tu verra si ton dataobject est bien passé.

- Secondo, il faut gérer le DragEnter sur ton second listview. Autrement dit, c'est l'évènement qui survient lorsque ton utilisateur est en train de faire un drag&drop, et que sa souris arrive sur ton listview de destination, mais attention, le bouton de la souris n'est pas encore relaché. C'est à ce moment là que tu peux accepter ou non l'objet qu'on te propose. Pour accepter ou non, tu regardes les paramètres passés à ton évènement... tu y trouveras un dataobject. Il te suffit de voir si le type de ce dataobject te convient. Ici, le type sera typeof(la classe dont on a parlé tout à l'heure).

- Enfin, le DragDrop. C'est quand l'utilisateur relache la souris sur ton second ListView. C'est à ce moment précis que tu récupères effectivement ton DataObject, et que tu en fais ce que tu veux. Typiquement, ici, tu vas devoir ajouter un nouvel élément à ton second listview, et mettre à jour ta base de données.

Autre chose que je te conseille : tu as deux listview, et tu veux peut-être pouvoir faire des drag&drop de l'une vers l'autre, et vice-versa. Ce que tu devrais donc faire, c'est un composant ergonomique qui dérive de listview, et qui implémente tout ce que je t'ais dit avant. De cette mannière, tu ne réécriras pas tes évènements de drag&drop 2 fois (1 fois par listview).

Bon, je ne sais pas si tout ce que j'ai écrit est exact car j'ai fait ça de mémoire. Je n'ai peut-être pas été non plus très clair dans mes explications.

Le mieux serait que tu je te fasse un tutoriel ce soir, si tu en as besoin.

a+
tibo76530
Messages postés
24
Date d'inscription
mercredi 6 juin 2007
Statut
Membre
Dernière intervention
15 octobre 2008

effectivement, j'ai relu, et c'est pas très clair ce que j'ai mis. c'est effectivement un drag and drop interne que je souhaite réaliser. j'explique:
j'ai 2 listview, remplies chacunes avec des éléments différents.
je souhaite que l'on puisse prendre un élément de la premiere liste, qu'on le fasse glisser sur la 2eme et quand on le lachera sur l'élément choisi, je coderai un enregistrement dans ma BDD. voila, j'espère que c'est plus clair.
dans tous les cas, merci de t'intéresser à mon problème.
tibo
cs_yoannd
Messages postés
305
Date d'inscription
lundi 7 janvier 2002
Statut
Membre
Dernière intervention
10 août 2011
4
Salut,

Je ne sais pas trop ce que tu veux faire, et effectivement, je veux bien des précisions.
Ceci-dit, la source présentée ici permet de gérer le drag&drop provenant d'applications tierces. Par exemple, que se passe-t-il quand on fait un drag en drop depuis excel ou word vers ton application. D'après ce que j'ai compris de ton message, il s'agirait plutôt d'un drag&drop interne. Les mêmes évènements sont les mêmes. Après, tu peux très bien effectuer des opérations (enregistrement en base par ex.) ou lever des évènements internes à ton application sur l'évènement gérant le drag "in" de teslist-box.
Pour pouvoir t'aider d'avantage, j'aurais besoin plus d'infos, avec pourquoi pas un peu de code.

Cordialement,

Yoann

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.