Troubleshooting Drag and Drop?
Do you have any suggestions for troubleshooting Drag and Drop? I'm using version 2.
Function are being called on the view model, the behavior, and the adorner. But nothing visually changes.
I simplified the inventory example down to a very simplified form and using that with a hard coded image rect for testing.
Function are being called on the view model, the behavior, and the adorner. But nothing visually changes.
I simplified the inventory example down to a very simplified form and using that with a hard coded image rect for testing.
-
sfernandez
Site Admin
- Posts: 3014
- Joined:
Re: Troubleshooting Drag and Drop?
The drag and drop behaviors provide the connection between the drag events and the commands you expose in your view model. And DragAdornerBehavior just notifies about the mouse position when dragging. But none of the behaviors will directly change anything related to the rendering, that would be the consequence of changing properties in the view model when drag commands are executed and the UI bindings to the view model properties.
To better understand the process of drag and drop you should probably start with a simple example with just 2 slots and 1 item you can move between them.
The view model will expose 3 commands for StartDrag, EndDrag and DropItem, and also properties for Slot1, Slot2 and DraggedItem.
You should set the DragItemBehavior and DropItemBehavior on the slot UI controls. And DragAdornerBehavior should be set on the root of your UI to receive all mouse events when dragging.
When the drag commands are called (the order of execution will be: StartDrag, DropItem and EndDrag, receiving as command parameter the DataContext of the control where the drag/drop behaviors are set) you should update the view model properties accordingly, and UI bindings will do the rest.
For example, if you initially have an item in slot 1, and start dragging from there, you should set Slot1 to null, DraggingItem to the item. When dropping the item in slot 2 you should set DraggingItem to null and Slot2 to the item.
Please let me know if you need further help with any specific part.
To better understand the process of drag and drop you should probably start with a simple example with just 2 slots and 1 item you can move between them.
The view model will expose 3 commands for StartDrag, EndDrag and DropItem, and also properties for Slot1, Slot2 and DraggedItem.
You should set the DragItemBehavior and DropItemBehavior on the slot UI controls. And DragAdornerBehavior should be set on the root of your UI to receive all mouse events when dragging.
When the drag commands are called (the order of execution will be: StartDrag, DropItem and EndDrag, receiving as command parameter the DataContext of the control where the drag/drop behaviors are set) you should update the view model properties accordingly, and UI bindings will do the rest.
For example, if you initially have an item in slot 1, and start dragging from there, you should set Slot1 to null, DraggingItem to the item. When dropping the item in slot 2 you should set DraggingItem to null and Slot2 to the item.
Please let me know if you need further help with any specific part.
Re: Troubleshooting Drag and Drop?
I have reduced the example to the minimal set of operations to get drag working, and then modified my code to match the example.
All of that seems to be working. I just cannot get the Drag Panel to display or move. The Drag X and Y are getting set and the DraggedItem contains a valid rectangle and is being accessed, but nothing happens with the Drag Panel.
All of that seems to be working. I just cannot get the Drag Panel to display or move. The Drag X and Y are getting set and the DraggedItem contains a valid rectangle and is being accessed, but nothing happens with the Drag Panel.
-
sfernandez
Site Admin
- Posts: 3014
- Joined:
Re: Troubleshooting Drag and Drop?
In our inventory sample we have a Grid filling the entire screen named "DragPanel", inside that panel we put a ContentControl with its Content property bound to the DraggedItem property of the view model, so when dragging starts and view model sets that property to the corresponding item, the item will be rendered on top of everything. The position of that dragging item is specified by binding to the DraggedItemX and DraggedItemY properties of the DragAdornerBehavior set on the root element.
If you attach here your xaml and viewmodel I can take a look to see what could be failing in your setup.
If you attach here your xaml and viewmodel I can take a look to see what could be failing in your setup.
Re: Troubleshooting Drag and Drop?
Here is my XAML.. it's a Page instead of a Window.
Code: Select all
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SimLabs"
x:Name="Root"
x:Class="SimLabs.StageEdit"
Title="Stage Edit" Width="1280" Height="720">
<Page.Resources>
<local:CourseDataObject x:Name="CourseData"/>
</Page.Resources>
<i:Interaction.Behaviors>
<local:DragAdornerBehavior x:Name="DragAdorner"/>
</i:Interaction.Behaviors>
<StackPanel>
<WrapPanel HorizontalAlignment="Center" Margin="0,4,0,6">
<Button x:Name="DeleteButton" Click="OnDeleteClick">Delete target</Button>
<Button x:Name="EditTargetButton" Click="OnEditTargetClick">Edit target</Button>
<Button x:Name="BackButton" Click="OnBackClick">Back</Button>
<Button x:Name="CenterHorizontallyButton" Width="24" Height="24" Click="OnCenterHorizontallyClick" Padding="0">
<Image Source="Icons\CenterXIcon.png"/>
</Button>
<Button x:Name="CenterVerticallyButton" Width="24" Height="24" Click="OnCenterVerticallyClick" Padding="0">
<Image Source="Icons\CenterYIcon.png"/>
</Button>
<Button x:Name="LeftEdgeButton" Width="24" Height="24" Click="OnLeftEdgeClick" Padding="0">
<Image Source="Icons\LeftEdgeIcon.png"/>
</Button>
<Button x:Name="RightEdgeButton" Width="24" Height="24" Click="OnRightEdgeClick" Padding="0">
<Image Source="Icons\RightEdgeIcon.png"/>
</Button>
<Button x:Name="TopEdgeButton" Width="24" Height="24" Click="OnTopEdgeClick" Padding="0">
<Image Source="Icons\TopEdgeIcon.png"/>
</Button>
<Button x:Name="BottomEdgeButton" Width="24" Height="24" Click="OnBottomEdgeClick" Padding="0">
<Image Source="Icons\BottomEdgeIcon.png"/>
</Button>
</WrapPanel>
<WrapPanel HorizontalAlignment="Center" Margin="0,4,0,6">
<TextBlock HorizontalAlignment="Center" Foreground="#FFFFFF">Position:</TextBlock>
<TextBox x:Name="PositionX" Width="100" TextChanged="OnXChange"/>
<TextBox x:Name="PositionY" Width="100" TextChanged="OnYChange"/>
<TextBlock HorizontalAlignment="Center" Foreground="#FFFFFF">Distance:</TextBlock>
<TextBox x:Name="Distance" Width="100" Margin="10,0,0,0" TextChanged="OnDistanceChange"/>
<ComboBox x:Name="Units" Width="100" Margin="0,4,0,4" SelectionChanged="OnUnitsChange">
<ComboBoxItem>Inches</ComboBoxItem>
<ComboBoxItem>Feet</ComboBoxItem>
<ComboBoxItem>Yards</ComboBoxItem>
<ComboBoxItem>Centimeter</ComboBoxItem>
<ComboBoxItem>Meter</ComboBoxItem>
</ComboBox>
</WrapPanel>
<WrapPanel HorizontalAlignment="Center" Margin="0,4,0,6" Width="1280" Height="512">
<TabControl x:Name="Resources" Width="300" Height="512">
<TabItem Header="Targets">
<Grid>
<ListBox x:Name="TargetImages" Width="300" ItemsSource="{Binding Children, Source={StaticResource CourseData}, Path=TargetImages}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path}" Margin="0" Width="100" Height="166">
<i:Interaction.Behaviors>
<local:TargetDragBehavior StartDragCommand="{Binding Source={StaticResource CourseData}, Path=StartTargetDrag, ElementName=Root}" EndDragCommand="{Binding Source={StaticResource CourseData}, Path=EndTargetDrag, ElementName=Root}"/>
</i:Interaction.Behaviors>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid x:Name="DragPanel">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.05*"/>
<ColumnDefinition Width="0.95*"/>
</Grid.ColumnDefinitions>
<Decorator x:Name="DragItemRef"/>
<ContentControl Content="{Binding Source={StaticResource CourseData}, Path=DraggedItem}" HorizontalAlignment="Left" VerticalAlignment="Top"
Width="{Binding ActualWidth, ElementName=DragItemRef}" Height="{Binding ActualWidth, ElementName=DragItemRef}" Style="{StaticResource Style.DraggedItem}">
<ContentControl.RenderTransform>
<TranslateTransform X="{Binding DraggedItemX, ElementName=DragAdorner}" Y="{Binding DraggedItemY, ElementName=DragAdorner}"/>
</ContentControl.RenderTransform>
</ContentControl>
</Grid>
</Grid>
</TabItem>
<TabItem Header="Backgrounds">
<ListBox x:Name="BackgroundImages" Width="300" ItemsSource="{Binding Children, Source={StaticResource CourseData}, Path=BackgroundImages}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path}" Margin="0" Width="200" Height="113">
<i:Interaction.Behaviors>
<local:BackgroundDragBehavior StartDragCommand="{Binding Source={StaticResource CourseData}, Path=StartBackgroundDrag, ElementName=Root}" EndDragCommand="{Binding Source={StaticResource CourseData}, Path=EndBackgroundDrag, ElementName=Root}"/>
</i:Interaction.Behaviors>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</TabItem>
<TabItem Header="Objects">
<ListBox x:Name="ObjectImages" Width="300" ItemsSource="{Binding Children, Source={StaticResource CourseData}, Path=ObjectImages}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path}" Margin="0" Width="280" Height="166">
<i:Interaction.Behaviors>
<local:ObjectDragBehavior StartDragCommand="{Binding Source={StaticResource CourseData}, Path=StartObjectDrag, ElementName=Root}" EndDragCommand="{Binding Source={StaticResource CourseData}, Path=EndObjectDrag, ElementName=Root}"/>
</i:Interaction.Behaviors>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</TabItem>
</TabControl>
<local:SceneView x:Name="SceneView" Stretch="Uniform" Focusable="True">
<local:SceneView.ContextMenu>
<ContextMenu>
<MenuItem x:Name="CenterHorizontallyMenu" Header="Center horizontally" Click="OnCenterHorizontallyMenu"/>
<MenuItem x:Name="CenterVerticallyMenu" Header="Center vertically" Click="OnCenterVerticallyMenu"/>
<MenuItem x:Name="MoveToLeftMenu" Header="Move to left edge" Click="OnLeftEdgeMenu"/>
<MenuItem x:Name="MoveToRightMenu" Header="Move to right edge" Click="OnRightEdgeMenu"/>
<MenuItem x:Name="MoveToTopMenu" Header="Move to top edge" Click="OnTopEdgeMenu"/>
<MenuItem x:Name="MoveToBottomMenu" Header="Move to bottom edge" Click="OnBottomEdgeMenu"/>
<Separator x:Name="SeparatorMenu"/>
<MenuItem x:Name="EditTargetMenu" Header="Edit target" Click="OnEditTargetMenu"/>
<MenuItem x:Name="DuplicateTargetMenu" Header="Duplicate target" Click="OnDuplicateTargetMenu"/>
<MenuItem x:Name="DeleteTargetMenu" Header="Delete target" Click="OnDeleteTargetMenu"/>
</ContextMenu>
</local:SceneView.ContextMenu>
<i:Interaction.Behaviors>
<local:SceneDropBehavior/>
</i:Interaction.Behaviors>
</local:SceneView>
<StackPanel VerticalAlignment="Top" Width="32">
<Button x:Name="UpButton" Width="16" Height="16" Click="OnUpButton" Padding="0">
<Image Source="Icons\MoveUpIcon.png"/>
</Button>
<Button x:Name="DownButton" Width="16" Height="16" Click="OnDownButton" Padding="0">
<Image Source="Icons\MoveDownIcon.png"/>
</Button>
<Button x:Name="DuplicateButton" Width="16" Height="16" Click="OnDuplicateButton" Padding="0">
<Image Source="Icons\DuplicateIcon.png"/>
</Button>
<Button x:Name="DeleteButton" Width="16" Height="16" Click="OnDeleteButton" Padding="0">
<Image Source="Icons\DeleteIcon.png"/>
</Button>
</StackPanel>
</WrapPanel>
</StackPanel>
</Page>
Re: Troubleshooting Drag and Drop?
Here is relevent part of the View Model header:
And the code:
Code: Select all
#pragma once
#include <NsApp/DelegateCommand.h>
#include <NsCore/Noesis.h>
#include <NsCore/ReflectionImplement.h>
#include <NsDrawing/Rect.h>
#include <NsGui/ImageSource.h>
#include <NsGui/ObservableCollection.h>
#include <NsGui/ResourceDictionary.h>
#include "BackgroundImageList.h"
#include "Macros.h"
#include "ObjectImageList.h"
#include "SoundList.h"
#include "TargetImageList.h"
using namespace Noesis;
NAMESPACE(SimLabs)
class Item : public Noesis::BaseComponent
{
public:
Noesis::Rect m_icon; // Icon rect
Item()
{
m_icon.x = 0;
m_icon.y = 0;
m_icon.width = 62;
m_icon.height = 62;
}
private:
NS_DECLARE_REFLECTION(Item, BaseComponent)
};
class NotifierBase: public Noesis::BaseComponent, public Noesis::INotifyPropertyChanged
{
public:
SUPER(BaseComponent)
Noesis::PropertyChangedEventHandler& PropertyChanged() final;
NS_IMPLEMENT_INTERFACE_FIXUP
protected:
void OnPropertyChanged(const char* _propertyName);
private:
Noesis::PropertyChangedEventHandler m_changed;
NS_DECLARE_REFLECTION(NotifierBase, BaseComponent)
};
class CourseDataObject : public NotifierBase
{
public:
SUPER(NotifierBase)
// Constructor
CourseDataObject();
// Destructor
~CourseDataObject();
// Get start target drag
NoesisApp::DelegateCommand* GetStartTargetDrag() const;
// Get end target drag
NoesisApp::DelegateCommand* GetEndTargetDrag() const;
// Get dragged item
Item* GetDraggedItem() const;
// Set dragged item info
void setDraggedItemInfo(Noesis::Rect _imageRect);
private:
NS_IMPLEMENT_INLINE_REFLECTION(CourseDataObject, NotifierBase)
{
NsMeta<TypeId>("SimLabs.CourseDataObject");
NsProp("StartTargetDrag", &CourseDataObject::GetStartTargetDrag);
NsProp("EndTargetDrag", &CourseDataObject::GetEndTargetDrag);
NsProp("DraggedItem", &CourseDataObject::GetDraggedItem);
}
Noesis::Ptr<Item> m_pDraggedItem; // Dragged item
Noesis::Ptr<NoesisApp::DelegateCommand> m_pStartTargetDrag; // Start target drag
Noesis::Ptr<NoesisApp::DelegateCommand> m_pEndTargetDrag; // End target drag
// On can start target drag
bool OnCanStartTargetDrag(Noesis::BaseComponent* _pParam);
// On start target drag
void OnStartTargetDrag(Noesis::BaseComponent* _pParam);
// On end target drag
void OnEndTargetDrag(Noesis::BaseComponent* _pParam);
};
ENDNAMESPACE
Code: Select all
#include <NsGui/INotifyPropertyChanged.h>
#include <NsGui/IntegrationAPI.h>
#include "CourseData.h"
#include "Log.h"
#include "System.h"
using namespace Noesis;
NAMESPACE(SimLabs)
PropertyChangedEventHandler& NotifierBase::PropertyChanged()
{
return m_changed;
}
void NotifierBase::OnPropertyChanged(const char* _propertyName)
{
if (false == m_changed.Empty())
{
NsSymbol propId(_propertyName);
m_changed(this, PropertyChangedEventArgs(propId));
}
}
CourseDataObject::CourseDataObject()
{
m_pDraggedItem = *new Item();
m_pStartTargetDrag = MakePtr<DelegateCommand>(MakeDelegate(this, &CourseDataObject::OnCanStartTargetDrag), MakeDelegate(this, &CourseDataObject::OnStartTargetDrag));
m_pEndTargetDrag = MakePtr<DelegateCommand>(MakeDelegate(this,&CourseDataObject::OnEndTargetDrag));
}
CourseDataObject::~CourseDataObject()
{
}
NoesisApp::DelegateCommand* CourseDataObject::GetStartTargetDrag() const
{
return m_pStartTargetDrag;
}
NoesisApp::DelegateCommand* CourseDataObject::GetEndTargetDrag() const
{
return m_pEndTargetDrag;
}
Item* CourseDataObject::GetDraggedItem() const
{
return m_pDraggedItem;
}
void CourseDataObject::setDraggedItemInfo(Noesis::Rect _imageRect)
{
if (m_pDraggedItem != nullptr)
{
m_pDraggedItem->m_icon = _imageRect;
}
}
bool CourseDataObject::OnCanStartTargetDrag(Noesis::BaseComponent* _pParam)
{
return true;
}
void CourseDataObject::OnStartTargetDrag(Noesis::BaseComponent* _pParam)
{
setDraggedItemInfo(Noesis::Rect(0.0f, 0.0f, 62.0f, 62.0f));
OnPropertyChanged("DraggedItem");
}
void CourseDataObject::OnEndTargetDrag(Noesis::BaseComponent* _pParam)
{
OnPropertyChanged("DraggedItem");
}
NS_IMPLEMENT_REFLECTION(NotifierBase)
{
NsImpl<INotifyPropertyChanged>();
}
NS_IMPLEMENT_REFLECTION(Item)
{
NsProp("Icon", &Item::m_icon);
}
ENDNAMESPACE
Re: Troubleshooting Drag and Drop?
The Resources info has been split into different parts:
I'm using the default InventoryAtlas,png for testing. It's located in an Image folder under the folder containing the UI. I'm also hard coding the image atlas rect to 0, 0, 62, 62 for testing.
Here's the template and Style info:
Here's the DragBehavior:
And the code:
The drag adorner is the same except for the namespace.
This is all contained in a Main Window:
I'm using the default InventoryAtlas,png for testing. It's located in an Image folder under the folder containing the UI. I'm also hard coding the image atlas rect to 0, 0, 62, 62 for testing.
Here's the template and Style info:
Code: Select all
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SimLabs">
<ControlTemplate x:Key="Template.DraggedItem" TargetType="{x:Type ContentControl}">
<Rectangle Width="62" Height="62" Margin="0">
<Rectangle.RenderTransform>
<TransformGroup>
<TranslateTransform X="-31" Y="-31"/>
</TransformGroup>
</Rectangle.RenderTransform>
<Rectangle.Fill>
<ImageBrush ImageSource="Images/InventoryAtlas.png" Stretch="Fill" ViewboxUnits="Absolute" Viewbox="{Binding Content.Icon, RelativeSource={RelativeSource TemplatedParent}}"/>
</Rectangle.Fill>
</Rectangle>
<ControlTemplate.Triggers>
<Trigger Property="Content" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="Style.DraggedItem" TargetType="{x:Type ContentControl}">
<Setter Property="Template" Value="{StaticResource Template.DraggedItem}"/>
</Style>
</ResourceDictionary>
Code: Select all
#pragma once
#include "DragBehavior.h"
#include "Macros.h"
NAMESPACE(SimLabs)
class TargetDragBehavior : public DragBehavior
{
public:
SUPER(DragBehavior)
static const Noesis::DependencyProperty* DragStartOffsetProperty;
static const Noesis::DependencyProperty* StartDragCommandProperty;
static const Noesis::DependencyProperty* EndDragCommandProperty;
// Constructor
TargetDragBehavior();
// Destructor
~TargetDragBehavior();
// Get drag start offset
const Noesis::Point& GetDragStartOffset() const;
// Set drag start offset
void SetDragStartOffset(const Noesis::Point& _offset);
// Get start drag command
Noesis::BaseCommand* GetStartDragCommand() const;
// Set start drag command
void SetStartDragCommand(Noesis::BaseCommand* _pCommand);
// Get end drag drag command
Noesis::BaseCommand* GetEndDragCommand() const;
// Set end drag drag command
void SetEndDragCommand(Noesis::BaseCommand* _pCommand);
protected:
// Create instance core
Noesis::Ptr<Freezable> CreateInstanceCore() const override;
// On attached
void OnAttached() override;
// On detached
void OnDetaching() override;
// On give feedback
void OnGiveFeedback(Noesis::BaseComponent* _pSender, const Noesis::GiveFeedbackEventArgs& _event);
// On mouse down
void OnMouseDown(Noesis::BaseComponent* _pSender, const Noesis::MouseButtonEventArgs& _event);
// On mouse up
void OnMouseUp(Noesis::BaseComponent* _pSender, const Noesis::MouseButtonEventArgs& _event);
// On mouse move
void OnMouseMove(Noesis::BaseComponent* _pSender, const Noesis::MouseEventArgs& _event);
private:
NS_DECLARE_REFLECTION(TargetDragBehavior, Behavior)
};
ENDNAMESPACE
Code: Select all
#include <NsCore/Delegate.h>
#include <NsDrawing/Rect.h>
#include <NsGui/BaseCommand.h>
#include <NsGui/DragDrop.h>
#include <NsGui/PropertyMetadata.h>
#include <NsGui/UIElementData.h>
#include "System.h"
#include "TargetDragBehavior.h"
using namespace Noesis;
NAMESPACE(SimLabs)
TargetDragBehavior::TargetDragBehavior()
{
}
TargetDragBehavior::~TargetDragBehavior()
{
}
const Noesis::Point& TargetDragBehavior::GetDragStartOffset() const
{
return GetValue<Point>(DragStartOffsetProperty);
}
void TargetDragBehavior::SetDragStartOffset(const Noesis::Point& _offset)
{
SetValue<Point>(DragStartOffsetProperty, _offset);
}
Noesis::BaseCommand* TargetDragBehavior::GetStartDragCommand() const
{
return GetValue<Ptr<BaseCommand>>(StartDragCommandProperty);
}
void TargetDragBehavior::SetStartDragCommand(Noesis::BaseCommand* _pCommand)
{
SetValue<Ptr<BaseCommand>>(StartDragCommandProperty, _pCommand);
}
Noesis::BaseCommand* TargetDragBehavior::GetEndDragCommand() const
{
return GetValue<Ptr<BaseCommand>>(EndDragCommandProperty);
}
void TargetDragBehavior::SetEndDragCommand(Noesis::BaseCommand* _pCommand)
{
SetValue<Ptr<BaseCommand>>(EndDragCommandProperty, _pCommand);
}
Noesis::Ptr<Noesis::Freezable> TargetDragBehavior::CreateInstanceCore() const
{
return *new TargetDragBehavior();
}
void TargetDragBehavior::OnAttached()
{
ParentClass::OnAttached();
FrameworkElement* pElement = GetAssociatedObject();
pElement->GiveFeedback() += MakeDelegate(this, &TargetDragBehavior::OnGiveFeedback);
pElement->PreviewMouseLeftButtonDown() += MakeDelegate(this, &TargetDragBehavior::OnMouseDown);
pElement->PreviewMouseLeftButtonUp() += MakeDelegate(this, &TargetDragBehavior::OnMouseUp);
pElement->PreviewMouseMove() += MakeDelegate(this, &TargetDragBehavior::OnMouseMove);
}
void TargetDragBehavior::OnDetaching()
{
FrameworkElement* pElement = GetAssociatedObject();
pElement->GiveFeedback() -= MakeDelegate(this, &TargetDragBehavior::OnGiveFeedback);
pElement->PreviewMouseLeftButtonDown() -= MakeDelegate(this, &TargetDragBehavior::OnMouseDown);
pElement->PreviewMouseLeftButtonUp() -= MakeDelegate(this, &TargetDragBehavior::OnMouseUp);
pElement->PreviewMouseMove() -= MakeDelegate(this, &TargetDragBehavior::OnMouseMove);
ParentClass::OnDetaching();
}
void TargetDragBehavior::OnGiveFeedback(Noesis::BaseComponent* _pSender, const Noesis::GiveFeedbackEventArgs& _event)
{
_event.useDefaultCursors = false;
_event.handled = true;
}
void TargetDragBehavior::OnMouseDown(Noesis::BaseComponent* _pSender, const Noesis::MouseButtonEventArgs& _event)
{
m_bMouseClicked = true;
SimLabs::CourseDataObject* pCourseData = System::getCourseData();
if (pCourseData != NULL)
{
Noesis::Image* pImage = reinterpret_cast<Noesis::Image*>(_pSender);
if (pImage != NULL)
{
pCourseData->setDraggedItemInfo(Noesis::Rect(0.0f, 0.0f, 62.0f, 62.0f));
}
}
}
void TargetDragBehavior::OnMouseUp(Noesis::BaseComponent* _pSender, const Noesis::MouseButtonEventArgs& _event)
{
m_bMouseClicked = false;
}
void TargetDragBehavior::OnMouseMove(Noesis::BaseComponent* _pSender, const Noesis::MouseEventArgs& _event)
{
if (true == m_bMouseClicked)
{
m_bMouseClicked = false;
FrameworkElement* pElement = GetAssociatedObject();
if (pElement != NULL)
{
BaseComponent* pItem = pElement->GetDataContext();
if (pItem != NULL)
{
BaseCommand* pStartDrag = GetStartDragCommand();
if (pStartDrag != NULL && true == pStartDrag->CanExecute(pItem))
{
SetDragStartOffset(pElement->PointFromScreen(_event.position));
pStartDrag->Execute(pItem);
}
DragDrop::DoDragDrop(pElement, pItem, DragDropEffects_Move, [this](DependencyObject*, BaseComponent*, UIElement*, const Point&, uint32_t _effects)
{
Ptr<BaseComponent> dragSuccess = Boxing::Box<bool>(_effects != DragDropEffects_None);
BaseCommand* pEndDrag = GetEndDragCommand();
if (pEndDrag != NULL && true == pEndDrag->CanExecute(dragSuccess))
{
pEndDrag->Execute(dragSuccess);
}
});
}
}
}
}
NS_BEGIN_COLD_REGION
NS_IMPLEMENT_REFLECTION(TargetDragBehavior)
{
NsMeta<TypeId>("SimLabs.TargetDragBehavior");
UIElementData* pData = NsMeta<UIElementData>(TypeOf<SelfClass>());
pData->RegisterProperty<Point>(DragStartOffsetProperty, "DragStartOffset", PropertyMetadata::Create(Point(0.0f, 0.0f)));
pData->RegisterProperty<Ptr<BaseCommand>>(StartDragCommandProperty, "StartDragCommand", PropertyMetadata::Create(Ptr<BaseCommand>()));
pData->RegisterProperty<Ptr<BaseCommand>>(EndDragCommandProperty, "EndDragCommand", PropertyMetadata::Create(Ptr<BaseCommand>()));
}
const Noesis::DependencyProperty* TargetDragBehavior::DragStartOffsetProperty;
const Noesis::DependencyProperty* TargetDragBehavior::StartDragCommandProperty;
const Noesis::DependencyProperty* TargetDragBehavior::EndDragCommandProperty;
ENDNAMESPACE
This is all contained in a Main Window:
Code: Select all
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SimLabs"
x:Class="SimLabs.MainWindow"
Background="{StaticResource WindowBackground}"
Title="Open Range" Width="1280" Height="720">
<Grid>
<local:InstructionEdit x:Name="InstructionEdit" Visibility="Hidden"/>
<local:MediaSelection x:Name="MediaSelection" Visibility="Hidden"/>
<local:StageEdit x:Name="StageEdit" Visibility="Hidden"/>
<local:StageSelection x:Name="StageSelection" Visibility="Hidden"/>
<local:TargetEdit x:Name="TargetEdit" Visibility="Hidden"/>
<local:CourseSelection x:Name="CourseSelection"/>
<Border x:Name="ConfirmationDialog" Background="{StaticResource WindowBackground}" CornerRadius="6" BorderBrush="Gray" BorderThickness="2" Padding="8" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">
<StackPanel VerticalAlignment="Center" MaxWidth="1200">
<TextBlock x:Name="ConfirmationMessage" HorizontalAlignment="Center" Foreground="#FFFFFF" Margin="0,4,0,10">Message</TextBlock>
<WrapPanel HorizontalAlignment="Center" Margin="0,10,0,4">
<Button x:Name="ConfirmationYesButton" Click="OnYesClick" Margin="4,0,4,0">Yes</Button>
<Button x:Name="ConfirmationNoButton" Click="OnNoClick" Margin="4,0,4,0">No</Button>
</WrapPanel>
</StackPanel>
</Border>
<Border x:Name="InfoDialog" Background="{StaticResource WindowBackground}" CornerRadius="6" BorderBrush="Gray" BorderThickness="2" Padding="8" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">
<StackPanel VerticalAlignment="Center" MaxWidth="1200">
<TextBlock x:Name="InfoMessage" HorizontalAlignment="Center" Foreground="#FFFFFF" Margin="0,4,0,10">Message</TextBlock>
<Button x:Name="InfoButton" Click="OnInfoButtonClick" Margin="4,0,4,0">OK</Button>
</StackPanel>
</Border>
<Border x:Name="InputDialog" Background="{StaticResource WindowBackground}" CornerRadius="6" BorderBrush="Gray" BorderThickness="2" Padding="8" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">
<StackPanel VerticalAlignment="Center" MaxWidth="1200">
<TextBlock x:Name="InputMessage" HorizontalAlignment="Center" Foreground="#FFFFFF" Margin="0,4,0,10">Message</TextBlock>
<TextBox x:Name="InputText" Foreground="#FFFFFF" Margin="0,4,0,10"/>
<WrapPanel HorizontalAlignment="Center" Margin="0,10,0,4">
<Button x:Name="ConfirmationOKButton" Click="OnOKClick" Margin="4,0,4,0">OK</Button>
<Button x:Name="ConfirmationCancelButton" Click="OnCancelClick" Margin="4,0,4,0">Cancel</Button>
</WrapPanel>
</StackPanel>
</Border>
</Grid>
</Window>
-
sfernandez
Site Admin
- Posts: 3014
- Joined:
Re: Troubleshooting Drag and Drop?
Thanks for all the files, I understand now what is happening. The DragAdornerBehavior was designed to be set on the root of the UI (in your window), but looking at your files I see the possibilities of allowing localized drag&drop in a setup like yours. In order to achieve that the adorner behavior needs to hook to the events of root element instead of its associated object:
Please try with that modified adorner behavior and let me know if it is working as expected.
Code: Select all
class DragAdornerBehavior final: public NoesisApp::BehaviorT<Noesis::FrameworkElement>
{
public:
const Noesis::Point& GetDragStartOffset() const;
void SetDragStartOffset(const Noesis::Point& offset);
float GetDraggedItemX() const;
float GetDraggedItemY() const;
public:
static const Noesis::DependencyProperty* DragStartOffsetProperty;
static const Noesis::DependencyProperty* DraggedItemXProperty;
static const Noesis::DependencyProperty* DraggedItemYProperty;
protected:
Noesis::Ptr<Freezable> CreateInstanceCore() const override;
void OnAttached() override;
void OnDetaching() override;
private:
void OnLoaded(Noesis::BaseComponent* sender, const Noesis::RoutedEventArgs& e);
void OnUnloaded(Noesis::BaseComponent* sender, const Noesis::RoutedEventArgs& e);
void OnDragOver(Noesis::BaseComponent* sender, const Noesis::DragEventArgs& e);
void OnDrop(Noesis::BaseComponent* sender, const Noesis::DragEventArgs& e);
void SetDraggedItemX(float x);
void SetDraggedItemY(float y);
private:
Noesis::FrameworkElement* mRoot;
NS_DECLARE_REFLECTION(DragAdornerBehavior, Behavior)
};
Code: Select all
DragAdornerBehavior::DragAdornerBehavior(): mRoot(nullptr)
{
}
...
void DragAdornerBehavior::OnAttached()
{
ParentClass::OnAttached();
FrameworkElement* element = GetAssociatedObject();
element->Loaded() += MakeDelegate(this, &DragAdornerBehavior::OnLoaded);
element->Unloaded() += MakeDelegate(this, &DragAdornerBehavior::OnUnloaded);
}
void DragAdornerBehavior::OnDetaching()
{
FrameworkElement* element = GetAssociatedObject();
element->Loaded() -= MakeDelegate(this, &DragAdornerBehavior::OnLoaded);
element->Unloaded() -= MakeDelegate(this, &DragAdornerBehavior::OnUnloaded);
ParentClass::OnDetaching();
}
void DragAdornerBehavior::OnLoaded(BaseComponent*, const RoutedEventArgs&)
{
mRoot = GetAssociatedObject()->GetView()->GetContent();
mRoot->SetAllowDrop(true);
mRoot->DragOver() += MakeDelegate(this, &DragAdornerBehavior::OnDragOver);
mRoot->Drop() += MakeDelegate(this, &DragAdornerBehavior::OnDrop);
}
void DragAdornerBehavior::OnUnloaded(BaseComponent*, const RoutedEventArgs&)
{
mRoot->ClearLocalValue(UIElement::AllowDropProperty);
mRoot->DragOver() -= MakeDelegate(this, &DragAdornerBehavior::OnDragOver);
mRoot->Drop() -= MakeDelegate(this, &DragAdornerBehavior::OnDrop);
mRoot = nullptr;
}
...
Re: Troubleshooting Drag and Drop?
Yes.. that did fix it. Or at least enough to start fixing it. Thank you.
Re: Troubleshooting Drag and Drop?
Thank you, marking as solved
Who is online
Users browsing this forum: Ahrefs [Bot], Semrush [Bot] and 2 guests