User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: [Unity] Various questions

21 May 2014, 12:24

I tested your example and yes it works, thanks to the MonoBehaviour where you set the DataContext to the view model you created in code. I tried it the other way around, creating the view model within xaml and setting the data context in another grid. So I changed your example to fit my needs but then it didn't work any more. :( Is it even possible to do it this way as this would be a much neater solution?
To use extended classes in a xaml they have to derive from a serializable component (currently BaseComponent is not serializable but maybe we should change this to avoid confusion). So you have to change DataViewModel base class to Noesis.SerializableComponent:
[Extended]
class DataViewModel : Noesis.SerializableComponent
{
    string _title;
    public string DataTitle
    {
        get { return _title; }
        set
        {
            if (_title != value)
            {
                _title = value;
                NotifyPropertyChanged("DataTitle");
            }
        }
    }

    Noesis.BaseComponent _child;
    public Noesis.BaseComponent DataChild
    {
        get { return _child; }
        set
        {
            if (_child != value)
            {
                _child = value;
                NotifyPropertyChanged("DataChild");
            }
        }
    }
}
Then you can use your DataViewModel class directly in the xaml:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid.Resources>
        <DataViewModel x:Key="ViewModel" DataTitle="Some Window">
            <DataViewModel.DataChild>
                <StackPanel>
                    <TextBlock Text="Some text in the window" Margin="0,0,0,10"/>
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                        <Button Content="OK" Width="100"/>
                        <Button Content="Cancel" Width="100" Margin="8,0,0,0"/>
                    </StackPanel>
                </StackPanel>
            </DataViewModel.DataChild>
        </DataViewModel>
    </Grid.Resources>
    
    <Grid DataContext="{StaticResource ViewModel}">
        <WindowControl HorizontalAlignment="Center" VerticalAlignment="Center"
            Title="{Binding DataTitle}"
            Child="{Binding DataChild}"/>
    </Grid>
</Grid>
I removed the MonoBehavior, clicked play and it worked :)
@new version: How long does it usually take to get it released on Unity?
We usually release a new version of NoesisGUI every 2/3 weeks containing improvement and fixes to bugs reported by customers. Then we submit that version to the Asset Store, that takes between 3 to 7 days, depending on their publishing queue, to be up in the web.
 
User avatar
Scherub
Topic Author
Posts: 141
Joined: 06 May 2014, 20:53
Contact:

Re: [Unity] Various questions

21 May 2014, 22:45

Okay, I tested your example and it works so far. The problem that it didn't work in my project was that I inherited my view model from BaseComponent instead of SerializableComponent. Now that I made the necessary modifications it works at least for very simple things like strings. It doesn't work for collections (bound to an ItemsControl such as a ListBox) though and I guess the reason is that your Collection doesn't inherit from SerializableComponent.

I also tried your nested example with the selected character. It doesn't work for me when I use the view model approach. (I didn't try your MonoBehaviour-approach.) To get it working I had to change the base class of SelectedCharacter from BaseComponent to SerializableComponent. Anyway, I attached an example to this post that doesn't work.

This apparently means that everything that's in the ViewModel has to inherit from SerializableComponent. The question is then. What exactly is BaseComponent still good for?

Even worse, originally I created a container class for my character named "CharacterContainer" where I had to pass a "Character" data class into. This means it doesn't have a parameterless default constructor and if I wanted it to get it working I am required to change the base class to SerializableCompoent that - of course - requires a parameterless default constructor. Most properties access the inner data class directly so I would have to extend all properties to make a check whether the inner data object is not null. And would that also mean that the data class has to inherit from SerializableComponent, too?

Now I'm not really sure whether this would work at all. Why serialize the content of the collection? Would you still be able to add/remove items during runtime?

Tbh I'm a bit confused and frustrated now that I already spent lots of hours and I'm still not there where I would like to be.
Attachments
SimpleNestedTest.rar
(1.47 KiB) Downloaded 102 times
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: [Unity] Various questions

22 May 2014, 20:55

Our C# API directly wraps our native plugin class structure. In that native structure our base object is the BaseComponent, but this class is not serializable. The base class for serializable objects is the SerializableComponent class.

This is causing some confusion, so in future versions we are going to hide this implementation details, and users won't need to know anything about serializable objects or not.

Currently, when a user defines a new class that will be set somewhere in the UI tree, it must have the [Noesis.Extended] attribute so we can register this class in our system, and it must inherit from Noesis.BaseComponent. But, if that class is directly used in the XAML file, the class must be serializable (inherit from SerializableComponent).

Additionally, any public C# property (with public get/set) exposed by a extended class is serialized with the object, thus, property type must be serializable too. Maybe we have to add a [NoSerializable] attribute for properties, so users can select which properties are serialized and which are excluded.

When a class is serializable it must provide a parameterless constructor so our system can instantiate it when unserializing. During unserialization we create an empty instance and then fill it with the serialized properties. Be careful with this because any property you set in the constructor will be overwritten by the serialized values.
It doesn't work for collections (bound to an ItemsControl such as a ListBox) though and I guess the reason is that your Collection doesn't inherit from SerializableComponent.
Collections are already serializable, but I detected that boxed values (like strings) stored in a collection are not correctly serialized. I solved this problem and will be fixed in the next release.
I also tried your nested example with the selected character. It doesn't work for me when I use the view model approach. (I didn't try your MonoBehaviour-approach.) To get it working I had to change the base class of SelectedCharacter from BaseComponent to SerializableComponent. Anyway, I attached an example to this post that doesn't work.
As I explained before, if you use the VM in the xaml, it must be serializable, and any public property of the VM must be serializable too. This is why you need SelectedCharacter to be serializable, otherwise a null value is unserialized when loading the xaml file.

Anyways, I consider that if you are following a MVVM model, the View shouldn't know anything about the ViewModel, it should only provide the Bindings to the desired data. Bindings will be solved when you attach the ViewModel to the loaded XAML. This way you don't need your ViewModel, and none of the nested classes, to be serializable.
Tbh I'm a bit confused and frustrated now that I already spent lots of hours and I'm still not there where I would like to be.
When anyone starts using NoesisGUI is hard to figure out what is best way to do things, even for people coming from the WPF world. In part because our API doesn't follow exactly the WPF API, and this is one of the things we are trying to improve for 1.2 version. We also are aware that our plugin still contains numerous bugs, but we are working hard to fix every bug found by our customers in the shortest possible time.

I just can say that you could find us here anytime you need help. I hope you don't give up, and continue using our product. When you get used to it, I'm sure you won't feel comfortable with any other UI framework. Just take a look what others achieved with NoesisGUI: http://voidexpanse.com/Pages/Home

;)
 
User avatar
Scherub
Topic Author
Posts: 141
Joined: 06 May 2014, 20:53
Contact:

Re: [Unity] Various questions

22 May 2014, 22:59

Ahhhh! ;) Now I finally understand what I was doing wrong. All the problems just appeared because I were creating the ViewModel within XAML. But after your explanation I figured that wasn't a good idea. Now I modified the code so that the ViewModel is created and assigned from a MonoBehaviour and everything that didn't work before just started working. Well, nearly everything but I've to check first whether that is a mistake on my side or the bug you mentioned.

So I thank you a lot for your explanation and your patience! :) I hope I'll progress a bit faster from now on. :)

And tbh I've never been really happy with neither NGUI nor DaikonForge. And it was just due to the Unity sale that I got aware of NoesisGUI and because I really liked the idea of using WPF (as I'm pretty familiar with it) I gave it a try. You guys really have to gather more attention!

Maybe I can help a bit later on showing the progress of the project on various websites and mentioning NoesisGUI. Once I've got a bit more of various gui stuff done and I'm satisfied with the results and how it works I'll also write a review on the Unity Store.

Who is online

Users browsing this forum: ivan.fuertes and 1 guest