Frage

ich geschaffen habe eine kleine Windows Forms-Testanwendung einige Drag / Drop-Code ausprobieren. Die Form besteht aus drei PictureBox. Meine Absicht war, ein Bild von einem PictureBox zu packen, es als während der Ziehoperation benutzerdefinierten Cursor angezeigt werden, dann legen Sie es auf einem anderen PictureBox Ziel.

Das funktioniert gut von einer PictureBox in eine andere , solange sie auf der gleichen Form sind .

Wenn ich zwei Instanzen derselben Anwendung zu öffnen und versuchen, zwischen ihnen zu ziehen / Drop, erhalte ich die folgende kryptische Fehlermeldung:

  

Dieser Remote Proxy hat keinen Kanal   sink was bedeutet, entweder der Server   keine Kanäle registriert sind Server,   Hören, oder diese Anwendung hat keine   geeigneter Client-Kanal zu der sprechen   Server.

Aus irgendeinem Grund aber es funktioniert auf Wordpad ziehen / Drop (aber nicht MS Word oder Pinsel).

Die drei PictureBox erhalten ihre Veranstaltungen wie diese angeschlossen:

foreach (Control pbx in this.Controls) {
    if (pbx is PictureBox) {
        pbx.AllowDrop = true;
        pbx.MouseDown    += new MouseEventHandler(pictureBox_MouseDown);
        pbx.GiveFeedback += new GiveFeedbackEventHandler(pictureBox_GiveFeedback);
        pbx.DragEnter    += new DragEventHandler(pictureBox_DragEnter);
        pbx.DragDrop     += new DragEventHandler(pictureBox_DragDrop);
    }
}

Dann gibt es die vier Ereignisse wie folgt:

void pictureBox_MouseDown(object sender, MouseEventArgs e) {
    int width = (sender as PictureBox).Image.Width;
    int height = (sender as PictureBox).Image.Height;

    Bitmap bmp = new Bitmap(width, height);
    Graphics g = Graphics.FromImage(bmp);
    g.DrawImage((sender as PictureBox).Image, 0, 0, width, height);
    g.Dispose();
    cursorCreatedFromControlBitmap = CustomCursors.CreateFormCursor(bmp, transparencyType);
    bmp.Dispose();

    Cursor.Current = this.cursorCreatedFromControlBitmap;

    (sender as PictureBox).DoDragDrop((sender as PictureBox).Image, DragDropEffects.All);
}

void pictureBox_GiveFeedback(object sender, GiveFeedbackEventArgs gfea) {
    gfea.UseDefaultCursors = false;
}

void pictureBox_DragEnter(object sender, DragEventArgs dea) {
    if ((dea.KeyState & 32) == 32) { // ALT is pressed
        dea.Effect = DragDropEffects.Link;
    }
    else if ((dea.KeyState & 8) == 8) { // CTRL is pressed
        dea.Effect = DragDropEffects.Copy;
    }
    else if ((dea.KeyState & 4) == 4) { // SHIFT is pressed
        dea.Effect = DragDropEffects.None;
    }
    else {
        dea.Effect = DragDropEffects.Move;
    }
}

void pictureBox_DragDrop(object sender, DragEventArgs dea) {
    if (((IDataObject)dea.Data).GetDataPresent(DataFormats.Bitmap))
        (sender as PictureBox).Image = (Image)((IDataObject)dea.Data).GetData(DataFormats.Bitmap);
}

Jede Hilfe wäre sehr geschätzt werden!

War es hilfreich?

Lösung

Nach viel Zähneknirschen und Ziehen der Haare, ich war in der Lage mit einer praktikablen Lösung zu kommen. Es scheint, gibt es einige undokumentierte Fremdheit unter der Decke mit .NET und seinem OLE-Drag los und Drop-Unterstützung. Es scheint zu versuchen, .NET Remoting zu verwenden, wenn Drag & Drop zwischen .NET-Anwendungen durchführen, aber diese überall dokumentiert? Nein, ich glaube nicht, es ist.

So ist die Lösung kam ich mit einer Hilfsklasse beinhaltet, um die Bitmap-Daten zwischen Prozessen Marschall. Als erstes ist hier die Klasse.

[Serializable]
public class BitmapTransfer
{
    private byte[] buffer;
    private PixelFormat pixelFormat;
    private Size size;
    private float dpiX;
    private float dpiY;

    public BitmapTransfer(Bitmap source)
    {
        this.pixelFormat = source.PixelFormat;
        this.size = source.Size;
        this.dpiX = source.HorizontalResolution;
        this.dpiY = source.VerticalResolution;
        BitmapData bitmapData = source.LockBits(
            new Rectangle(new Point(0, 0), source.Size),
            ImageLockMode.ReadOnly, 
            source.PixelFormat);
        IntPtr ptr = bitmapData.Scan0;
        int bufferSize = bitmapData.Stride * bitmapData.Height;
        this.buffer = new byte[bufferSize];
        System.Runtime.InteropServices.Marshal.Copy(ptr, buffer, 0, bufferSize);
        source.UnlockBits(bitmapData);
    }

    public Bitmap ToBitmap()
    {
        Bitmap bitmap = new Bitmap(
            this.size.Width,
            this.size.Height,
            this.pixelFormat);
        bitmap.SetResolution(this.dpiX, this.dpiY);
        BitmapData bitmapData = bitmap.LockBits(
            new Rectangle(new Point(0, 0), bitmap.Size),
            ImageLockMode.WriteOnly, bitmap.PixelFormat);
        IntPtr ptr = bitmapData.Scan0;
        int bufferSize = bitmapData.Stride * bitmapData.Height;
        System.Runtime.InteropServices.Marshal.Copy(this.buffer, 0, ptr, bufferSize);
        bitmap.UnlockBits(bitmapData);
        return bitmap;
    }
}

Um die Klasse in einer Weise zu nutzen, die sowohl .NET als auch nicht verwaltete Empfänger der Bitmap unterstützen wird, ein Dataobject-Klasse ist für die Drag & Drop-Operation verwendet, wie folgt.

den Ziehvorgang zu starten:

DataObject dataObject = new DataObject();
dataObject.SetData(typeof(BitmapTransfer), 
  new BitmapTransfer((sender as PictureBox).Image as Bitmap));
dataObject.SetData(DataFormats.Bitmap, 
  (sender as PictureBox).Image as Bitmap);
(sender as PictureBox).DoDragDrop(dataObject, DragDropEffects.All);

Um den Vorgang abzuschließen:

if (dea.Data.GetDataPresent(typeof(BitmapTransfer)))
{
    BitmapTransfer bitmapTransfer = 
       (BitmapTransfer)dea.Data.GetData(typeof(BitmapTransfer));
    (sender as PictureBox).Image = bitmapTransfer.ToBitmap();
}
else if(dea.Data.GetDataPresent(DataFormats.Bitmap))
{
    Bitmap b = (Bitmap)dea.Data.GetData(DataFormats.Bitmap);
    (sender as PictureBox).Image = b;
}

Die Prüfung für die Kunden BitmapTransfer zuerst durchgeführt, so dass es Vorrang vor der Existenz eines regelmäßigen Bitmap in dem Datenobjekt nimmt. Die BitmapTransfer Klasse konnte mit mehreren Anwendungen in einer gemeinsamen Bibliothek für den Einsatz platziert werden. Es muss serialisierbar markiert werden, wie für Drag & Drop zwischen den Anwendungen gezeigt. Getestet habe ich es mit Drag & Drop von Bitmaps innerhalb einer Anwendung, zwischen Anwendungen und von einer .NET-Anwendung zu Wordpad.

Hope, das hilft dir.

Andere Tipps

ich auf diesem Problem vor kurzem kam, und wurde ein benutzerdefiniertes Format in der Zwischenablage verwenden, Interop ein bisschen schwieriger zu machen. Wie auch immer, mit einem wenig Lichtreflexion war ich in der Lage auf die ursprüngliche System.Windows.Forms.DataObject zu bekommen, und dann die GetData anrufen und mein benutzerdefiniertes Element wie normale aus ihn heraus.

var oleConverterType = Type.GetType("System.Windows.DataObject+OleConverter, PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
var oleConverter = typeof(System.Windows.DataObject).GetField("_innerData", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(e.Data);
var dataObject = (System.Windows.Forms.DataObject)oleConverterType.GetProperty("OleDataObject").GetValue(oleConverter, null);

var item = dataObject.GetData(this.Format);

Nach Stunden und Stunden der Frustration mit Dampf aus den Ohren kommt, kam ich schließlich mit einer zweiten Lösung für dieses Problem. Genau die Lösung ist die eleganteste ist wahrscheinlich in den Augen des Betrachters. Ich hoffe, dass Michael und meine Lösungen werden sowohl Hilfe frustriert Programmierer und ihnen Zeit sparen, wenn sie auf ähnliche Aufgaben zu beginnen.

Zunächst einmal eine Sache, die mich hat schlagen war, dass Wordpad der Lage war, den Drag / Drop-Bilder zu empfangen gerade aus dem Kasten heraus. So ist die Verpackung der Datei war wahrscheinlich nicht das Problem, aber es war vielleicht etwas faul am empfangenden Ende geht.

Und faul war. Es stellt sich heraus gibt es seveal Arten von IDataObjects über den Rahmen .Net schweben. Wie Michael wies darauf hin, OLE Drag und Unterstützung Versuche fallen zu .NET Remoting zu verwenden, wenn zwischen den Anwendungen interagieren. Damit ist eigentlich ein System.Runtime.Remoting.Proxies .__ Transparent, wo das Bild sein sollte. Dies ist eindeutig nicht (vollständig) korrekt ist.

Der folgende Artikel gab mir ein paar Hinweise in der richtigen Richtung:

http://blogs.msdn.com/adamroot/archive/2008/02/01/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx

Windows Forms standardmäßig System.Windows.Forms.IDataObject. Da wir jedoch mit unterschiedlichen Verfahren hier zu tun haben, habe ich mich entschlossen System.Runtime.InteropServices.ComTypes.IDataObject einen Schuss statt zu geben.

In der Drag & Drop-Ereignisse, der folgende Code löst das Problem:

const int CF_BITMAP = 2;

System.Runtime.InteropServices.ComTypes.FORMATETC formatEtc;
System.Runtime.InteropServices.ComTypes.STGMEDIUM stgMedium;

formatEtc = new System.Runtime.InteropServices.ComTypes.FORMATETC();
formatEtc.cfFormat = CF_BITMAP;
formatEtc.dwAspect = System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT;
formatEtc.lindex = -1;
formatEtc.tymed = System.Runtime.InteropServices.ComTypes.TYMED.TYMED_GDI;

Die beiden GetData Funktionen nur den gleichen Namen. Man gibt ein Objekt, das andere definiert leer kommen und stattdessen übergibt die Informationen in die STGMEDIUM aus Parameter:

(dea.Data as System.Runtime.InteropServices.ComTypes.IDataObject).GetData(ref formatEtc, out stgMedium);
Bitmap remotingImage = Bitmap.FromHbitmap(stgMedium.unionmember);

(sender as PictureBox).Image = remotingImage;

Schließlich, um Speicherlecks zu vermeiden, ist es wahrscheinlich eine gute Idee, die OLE-Funktion ReleaseStgMedium aufzurufen:

ReleaseStgMedium(ref stgMedium);

kann Diese Funktion enthalten sein, wie folgt:

[DllImport("ole32.dll")]
public static extern void ReleaseStgMedium([In, MarshalAs(UnmanagedType.Struct)] ref System.Runtime.InteropServices.ComTypes.STGMEDIUM pmedium);

... und dieser Code scheint perfekt mit Drag-and-Drop-Operationen zu arbeiten (von Bitmaps) zwischen zwei Anwendungen. Der Code könnte leicht auf andere gültige Zwischenablage-Formate erweitert werden und wahrscheinlich Gewohnheit zu Zwischenablage-Formate. Da nichts mit dem Verpackungsteil fertig war, können Sie immer noch ein Bild zu Wordpad Drag & Drop-und da es Bitmap-Formaten akzeptiert, können Sie auch ein Bild aus Word in die Anwendung ziehen.

Als Randbemerkung, Ziehen und Fallenlassen ein Bild nicht direkt von IE nicht einmal die Drag & Drop-Ereignis auslösen. Seltsam.

Nur aus Neugier, in der Drag & Drop-Methode, haben Sie versucht, testen, ob Sie das Bitmap-Bild aus dem DragEventArgs überhaupt bekommen können? Ohne den Absender Besetzung zu tun? Ich frage mich, ob das picturebox Objekt nicht serialisierbar ist, was das Problem verursacht, wenn Sie versuchen, den Absender in einer anderen Anwendungsdomäne zu verwenden ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top