Kristof
Topic Author
Posts: 19
Joined: 22 Apr 2014, 14:44

Binding to indexers

10 Jun 2014, 10:38

In WPF, you can bind to 'property indexers'.

Example of a viewmodel that contains a Dictionary:
public class ViewModel
    {
        public ViewModel()
        {
            Resources = new Dictionary<string, string>();

            Resources["ButtonResource"] = "PLAY";
        }

        public Dictionary<string, string> Resources { get; private set; }
    }
In the view I can now bind directly to items in this dictionary:
<Button Content="{Binding Resources[ButtonResource]}"/>
Is there any way I can do this in NoesisGUI as well? Binding to indexers doesn't seem to work, so at this moment I have to create a new property for each item in the dictionary. That is very cumbersome.

I want to use this to make an app that will support many languages. So instead of coding all the text in the XAML, I want to store the text in a Dictionary and I'm looking for a nice way to access these Dictionaries from XAML.
 
User avatar
sfernandez
Site Admin
Posts: 3154
Joined: 22 Dec 2011, 19:20

Re: Binding to indexers

12 Jun 2014, 20:17

We don't support the use of a .NET Dictionary as a ViewModel property.

An alternative to the dictionary would be using a Noesis Collection:
[Noesis.Extended]
public class ViewModel : Noesis.BaseComponent
{
    public Noesis.Collection Texts { get; private set; }

    public ViewModel()
    {
        Texts = new Noesis.Collection();
        Texts.Add("One");
        Texts.Add("Two");
        Texts.Add("Three");
        Texts.Add("Four");
    }
}

public class _Test : MonoBehaviour
{
    void Start()
    {
        var gui = GetComponent<NoesisGUIPanel>();
        var root = gui.GetRoot<Noesis.Grid>();

        root.SetDataContext(ViewModel());
    }
}
And you can use collection indexers in the xaml:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Background="White">
        <TextBlock Text="{Binding Texts[0]}"/>
        <TextBlock Text="{Binding Texts[1]}"/>
        <TextBlock Text="{Binding Texts[2]}"/>
        <TextBlock Text="{Binding Texts[3]}"/>
    </StackPanel>
</Grid>
 
Kristof
Topic Author
Posts: 19
Joined: 22 Apr 2014, 14:44

Re: Binding to indexers

16 Jun 2014, 11:16

Thanks for the reply.

I won't be able to use the workaround that you propose. The key of the collection should really be a string and not just an integer. Using integers, the risk is too high that when the order changes the whole GUI becomes messed up.
 
User avatar
sfernandez
Site Admin
Posts: 3154
Joined: 22 Dec 2011, 19:20

Re: Binding to indexers

16 Jun 2014, 17:30

I understand the maintainability problems you exposed when using a Collection and integer indexers ;)

The solution then is to use a ResourceDictionary of strings (I should probably think of this first :D ):
<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <sys:String x:Key="PlayButton">Play</sys:String>
    <sys:String x:Key="SettingsButton">Settings</sys:String>
    <sys:String x:Key="ExitButton">Exit</sys:String>
</ResourceDictionary>
Then you can load that dictionary into a ViewModel property:
[Extended]
class ViewModel : BaseComponent
{
    public ResourceDictionary Texts { get; private set; }

    public ViewModel()
    {
        Texts = NoesisGUISystem.LoadXaml<ResourceDictionary>(
            "Assets/UI/TextResources.xaml");
    }
}
And then, bind to these string resources using the dictionary keys as indexers:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        <Button Margin="5" Content="{Binding Texts[PlayButton]}"/>
        <Button Margin="5" Content="{Binding Texts[SettingsButton]}"/>
        <Button Margin="5" Content="{Binding Texts[ExitButton]}"/>
    </StackPanel>

</Grid>
 
Kristof
Topic Author
Posts: 19
Joined: 22 Apr 2014, 14:44

Re: Binding to indexers

02 Jul 2014, 13:14

Thanks for this solution.

It works great in the Unity-editor, however I could not get it to work on Android. The call to NoesisGUISystem.LoadXaml() crashes, probably because on Android the assets are stored inside the APK file.

When I want to load assets at runtime, I usually store them in the 'StreamingAssets' folder and access them through the WWW class (this supports reading in the APK file). However, NoesisGUISystem.LoadXaml() just accepts a file-path so I cannot use this trick. It would be great if it accepted a WWW instance (or a string with the XAML-content).

Or is there another way to get this to work on Android?
 
User avatar
sfernandez
Site Admin
Posts: 3154
Joined: 22 Dec 2011, 19:20

Re: Binding to indexers

07 Jul 2014, 13:04

It works great in the Unity-editor, however I could not get it to work on Android. The call to NoesisGUISystem.LoadXaml() crashes, probably because on Android the assets are stored inside the APK file.
Which kind of crash are you getting? Can you provide any log error message, callstack, or dump?
When I want to load assets at runtime, I usually store them in the 'StreamingAssets' folder and access them through the WWW class (this supports reading in the APK file). However, NoesisGUISystem.LoadXaml() just accepts a file-path so I cannot use this trick. It would be great if it accepted a WWW instance (or a string with the XAML-content).
Our AssetPostProcessor does exactly that, it builds all the xaml files inside Assets folder and stores a binary representation in the StreamingAssets folder. In Android we are able to access the assets inside the .apk by using the AssetManager class. In fact, our SampleGallery demo is loading 3 ResourceDictionary xaml files when ControlGalleryLogic script is started.

Maybe you forgot to activate the Android platform in our Build Settings panel (menu Window -> NoesisGUI -> Settings). Or maybe your xaml has parsing errors and cannot be built. Have you checked the Unity Editor Console window? You can go to the NoesisGUI Settings panel, click the Build button to rebuild all the assets in the project, and take a look at the Console to see if anything is wrong.

Who is online

Users browsing this forum: maherne and 1 guest