Page 1 of 1

problem in Register command

Posted: 19 Mar 2018, 04:22
by UE4
I want to register a custom command in UserControl, I implement it in WPF, but not work C++, some advices?
//command in WPF
		public static readonly DependencyProperty ButtonActionCommandProperty = DependencyProperty.Register(
			"Command", typeof(ICommand), typeof(TouchButton), new UIPropertyMetadata(null));

		public ICommand Command
		{
			get { return (ICommand)GetValue(ButtonActionCommandProperty); }
			set { SetValue(ButtonActionCommandProperty, value); }
		}
//Register command

/*UIData->RegisterProperty<Ptr<BaseCommand>>(CommandProperty, "Command",
		FrameworkPropertyMetadata::Create(Ptr<BaseCommand>(), FrameworkOptions_None));*/

	UIData->RegisterProperty<Ptr<BaseCommand>>(CommandProperty, "Command",
		UIPropertyMetadata::Create(Ptr<BaseCommand>()));

	/*UIData->RegisterProperty<Ptr<BaseComponent>>(CommandParameterProperty, "CommandParameter",
		FrameworkPropertyMetadata::Create(Ptr<BaseComponent>(), FrameworkOptions_None));*/

	UIData->RegisterProperty<Ptr<BaseComponent>>(CommandParameterProperty, "CommandParameter",
		UIPropertyMetadata::Create(Ptr<BaseComponent>()));


//Implemtent ICommand interface

Noesis::ICommand* TouchButton::GetCommand() const
{
	//return nullptr;
	return DependencyObject::GetValue<Ptr<ICommand>>(CommandProperty).GetPtr();
}

void GameGUI::TouchButton::SetCommand(BaseCommand* InCommand)
{
	DependencyObject::SetValue<Ptr<BaseCommand>>(CommandProperty, InCommand);
}

Noesis::BaseComponent* TouchButton::GetCommandParameter() const
{
	return DependencyObject::GetValue<Ptr<BaseComponent>>(CommandParameterProperty).GetPtr();
}

void TouchButton::SetCommandParameter(BaseComponent* InParam)
{
	DependencyObject::SetValue<Ptr<BaseComponent>>(CommandParameterProperty, InParam);
}

//Fire command

if (GetCommand())
		{
			//this line is called
			GetCommand()->Execute(GetCommandParameter());
		}

Re: problem in Register command

Posted: 19 Mar 2018, 16:10
by hcpizzi
Sorry for the late reply. What's exactly the problem? The only thing that I see missing is registering the property itself in your reflection code, like this:
NsProp("Command", & TouchButton::GetCommand, & TouchButton::SetCommand)
        .Meta<TypeConverterMetaData>("Converter<Command>");
 
Can you give that a try and let me know if that fixes it for you?

Re: problem in Register command

Posted: 19 Mar 2018, 18:51
by hcpizzi
I'm sorry, one of my colleagues has pointed out an error in your code. The types in the Get/Set functions are wrong. Try this:
  // Reflection code
    NsProp("Command", &TouchButton::GetCommand, &TouchButton::SetCommand)
        .Meta<TypeConverterMetaData>("Converter<Command>");

    Ptr<UIElementData> data = NsM88eta<UIElementData>(TypeOf<SelfClass>());
    data->RegisterProperty<Ptr<BaseComponent> >(CommandProperty, "Command",
        FrameworkPropertyMetadata::Create(Ptr<BaseComponent>(), FrameworkOptions_None));
    data->RegisterProperty<Ptr<BaseComponent> >(CommandParameterProperty, "CommandParameter",
        FrameworkPropertyMetadata::Create(Ptr<BaseComponent>(), FrameworkOptions_None));
        
   // Getter
 ICommand* TouchButton::GetCommand() const
{
    return NsDynamicCast<ICommand*>(GetValue<Ptr<BaseComponent> >(CommandProperty).GetPtr());
}

// Setter
void TouchButton::SetCommand(ICommand* command)
{
    SetValue<Ptr<BaseComponent> >(CommandProperty, command != 0 ?
        NsStaticCast<BaseComponent*>(command->GetBaseObject()) : 0);
}
Note that the type used is a BaseComponent, that is later cast to ICommand.

Re: problem in Register command

Posted: 20 Mar 2018, 00:48
by sfernandez
To simplify this code a lot you can derive your command from BaseCommand and make the property use the base type instead of BaseComponent:
data->RegisterProperty<Ptr<BaseCommand>>(CommandProperty, "Command", PropertyMetadata::Create(Ptr<BaseCommand>()));
I want to remark here that adding the property to reflection (NsProp) to register the Command converter is not necessary unless you want that property to be able to parse ApplicationCommands and ComponentCommands from xaml.

The property getter and setter will use both BaseCommand also:
BaseCommand* TouchButton::GetCommand() const
{
  return GetValue<Ptr<BaseCommand>>(CommandProperty);
}
void TouchButton::SetCommand(BaseCommand* command)
{
  SetValue<Ptr<BaseCommand>>(CommandProperty, command);
}
Then you can execute the command like this:
BaseCommand* command = GetCommand();
BaseComponent* param = GetCommandParameter();
if (command->CanExecute(param))
{
  command->Execute(param);
}

Re: problem in Register command

Posted: 20 Mar 2018, 04:31
by UE4
Thanks, now it works as I expected.

Re: problem in Register command

Posted: 20 Mar 2018, 04:34
by jsantos
You welcome! Marking as solved

Re: problem in Register command

Posted: 22 Mar 2018, 11:20
by UE4
Can you make more explanation about NsProp?
the Command or BaseCommand is a DependencyProperty, same as WidthProperty? BackgroundProperty?
why does Command need a NsProp? why doesn't others?

Re: problem in Register command

Posted: 27 Mar 2018, 10:28
by jsantos
If you want to support built-in commands, then you need to add a converter for the property. For example, to properly convert the string "ApplicationCommands.Copy" to a valid command. Right now, we only support adding converters to reflection properties, not to dependencies properties. This is exactly the same as in C#, and probably a bit confusing. You can avoid it at all, I don't think you need it.
NsProp("Command", &TouchButton::GetCommand, &TouchButton::SetCommand)
    .Meta<TypeConverterMetaData>("Converter<Command>");