drag and drop - univerzita karlovapři změně stavu klávesnice nebo tlačítek myši •odpověď...

Post on 23-Feb-2021

1 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Drag–and–Drop

sada COM protokolů

29.12.2019 vjj 1

použitá rozhraní

• IDataObject - obal přenášených dat s informacemi o jejich typu, resp. o poskytovaných formátech

• IDropSource - komunikace se Systémem pro zajištění konzistentního vzhledu kurzoru a pro definici reakcí na činnost uživatele

• IDropTarget - oznamuje schopnost přijmout či nepřijmout přenášený typ dat a případně extrahuje z IDataObject přenášená data

29.12.2019 vjj 2

Client

Drag-and-Drop

29.12.2019 vjj 3

Window

Server

moje dataDocument / Container

IDropSource

IDataObject

IDropTarget

DoDragDrop(...)

SYSTEM

register Drag-and-Drop target• target:

pro okno které by mělo být schopno přijímat COM objekty prostřednictvím Drag-and-Drop

RegisterDragDrop(hWindow, pIDropTarget);

29.12.2019 vjj 4

start Drag-and-Drop

• source:nejčastěji v reakci na specifickou činnost uživatelepro odstartování Drag-and-Drop,od té chvíle patří myš i klávesnice funkci DoDragDrop!!!

case WM_LBUTTONDOWN :pIDataObject = new mujDatovyObjekt(...) ;

DoDragDrop (pIDataObject, pIDropSource,..29.12.2019 vjj 5

řídící funkce DoDragDrop• DoDragDrop - systémová knihovna OLE2

(naštěstí to nemusím programovat já !!!!!)

• zjistí, nad kterým oknem kurzor zrovna je

case WM_MOUSEMOVE :

. . .

WindowFromPoint ( . . . ) ;

. . .

• podle svých tabulek zjistí, jestli má toto okno zaregistrovaný interface IDropTarget

• pokud ano, zahájí komunikaci s objektyIDropSource a IDropTarget

29.12.2019 vjj 6

vzhled kurzoru• zobrazení správného informačního kurzoru např. pro okamžik, kdy kurzor

přenášející COM objekt přijde nad zaregistrované okno:

DoDragDrop zavolá:

pIDropTarget->DragEnter( pIDataObject,

KeyState, point, pEffect ) ;

• aplikace, které okno patří, se podívá na pIDataObject a odpoví do pEffect, co by byla ochotna s takovým objektem provést

• source aplikace rozhoduje o vzhledu kurzoru pro danou akci

pIDropSource->GiveFeedback( pEffect ) ;

GiveFeedback (. . . )

{ return DRAGDROP_S_USEDEFAULTCURSORS ;

}

29.12.2019 vjj 7

DragOver and DragLeave

• DoDragDrop informuje okno pod kurzorem

• při pohybu kurzoru nad zaregistrovaným oknem

IDropTarget -> DragOver

• když kurzor opouští zaregistrované okno

IDropTarget -> DragLeave

29.12.2019 vjj 8

při změně stavu klávesnice nebo tlačítek myši

• odpověď S_OK znamená "nic se neděje", tj. že danou změnu stavu klávesnice nebo tlačítek myši má funkce DoDragDrop prostě ignorovat a v Drag-and-Drop se má pokračovat.

• pro zaregistrované okno to znamená jen obyčejný pohyb kurzoru na oknem:

IDropTarget -> DragOver

• pokud je odpověď DRAGDROP_S_DROP uvědomí funkce DoDragDropzaregistrované okno o tom, že na ně byl položen datový COM objekt

IDropTarget -> Drop (pIDataObject

29.12.2019 vjj 9

• pokud je odpověď DRAGDROP_S_CANCEL uvědomí funkce DoDragDropzaregistrované okno prostě jen o tom, že kurzor s COM objektem z něho zmizel

IDropTarget -> DragLeave

• DoDragDrop se zeptá zdrojové aplikace, jak na to má reagovat

IDropSource -> QueryContinueDrag

IDataObject metody• IUnknown methods

• ULONG STDMETHODCALLTYPE AddRef()

• ULONG STDMETHODCALLTYPE Release()

• HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)

• IDataObject methods

• STDMETHODIMP QueryGetData(FORMATETC* pformatetc)

• STDMETHODIMP GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium)

• STDMETHODIMP GetCanonicalFormatEtc(LPFORMATETC pformatetc,

• STDMETHODIMP SetData(FORMATETC* pFormatetc, STGMEDIUM* pmedium, BOOL fRelease)

• STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc)

• STDMETHODIMP DAdvise(FORMATETC* pFormatetc, DWORD advf, IAdviseSink* pAdvSink,DWORD* pdwConnection)

• STDMETHODIMP DUnadvise(DWORD dwConnection)

• STDMETHODIMP EnumDAdvise(IEnumSTATDATA** ppenumAdvise)

• STDMETHODIMP GetDataHere(FORMATETC* pformatetc, STGMEDIUM* pmedium)

29.12.2019 vjj 10

IDataObject formáty

• https://www.codeproject.com/Reference/1091137/Windows-Clipboard-Formats

• několik desítek formátů =>složitá inicializace instance IDataObject na jedné straně a extrakce dat z IDataObject na straně druhé

• Win32 API COM/OLE C++ vs MFC vs .NET

29.12.2019 vjj 11

.NET Drag-and-Drop

29.12.2019 vjj 12

.NET• využívá COM implementaci Drag-and-Drop

• objekty, u kterých uživatel oprávněně očekává podporu Drag-and-Drop, např. TextBox, ji mají vesměs již standardně zabudovánu

• pro ostatní vizuální objekty, např. Rectangle, jsou k dispozici

• drag source: metoda DragDrop.DoDragDrop a události GiveFeedback, QueryContinueDrag

• drag target: vlastnost AllowDrop a události DragEnter, DragOver, DragLeave, Drop

• .NET DataObject je odvozen od .NET IDataObject, který obsahuje zjednodušenou implementaci OLE IDataObject

29.12.2019 vjj 13

XAML ellipse as a drag source<Ellipse Fill="Green" Stroke="Black"

Height="200" Width="400" Margin="10"

MouseMove="ellipse_MouseMove" />

29.12.2019 vjj 14

drag source: MouseMoveprivate void ellipseX_MouseMove( object sender,

MouseEventArgs e)

{

if (e.LeftButton == MouseButtonState.Pressed)

{

DragDrop.DoDragDrop

(ellipseX, // Drag-and-Drop Server object

ellipseX.Fill.ToString(), // Drag-and-Drop Data object

DragDropEffects.Copy);

}

}

29.12.2019 vjj 15

defaults for drag source

• GiveFeedback event handler missing=>default system feedback for user during entire drag-and-drop process

• QueryContinueDrag event handler missing=>default reactions on key/button states during entire drag-and-drop process

29.12.2019 vjj 16

XAML ellipse as a drag target<Ellipse Fill="Green" Stroke="Black"

Height="200" Width="400" Margin="10"

Name="ellipseX"

AllowDrop ="True"

DragEnter ="ellipseX_DragEnter"

DragOver ="ellipseX_DragOver"

DragLeave ="ellipseX_DragLeave"

Drop ="ellipseX_Drop"

/>

29.12.2019 vjj 17

drag target: AllowDrop property

• true:

• .NET runtime zaregistruje (RegisterDragDrop) celé okno do seznamu oken s implementací COM rozhraní IDropTarget

• .NET runtime interně zaregistruje objekt jako případný drag target

• .NET runtime ve své implementaci COM rozhraní IDropTarget volá event handlery DragEnter, DragOver, DragLeave, Drop interně zaregistrovaných objektů

29.12.2019 vjj 18

IDataObject

string

29.12.2019 vjj 19

Drag target: DragEnterprivate void ellipseX_DragEnter( object sender, DragEventArgs e )

{

_previousEllipseFill = ellipseX.Fill;

temporary = false;

if ( e.Data.GetDataPresent( DataFormats.StringFormat ) )

{

string dataString = (string)e.Data.GetData( DataFormats.StringFormat );

BrushConverter converter = new BrushConverter( );

if( converter.IsValid( dataString ) )

{

Brush newFill = (SolidColorBrush)converter.ConvertFromString( dataString );

ellipseX.Fill = newFill;

temporary = true;

}

}

}

29.12.2019 vjj 20

DragOverprivate void DragOver( object sender, DragEventArgs e )

{

if (temporary) e.Effects = DragDropEffects.Copy;

}

29.12.2019 vjj 21

Drag target: DragLeaveprivate void ellipseX_DragLeave( object sender,

DragEventArgs e )

{

if (temporary)

{

ellipseX.Fill = _previousEllipseFill;

temporary = false;

}

}

29.12.2019 vjj 22

Drag target: Dropprivate void ellipseX_Drop( object sender, DragEventArgs e )

{

if (temporary)

temporary = false;

else if (e.Data.GetDataPresent(DataFormats.StringFormat))

{

string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

BrushConverter converter = new BrushConverter();

if (converter.IsValid(dataString))

{

Brush newFill = (Brush)converter.ConvertFromString(dataString);

ellipseX.Fill = newFill;

}

}

}

29.12.2019 vjj 23

setting dragged data objectprivate void ellipseX_MouseMove ( object sender,

MouseEventArgs e)

{

if (e.LeftButton == MouseButtonState.Pressed)

{

DragDrop.DoDragDrop(

ellipseX, // drag source object

ellipseX.Fill.ToString(), // dragged data object - string

DragDropEffects.Copy); // first value for GiveFeedback query

}

}

29.12.2019 vjj 24

IDataObject

brush

29.12.2019 vjj 25

setting dragged data objectprivate void ellipseX_MouseMove ( object sender,

MouseEventArgs e)

{

if (rctngl != null &&

e.RightButton == MouseButtonState.Pressed)

{

DragDrop.DoDragDrop(

ellipseX, // drag source object

ellipseX.Fill, // dragged data object - brush

DragDropEffects.Copy); // first value for GiveFeedback query

}

}

29.12.2019 vjj 26

Drag target: DragEnterprivate void rectangleX_DragEnter(object sender, DragEventArgs e)

{

_previousRectangleFill = rectangleX.Fill;

if (e.Data.GetDataPresent("System.Windows.Media.SolidColorBrush"))

{

SolidColorBrush newFill =

(SolidColorBrush)e.Data.GetData("System.Windows.Media.SolidColorBrush");

rectangleX.Fill = newFill;

temporary = true;

}

}

29.12.2019 vjj 27

Drag target: DragLeaveprivate void rectangleX_DragLeave(object sender,

DragEventArgs e)

{

if (temporary)

{

rectangleX.Fill = _previousRectangleFill;

temporary = false;

}

}

29.12.2019 vjj 28

Drag target: Dropprivate void rectangleX_Drop(object sender, DragEventArgs e)

{

if (temporary)

temporary = false;

else if (e.Data.GetDataPresent("System.Windows.Media.SolidColorBrush"))

{

SolidColorBrush newFill =

(SolidColorBrush)e.Data.GetData("System.Windows.Media.SolidColorBrush");

rectangleX.Fill = newFill;

}

}

29.12.2019 vjj 29

IDataObject

shape

29.12.2019 vjj 30

setting dragged data objectprivate void rectangleX_MouseMove ( object sender, MouseEventArgs e )

{

if (e.RightButton == MouseButtonState.Pressed)

{

Rectangle rectangle = new Rectangle();

rectangle.Width = rectangleX.Width;

rectangle.Height = rectangleX.Height;

rectangle.Fill = rectangleX.Fill;

rectangle.Stroke = rectangleX.Stroke;

rectangle.StrokeThickness =

rectangleX.StrokeThickness;

DragDrop.DoDragDrop(rectangleX, // Drag-and-Drop Server object

rectangle, // Drag-and-Drop Data object

DragDropEffects.Copy);

}

}29.12.2019 vjj 31

Drag target: DragEnterprivate void stackX_DragEnter(object sender, DragEventArgs e)

{

if (e.Data.GetDataPresent("System.Windows.Shapes.Rectangle"))

{

Rectangle rectangle =

(Rectangle)e.Data.GetData("System.Windows.Shapes.Rectangle");

rectangle.Margin = new Thickness(5);

rectangle.VerticalAlignment = VerticalAlignment.Center;

stackX.Children.Add(rectangle);

temporary = true;

}

}

29.12.2019 vjj 32

Drag target: DragLeaveprivate void stackX_DragLeave(object sender, DragEventArgs e)

{

if (temporary)

{

int last = stackX.Children.Count - 1;

stackX.Children.RemoveAt(last);

temporary = false;

}

}

29.12.2019 vjj 33

Drag target: Dropprivate void stackX_Drop(object sender, DragEventArgs e)

{

if (inserted)

inserted = false;

else {

if (e.Data.GetDataPresent("System.Windows.Shapes.Rectangle"))

{

Rectangle rectangle =

(Rectangle)e.Data.GetData("System.Windows.Shapes.Rectangle");

rectangle.Margin = new Thickness(5);

rectangle.VerticalAlignment = VerticalAlignment.Center;

stackX.Children.Add(rectangle);

}

}

}

29.12.2019 vjj 34

DataObject

user object

29.12.2019 vjj 35

user objectclass UserObject {

public double Width;

public double Height;

public Brush Fill;

public Brush Stroke;

public double StrokeThickness;

public UserObject() {

this.Width = 10;

this.Height = 10;

this.Fill = new SolidColorBrush(Colors.Transparent);

this.Stroke = new SolidColorBrush(Colors.Transparent);

this.StrokeThickness = 0;

}

public override String ToString() {

return " UserObject ";

}

// Return a copy of this object by making a simple field copy.

public UserObject Copy() {

return (UserObject)this.MemberwiseClone();

}

}29.12.2019 vjj 36

start Drag-and-Dropprivate void rectangle_MouseMove ( object sender,

MouseEventArgs e)

{

if (e.MiddleButton == MouseButtonState.Pressed)

{

UserDragObject userObject = new UserDragObject();

userObject.Width = rectangleX.Width;

userObject.Height = rectangleX.Height;

userObject.Fill = rectangleX.Fill;

userObject.Stroke = rectangleX.Stroke;

userObject.StrokeThickness = rectangleX.StrokeThickness;

DataObject dataObject = new DataObject();

dataObject.SetData("UserObject", userObject);

DragDrop.DoDragDrop(rectangleX, // Drag-and-Drop Server object

dataObject, // Drag-and-Drop Data object

DragDropEffects.Copy);

}

}

29.12.2019 vjj 37

Drag target: DragEnterprivate void stackX_DragEnter(object sender, DragEventArgs e)

{

if (e.Data.GetDataPresent("UserObject"))

{

UserDragObject userObject = (UserObject)e.Data.GetData("UserObject");

Ellipse ellipse = new Ellipse();

ellipse.Width = userObject.Width;

ellipse.Height = userObject.Height;

ellipse.Fill = userObject.Fill;

ellipse.Stroke = userObject.Stroke;

ellipse.StrokeThickness = userObject.StrokeThickness;

ellipse.Margin = new Thickness(5);

ellipse.VerticalAlignment = VerticalAlignment.Center;

stack.Children.Add(ellipse);

temporary = true;

}

}

29.12.2019 vjj 38

Drag target: DragLeaveprivate void stackX_DragLeave(object sender,

DragEventArgs e)

{

if (temporary)

{

int last = stack.Children.Count - 1;

stack.Children.RemoveAt(last);

temporary = false;

}

}

29.12.2019 vjj 39

Drag target: Dropprivate void stackX_Drop(object sender, DragEventArgs e)

{

if (temporary)

temporary = false;

else {

if (e.Data.GetDataPresent("UserObject")) {

UserObject userObject = (UserObject)e.Data.GetData("UserObject");

Ellipse ellipse = new Ellipse();

ellipse.Width = userObject.Width;

ellipse.Height = userObject.Height;

ellipse.Fill = userObject.Fill;

ellipse.Stroke = userObject.Stroke;

ellipse.StrokeThickness = userObject.StrokeThickness;

ellipse.Margin = new Thickness(5);

ellipse.VerticalAlignment = VerticalAlignment.Center;

stack.Children.Add(ellipse);

}

}

}

29.12.2019 vjj 40

IDataObject

image file

29.12.2019 vjj 41

Drag target: DragEnterpublic static readonly List<string> ImageExtensions =

new List<string> { ".JPG", ".BMP", ".GIF", ".PNG" };

private void ellipseX_DragEnter(object sender, DragEventArgs e)

{

_previousEllipseFill = ellipseX.Fill;

if (e.Data.GetDataPresent("FileName"))

{

String fileName = "";

String[] filenames = (String[])e.Data.GetData("FileName");

foreach (String filename in filenames)

{

if

(ImageExtensions.Contains(System.IO.Path.GetExtension(filename).ToUpperInvariant()))

{

fileName = filename;

break;

}

}

29.12.2019 vjj 42

Drag target: DragEnterif (!String.IsNullOrEmpty(fileName))

{

// <ImageBrush ImageSource="d:\My Pictures\background.jpg" />

var bitmap = new BitmapImage();

bitmap.BeginInit();

var uri = new System.Uri(fileName, UriKind.Absolute);

bitmap.UriSource = uri;

bitmap.CacheOption = BitmapCacheOption.OnLoad;

bitmap.EndInit();

ImageSource imageSrc = bitmap;

ImageBrush bmpBrush = new ImageBrush();

bmpBrush.ImageSource = imageSrc;

ellipseX.Fill = bmpBrush;

temporary = true;

}

}

}

29.12.2019 vjj 43

Drag target: DragLeaveprivate void ellipseX_DragLeave( object sender,

DragEventArgs e )

{

if (temporary)

{

ellipseX.Fill = _previousEllipseFill;

temporary = false;

}

}

29.12.2019 vjj 44

Drag target: Dropprivate void ellipseX_Drop(object sender, DragEventArgs e)

{

if (temporary)

temporary = false;

else {

if (e.Data.GetDataPresent("FileName"))

{

String fileName = "";

String[] filenames = (String[])e.Data.GetData("FileName");

foreach (String filename in filenames)

{

if

(ImageExtensions.Contains(System.IO.Path.GetExtension(filename).ToUpperInvariant()))

{

fileName = filename;

break;

}

}

}

29.12.2019 vjj 45

Drag target: Dropif (!String.IsNullOrEmpty(fileName))

{

var bitmap = new BitmapImage();

bitmap.BeginInit();

var uri = new System.Uri(fileName, UriKind.Absolute);

bitmap.UriSource = uri;

bitmap.CacheOption = BitmapCacheOption.OnLoad;

bitmap.EndInit();

ImageSource imageSrc = bitmap;

ImageBrush bmpBrush = new ImageBrush();

bmpBrush.ImageSource = imageSrc;

newFill = (ImageBrush)bmpBrush;

ellipseX.Fill = newFill;

}

}

}

29.12.2019 vjj 46

top related