Joren
Topic Author
Posts: 18
Joined: 12 Nov 2019, 15:33

Dependency property that expects list of integers in c++

26 Feb 2020, 11:23

I want to be able to assign a list of integers to a dependency property, as done here:
<Button Content="TEST" ui:KeyTriggerExtension.Key="179, 168, 23"/>
This works perfectly fine in blend using C# with this sample:
  public class KeyTriggerExtension
  {
    public static readonly DependencyProperty Key = DependencyProperty.RegisterAttached("Key", typeof(List<int>), typeof(KeyTriggerExtension), new PropertyMetadata(default(List<int>)));

    public static void SetKey(DependencyObject element, List<int> value)
    {
      element.SetValue(Key, value);
    }

    public static List<int> GetKey(DependencyObject element)
    {
      return (List<int>)element.GetValue(Key);
    }
However, I have trouble converting this to C++ because of the following reasons, please correct me if I'm wrong in one of the following statements:
  • I can't use a generic type of std list/vector with Noesis (in C# I use a generic list)
  • I can use Collection or Observable collection, but the type needs to be atleast a BaseComponent
  • I can Box/Unbox the integers if I use a list of BaseComponents
So yeah, I'm trying that but I can't get it to work with the snippet below, I will get the error " '179, 168, 23' is not a valid value for property Button.Key.". Which makes sense because I completely lost any definition of the integer, so I can imagine that it doesn't understand how to convert those values.
class TGCNoesisKeyTriggerExtension : public Noesis::DependencyObject
{
public:
  void                                                        SetKey(Noesis::ObservableCollection<Noesis::BaseComponent>* pValue);
  Noesis::ObservableCollection<Noesis::BaseComponent>*        GetKey();
  static void                                                 KeyChanged(Noesis::DependencyObject* d, const Noesis::DependencyPropertyChangedEventArgs& e);
  //
  static const Noesis::DependencyProperty*                    Key;
private:

  NS_IMPLEMENT_INLINE_REFLECTION(TGCNoesisKeyTriggerExtension, Noesis::DependencyObject)
  {
    NsMeta<Noesis::TypeId>("UI.KeyTriggerExtension");
    const Noesis::TypeClass* type = Noesis::TypeOf<SelfClass>();

    Noesis::UIElementData* data = NsMeta<Noesis::UIElementData>(type);
    data->RegisterProperty<Noesis::Ptr<Noesis::ObservableCollection<Noesis::BaseComponent>>>(Key, "Key", Noesis::FrameworkPropertyMetadata::Create(Noesis::Ptr<Noesis::ObservableCollection<Noesis::BaseComponent>>(), KeyChanged));
  }
};
////////////////////////////////////////////////////
const Noesis::DependencyProperty* TGCNoesisKeyTriggerExtension::Key;

void TGCNoesisKeyTriggerExtension::SetKey(Noesis::ObservableCollection<Noesis::BaseComponent>* pValue)
{
  SetValue<Noesis::Ptr<Noesis::ObservableCollection<Noesis::BaseComponent>>>(Key, pValue);
}

Noesis::ObservableCollection<Noesis::BaseComponent>* TGCNoesisKeyTriggerExtension::GetKey()
{
  return GetValue<Noesis::Ptr<Noesis::ObservableCollection<Noesis::BaseComponent>>>(Key).GetPtr();
}

void TGCNoesisKeyTriggerExtension::KeyChanged(Noesis::DependencyObject* d, const Noesis::DependencyPropertyChangedEventArgs& e)
{
}
I'm a bit stuck on this one, any help is appriciated!
 
User avatar
sfernandez
Site Admin
Posts: 2983
Joined: 22 Dec 2011, 19:20

Re: Dependency property that expects list of integers in c++

27 Feb 2020, 12:02

Hi Joren,

Right now in C++ we only offer Collection and ObservableCollection that are working with BaseComponent types, so you can use them by boxing/unboxing the integers.
You can also create your own BoxedCollection<T> for non-BaseComponent types inheriting from BaseCollection to expose a more friendly API and hide all the boxing/unboxing stuff, something like this:
template <class T>
class BoxedCollection: public Noesis::BaseCollection
{
public:
    static_assert(!Noesis::IsDerived<T, Noesis::BaseComponent>::Result, "T can't inherit from BaseComponent");

    inline const typename Noesis::Param<T>::Type Get(uint32_t index) const;
    inline void Set(uint32_t index, const typename Noesis::Param<T>::Type item);
    inline int Add(const typename Noesis::Param<T>::Type  item);
    inline void Insert(uint32_t index, const typename Noesis::Param<T>::Type  item);
    inline bool Contains(const typename Noesis::Param<T>::Type  item) const;
    inline int IndexOf(const typename Noesis::Param<T>::Type item) const;
    inline bool Remove(const typename Noesis::Param<T>::Type  item);

protected:
    inline const TypeClass* GetItemType() const override;

    NS_IMPLEMENT_INLINE_REFLECTION(BoxedCollection<T>, Noesis::BaseCollection)
    {
        NsMeta<Noesis::TypeId>(Noesis::IdOfCollection(Noesis::TypeOf<T>()).GetStr());
    }
};
But in order to use "179, 168, 23" in xaml as a valid value for that property you have to specify a TypeConverter in the reflection:
NS_IMPLEMENT_INLINE_REFLECTION(TGCNoesisKeyTriggerExtension, Noesis::DependencyObject)
{
  NsMeta<Noesis::TypeId>("UI.KeyTriggerExtension");

  NsProp("Key", &TGCNoesisKeyTriggerExtension::GetKey, &TGCNoesisKeyTriggerExtension::SetKey)
    .Meta<Noesis::TypeConverterMetaData>("IntCollectionConverter");

  Noesis::UIElementData* data = NsMeta<Noesis::UIElementData>(Noesis::TypeOf<SelfClass>());
  data->RegisterProperty<Noesis::Ptr<Noesis::ObservableCollection<Noesis::BaseComponent>>>(Key, "Key", Noesis::FrameworkPropertyMetadata::Create(Noesis::Ptr<Noesis::ObservableCollection<Noesis::BaseComponent>>(), KeyChanged));
}
class IntCollectionConverter: public Noesis::TypeConverter
{
public:
    /// From TypeConverter
    //@{
    bool TryConvertFromString(const char* str, Noesis::Ptr<Noesis::BaseComponent>& result) const override;
    //@}

    NS_DECLARE_REFLECTION(IntCollectionConverter, Noesis::TypeConverter)
};
Hope this helps.
 
Joren
Topic Author
Posts: 18
Joined: 12 Nov 2019, 15:33

Re: Dependency property that expects list of integers in c++

27 Feb 2020, 16:06

Thanks for your reply! A TypeConverter is exactly what I'm looking for. I tried this out and after working through some errors I am now at a point where I have something that I can use. Listing some errors I encountered below for those who want to try something similar:
  • GetKey needs to be a const function
    Noesis::Collection<Noesis::BaseComponent>* GetKey() const
  • The type in sample below needs to be the type declared in the reflection of the TypeConverter class, not the actual class name. Don't forget to register the class aswell.
    Meta<Noesis::TypeConverterMetaData>("IntCollectionConverter") 

Who is online

Users browsing this forum: Google [Bot] and 59 guests