Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
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