HateDread
Topic Author
Posts: 72
Joined: 06 Feb 2020, 10:27

Blend -> C++ failures - formatting, namespaces

04 Oct 2023, 16:24

Hi,

I'm using Blend to create xaml-based UI with a C# mock, after which I copy the xaml files over and write up a C++ equivalent of the mock-ups.

Two areas consistently fail for me and need manual fix-up, meaning any time I copy and forget, I break my C++ version of the UI.

* String formatting - in Blend, if I want for example a time to be always two digits and a trailing 's' for Seconds, it looks like this
StringFormat=\{0:#\,0.0\}s
(Not doing this _sometimes_ works but sometimes breaks the C# build).

But this breaks in the C++ build, which instead wants what I expected:
StringFormat={}{0:#,0.0}
* Namespaces - I put my view models in a "ViewModels" folder in the Blend project, which put them inside a namespace, the final result being (with project name as well); "rtg.ViewModels.MyViewModelName", and in xaml that is accessed like so
xmlns:viewModels="clr-namespace:rtg.ViewModels"
...
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type viewModels:MyViewModelName}">
            <views:SomeViewHere/>
        </DataTemplate>
    </UserControl.Resources>
But this doesn't work in the C++ build - it can't recognize MyViewModelName, or it can't recognize SomeViewHere, and so on. Seems to happen to anything in a namespace like this.

So I try to register on the C++ side my types in the reflection macros - they're inside 'rtg' namespace already, then I try
NS_IMPLEMENT_REFLECTION(MyViewModelName, "MyViewModelName")
and outside of namespace
NS_IMPLEMENT_REFLECTION(rtg::MyViewModelName, "rtg.MyViewModelName")
and with ViewModels or viewModels in front
NS_IMPLEMENT_REFLECTION(rtg::MyViewModelName, "rtg.viewModels.MyViewModelName")
NS_IMPLEMENT_REFLECTION(rtg::MyViewModelName, "rtg.viewModels:MyViewModelName")
NS_IMPLEMENT_REFLECTION(rtg::MyViewModelName, "rtg.ViewModels.MyViewModelName")
NS_IMPLEMENT_REFLECTION(rtg::MyViewModelName, "rtg.ViewModels:MyViewModelName")
I can't get any combination to work unless I modify the xaml to not use namespaces at all
<!--xmlns:viewModels="clr-namespace:rtg.ViewModels"-->
...
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type MyViewModelName}">
            <SomeViewHere/>
        </DataTemplate>
    </UserControl.Resources>
But this of course breaks in Blend, which seems to encourage namespaces, unless I modify it there and get rid of namespaces that naturally come with the directory structure. Or I maintain two xaml copies, which is not desirable.

What is the canonical and correct way to handle the namespace differences between Blend and Noesis C++? Same Q with the string formatting and why I need to sometimes escape it.

Thanks!
 
User avatar
sfernandez
Site Admin
Posts: 3008
Joined: 22 Dec 2011, 19:20

Re: Blend -> C++ failures - formatting, namespaces

05 Oct 2023, 10:10

Hi,

For the string formatting problem, could you please report it in our bugtracker? This is clearly an unsupported syntax we need to add.

Regarding the namespaces you need to match the reflection name in C++ with the full name of the C# type. In your examples the C# namespace is "rtg.ViewModels", so the full name of a view model defined there will be "rtg.ViewModels.MyViewModelName". This means your C++ reflection name should be exactly that:
NS_IMPLEMENT_REFLECTION(rtg::MyViewModelName, "rtg.ViewModels.MyViewModelName")
And in the xaml it will be referenced like this:
xmlns:viewModels="clr-namespace:rtg.ViewModels"
...
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type viewModels:MyViewModelName}">
            <views:SomeViewHere/>
        </DataTemplate>
    </UserControl.Resources>
There is another thing to take into account, the reflection type must be registered in Noesis before loading the xaml. This can be done by just calling TypeOf for that type when you are initializing your application and registering your components:
void RegisterComponents()
{
  Noesis::TypeOf<rtg::MyViewModelName>();
  ...
  Noesis::RegisterComponent<rtg::SomeViewHere>();
  ...
}
Hope this helps.
 
HateDread
Topic Author
Posts: 72
Joined: 06 Feb 2020, 10:27

Re: Blend -> C++ failures - formatting, namespaces

05 Oct 2023, 14:52

Hi,

For the string formatting problem, could you please report it in our bugtracker? This is clearly an unsupported syntax we need to add.

Regarding the namespaces you need to match the reflection name in C++ with the full name of the C# type. In your examples the C# namespace is "rtg.ViewModels", so the full name of a view model defined there will be "rtg.ViewModels.MyViewModelName". This means your C++ reflection name should be exactly that:
NS_IMPLEMENT_REFLECTION(rtg::MyViewModelName, "rtg.ViewModels.MyViewModelName")
And in the xaml it will be referenced like this:
xmlns:viewModels="clr-namespace:rtg.ViewModels"
...
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type viewModels:MyViewModelName}">
            <views:SomeViewHere/>
        </DataTemplate>
    </UserControl.Resources>
There is another thing to take into account, the reflection type must be registered in Noesis before loading the xaml. This can be done by just calling TypeOf for that type when you are initializing your application and registering your components:
void RegisterComponents()
{
  Noesis::TypeOf<rtg::MyViewModelName>();
  ...
  Noesis::RegisterComponent<rtg::SomeViewHere>();
  ...
}
Hope this helps.
Awesome, thanks!

One question - I've been using Noesis::RegisterComponent<T>() for all types - view models, views, etc. When should I use one over the other (TypeOf<T>()), if there's a difference?
 
User avatar
sfernandez
Site Admin
Posts: 3008
Joined: 22 Dec 2011, 19:20

Re: Blend -> C++ failures - formatting, namespaces

05 Oct 2023, 22:29

I've been using Noesis::RegisterComponent<T>() for all types - view models, views, etc.
This is the safest thing to do, as RegisterComponent registers the class in the factory (so an instance can be created by name when found in the XAML), and it also registers the type in the reflection.
When should I use one over the other (TypeOf<T>()), if there's a difference?
If a class is only referenced in XAML as a type (with the x:Type extension) and there is no need to create objects of that class in XAML, registering the type with TypeOf<T>() should be enough (for example, view models that only appear in the DataType property of a DataTemplate).

Anyway I recommend you continue using RegisterComponent for everything.

Who is online

Users browsing this forum: Ahrefs [Bot] and 12 guests