Page 1 of 5

Caliburn.Micro port issues

Posted: 24 Feb 2017, 19:59
by KeldorKatarn
I'm currently trying to port Caliburn.Micro to Noesis. It's going fine for the most part actually. (The property binding conventions seems to work perfectly fine)
The biggest issue are it's automatic Message Binding conventions. I'm running into missing APIs left and right. Would it be ok if I post those here and anybody can tell me if we have an alternative available in Noesis how to get that done or whether it's planned for the future.

Oh yeah and also if there's even any interest in this project.

Re: Caliburn.Micro port issues

Posted: 24 Feb 2017, 20:22
by Ziriax
Please note, I am just a user, not associated with Noesis.

I guess that currently the situation for creating portable user interfaces isn't that great unless you rewrite the views or use QT.

So a framework that is as popular as Caliburn.Micro would be a great addition for Noesis IMHO. It would allow more adoption in the business IT world.

Feel free to post your problems, as a Noesis user using mostly C# I might be able to answer some questions

Best regards,

Re: Caliburn.Micro port issues

Posted: 24 Feb 2017, 21:03
by KeldorKatarn
Pretty much everything works in terms of API except where the message conventions are concerned. There I'm running into a lot of missing API.

First of all XamlReader is missing, which is used in Caliburn to create some basic DataTemplates on the fly.
Then a lot of stuff regarding AttachedProperties and the System.Windows.Interactivity namespace.

Missing stuff are:
TriggerAction<T>
static class Interaction //  GetTriggers() method
AssociatedObject
DependencyObjectCollection<T>
IAttachedObject
TriggerBase.Actions // collection
also some EventTrigger constructor issues, or in general RoutedEvent API issues:
CreateTrigger = () => new EventTrigger { EventName = eventName }
seems not to work in Noesis so I used this instead? Is that correct?
CreateTrigger = () => new EventTrigger { RoutedEvent = new RoutedEvent(eventName) }
Caliburn also creates some basic data templates like this:
        XamlReader.Parse("<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'><TextBlock Text=\"{Binding DisplayName, Mode=TwoWay}\" /></DataTemplate>");
which I don't know how to do without the XamlReader.

Then there's also the later question on how to implement the WindowManager for dialogues and stuff but I have an idea for that.
The biggest thing is probably that Noesis can have multiple NoesisViews. Some on cameras, some for rendertextures.
That shouldn't be a major issue though. It's just a question of how the bootstrapper should be handled. Probaly run once and somehow be informed of every NoesisView that exists, to build it's view/viewModel structure up.

The main problems are the API issues above for message conventions. If one doesn't use those at all, the framework pretty much works already except for the windowsmanager on my end.
I can already autobind a textbox with x:Name="FirstName" to a property of the same name on the viewmodel, all automaticall. The ViewLocator etc also works.

Re: Caliburn.Micro port issues

Posted: 24 Feb 2017, 21:59
by Ziriax
With message conventions, you mean naming conventions? Can you give a specific example?

These questions are unfortunately a bit too deep into the SDK for me to answer, and require response from the main Noesis engineers.

Re: Caliburn.Micro port issues

Posted: 24 Feb 2017, 22:10
by KeldorKatarn
Caliburn supports two kinds of conventions for binding. Property conventions and Action conventions.

they're based on the x:Name of the control.

The property convention works like this:

<TextBox x:Name="FirstName" /> will get it's Text property automatically bound to a FirstName string property on the ViewModel if such exists.

Acvtion conventions work also on the x:Name thing but actually bind to methods instead of to properties.

if you have a button
<Button x:Name="Login" /> Caliburn will try to use the Clicked event to trigger a method call to a method "Login()" on the viewmodel and if present also check for a CanExecute boolean method or property for the guard.

These conventions bind the control property and event that makes the most sense (like Clicked on a button) to the viewmodel usually. You can always use your own bindings of course but these are really shortcuts since the TextBox Binding would have to be {Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} or some stuff like that. So it really saves typing for the standard everyday stuff. You can also use a TabControl and bind it to a collection of ViewModels and it will automatically fill every tab with the view for each viewmodel and such stuff.


The property conventions already work. The action conventions not, due to above API issues. The action conventions work with attached properties and Interaction stuff that's a bit more complicated than simply creating a binding. So it uses a more complicated setup.

Re: Caliburn.Micro port issues

Posted: 25 Feb 2017, 03:25
by sfernandez
Hi,

We should add support for this:
CreateTrigger = () => new EventTrigger { EventName = eventName }
The way you tried creating RoutedEvent(name) won't work because it will point to a new routed event, not to the one defined in the control, and EventTrigger will never be fired.

Please create a ticket in our bugtracker asking for the EventTrigger.EventName property, and another one for the XamlReader.Parse(string xaml).

Re: Caliburn.Micro port issues

Posted: 25 Feb 2017, 04:46
by KeldorKatarn
Please create a ticket in our bugtracker asking for the EventTrigger.EventName property, and another one for the XamlReader.Parse(string xaml).
#1025

I'll check tomorrow if there was some other stuff needed for RoutedEvents. I found some event handlers that don't match the WPF version too. I'll dig that up later.

Re: Caliburn.Micro port issues

Posted: 25 Feb 2017, 08:41
by Ziriax
Regarding the missing Blend interactivity features, maybe Microsoft's open source XamBehaviors for UWP can serve as a good starting point?

https://github.com/Microsoft/XamlBehaviors/

It comes with an MIT license.

Personally I have never used the Blend assemblies, I just use attached properties, but the Blend toys are more convenient I guess.

Re: Caliburn.Micro port issues

Posted: 25 Feb 2017, 14:15
by KeldorKatarn
That might help. I'll have to look into it. But there are still some API differences, collections that dont implement IEnumerable etc that need adjusting. I'll summarize the changes I had to make or problems I'll ran into sometime this weekend. Would anybody be interested in collaborating on this? I could upload the code to GitHub

Re: Caliburn.Micro port issues

Posted: 27 Feb 2017, 17:05
by KeldorKatarn
Further API differences I ran into:

Caliburn is trying to hook into the FrameworkElement.Loaded and FrameworkElement.Unloaded events. In WPF both are events based on a RoutedEventHandler.
Noesis used their own event handlers called FrameworkElement.LoadedHandler and FrameworkElement.UnloadedHandler

Additional to this, I cannot create a RoutedEventArgs instance. I'm suspecting this code will not work correctly, based on an earlier answer?
#if NOESIS
                handler(element, new RoutedEventArgs(element, new RoutedEvent("Loaded")));
#else
                // This is the original Caliburn code for WPF. The Noesis version of RoutedEventArgs does not have a parameterless constructor.
               // So I'm not sure what I should call the handler with.
                handler(element, new RoutedEventArgs());
#endif
Also as discussed somewhere on this forums before, the LayoutUpdated event is missing.

On the TriggerBase class the Actions Property is missing. It should return a TriggerActionCollection.

The EventTrigger class is missing the EventName property. How do I reproduce this in Noesis?
 new EventTrigger { EventName = triggerDetail };
I only see a "RoutedEvent" property, but if I put a new event on that, that will again not be semantically the same as the code above, correct?

The IAttachedObject interface is missing completely.
var allTriggers = Interaction.GetTriggers(d);
does not work since the GetTriggers() method is missing from the Interaction class. (d is a DependencyObject)
Is there a way to retrieve the triggers any other way?

Caliburn.Micro for WPF uses the code
                var childCount = (current is Visual || current is Visual3D)
                    ? VisualTreeHelper.GetChildrenCount(current) : 0;
I found the Visual3D type does not exist in Noesis, probably on purpose so I left that second is-check away for Noesis.

The
VisualTreeHelper.GetParent()
method expects a DependencyObject in WPF as a parameter. In noesis it expects a Visual.
Should I simply cast it? Does that work? If WPF uses it in this way I expect the type in this context to be a Visual?

Minor but I want to mention it anyway, the AttachedPropertyBrowsableForTypeAttribute is missing.

The biggest issues probably are that the DependencyObjectCollection as well as the TriggerAction<> generic type are entirely missing.

And finally, ItemCollection does not implement the IEnumerable interface. Which is a problem when trying to use LINQ on it. I need to implement the LINQ operators specifically for this type if I want to use it. From what I can see it correctly implements the interface already (it does have the GetEnumerator() method), it just doesn't DECLARE that it is an IEnumerable. Could that be added?

From what I can see those are the main issues.

Oh yeah, one big issue is of course that in the absense of both XamlReader and FrameworkElementFactory types, there's seemingly no way to create a DataTemplate in code. Any suggestions on that?