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:
<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>
Here's the DragBehavior:
#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
And the code:
#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
The drag adorner is the same except for the namespace.
This is all contained in a Main Window:
<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>