MobileEssentials / DynamicForms

Makes Xamarin.Forms more dynamic, by allowing loading of XAML for views, and Json for bi-directionally bindable view models
MIT License
41 stars 23 forks source link

Windows Phone version #1

Open nfplay opened 9 years ago

nfplay commented 9 years ago

Hello, and thanks again for this amazing funcionality. I successfully tested it on IOS and Android, but failed to get results on Windows Phone.

Looking at the source:

  1. Is there a reason for the Windows Phone project being outside the main solution?
  2. I can see that the project references a whole bunch of different files, different from all the other projects (that are linked to Desktop project), and seem to be missing?
  3. After some tests i realize that the Windows Phone implementation of a lot of the Reflection stuff common in all other projects seems to be quite different. If i target the project to Windows Phone 8.1 i get a lot of errors, if i try adding a simpler Windows Phone 8.0 target (the one i'm actually interested in), i get 2 errors:

a. ConcurrentDictionary -> Not available in Windows Phone 8.0

This is easily replaced by an ImmutableDictionary, refer to this: http://stackoverflow.com/questions/18367839/alternative-to-concurrentdictionary-for-portable-class-library

b. In DynamicParameterInfo i get an error related to ParameterInfo, which doesn't have "a constructor that takes 0 arguments". Windows Phone "mscorlib" implementation shows ParameterInfo as an abstract class without a constructor (other platforms implementations have it), so the exact same code fails. Perhaps i'm missing something, but the boilerplate code for DictionaryModel and JsonModel must be a little different for Windows Phone.

If i ignore DictionaryModel and JsonModel entirely and stick just to LoadFromXaml reflection, (i used DependencyService to create my own method just to test Windows Phone version) it works without problems.

Bottom line: do you have any clue regarding that DynamicParameterInfo problem stated above? If we can resolve it, i think all the problems will be solved.

What do you think?

Thanks,

Nuno

kzu commented 9 years ago

Good point. IIRC, the reason I didn't support it initially was because I didn't have a WP emulator I could run (I use a MacBook Pro with Parallels for Windows). And it was more important for my pet project to support iOS/Android first ;)

I see no good reason not to tweak code so that it works on WP too. The reflection stuff might be tricky, but I think it should work too.

On Sun, Aug 16, 2015 at 12:32 AM Nuno Fonseca notifications@github.com wrote:

Hello, and thanks again for this amazing funcionality. I successfully tested it on IOS and Android, but failed to get results on Windows Phone.

Looking at the source:

  1. Is there a reason for the Windows Phone project being outside the main solution?
  2. I can see that the project references a whole bunch of different files, different from all the other projects (that are linked to Desktop project), and seem to be missing?
  3. After some tests i realize that the Windows Phone implementation of a lot of the Reflection stuff common in all other projects seems to be quite different. If i target the project to Windows Phone 8.1 i get a lot of errors, if i try adding a simpler Windows Phone 8.0 target (the one i'm actually interested in), i get 2 errors:

a. ConcurrentDictionary -> Not available in Windows Phone 8.0

This is easily replaced by an ImmutableDictionary, refer to this:

http://stackoverflow.com/questions/18367839/alternative-to-concurrentdictionary-for-portable-class-library

b. In DynamicParameterInfo i get an error related to ParameterInfo, which doesn't have "a constructor that takes 0 arguments". Windows Phone "mscorlib" implementation shows ParameterInfo as an abstract class without a constructor (other platforms implementations have it), so the exact same code fails. Perhaps i'm missing something, but the boilerplate code for DictionaryModel and JsonModel must be a little different for Windows Phone.

If i ignore DictionaryModel and JsonModel entirely and stick just to LoadFromXaml reflection, (i used DependencyService to create my own method just to test Windows Phone version) it works without problems.

Bottom line: do you have any clue regarding that DynamicParameterInfo problem stated above? If we can resolve it, i think all the problems will be solved.

What do you think?

Thanks,

Nuno

— Reply to this email directly or view it on GitHub https://github.com/MobileEssentials/DynamicForms/issues/1.

nfplay commented 9 years ago

Well, i'm having a hard time trying to circumvent the limitation of the abstract PropertyInfo's internal constructor. This prevents the class from being subclassed, and since its derived class (DynamicPropertyInfo) relies basically on overrides, i'm not seeing a way to do this. I've replaced all of the problematic System.Reflection classes with a version obtained through reflection (with JustDecompile) but with a public constructor. This gets me to a certain point, but doesn't really work because we need a real PropertyInfo, not a reflection-copy. Unless i'm missing something, abstract classes with internal constructors are impossible to derive on a distinct assembly.

I will give it a shot at Windows Phone 8.1 version now, to see if i encounter the same problems.

P.S. LoadFromXaml is working though ;) (that's what i'll use most actually)

nfplay commented 9 years ago

Windows Phone 8.1 has the same problems. But how about this approach instead:

  1. You load the XAML as normally do:
    content.LoadFromXaml(xamlToUpdate);
  1. For the BindingContext using JSON, deserialize it with JSON.Net into a Dictionary:
 var json = "{Title:'Welcome to Xamarin Forms Dynamic!', DynamicList: [1,2,3,4,5,6], ListViewIsVisible:false}";
var context = JsonConvert.DeserializeObject<Dictionary<string, object>>(json); 
  1. And proceed as you normally would:
 content.BindingContext = context;
 Application.Current.MainPage = content; (etc...)

Now in the XAML you can bind using "Binding Path=[Property]" with square brackets:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

    <StackLayout VerticalOptions="Center">
        <Label TextColor="Red"  Text="XAML / JSON tests..." 
           VerticalOptions="Center" HorizontalOptions="Center" />
        <Label TextColor="Green"  Text="{Binding Path=[Title], StringFormat='{0}'}" 
           VerticalOptions="Center" HorizontalOptions="Center" />
        <ListView x:Name="itemListView"
                  HeightRequest="300"
                  ItemsSource="{Binding Path=[DynamicList]}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <Label Font="Large" Text="{Binding ., StringFormat='{0}'}">
                            </Label>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

And this xaml gives the lovely layouts that i send in attachments! IOS, Android and Windows Phone. All these example types are working: string, array, boolean (i attached an additional windows phone screenshot where i added the property "IsVisible" to the above ListView binded on "ListViewIsVisible").

It seems a lot easier than dealing with all the refactoring boilerplate, and this works fine on Windows Phone too ;)

Let me know what you think,

Thanks

Nuno Android: android IOS: ios Windows Phone: wp_list Windows Phone with "IsVisible" binded to "ListViewIsVisible": wp_list_off

kzu commented 9 years ago

If all the binding tests pass, I'm good. I don't think the dictionary will give you the two way binding though, so it may need to be a custom observable (INotifyPropertyChange) dictionary instead, but otherwise, it looks good to me! On Mon, Aug 17, 2015 at 12:21 AM Nuno Fonseca notifications@github.com wrote:

Windows Phone 8.1 has the same problems. But how about this approach instead:

  1. You load the XAML as normally do:

    content.LoadFromXaml(xamlToUpdate);

  2. For the BindingContext using JSON, deserialize it with JSON.Net into a Dictionary:

    var json = "{Title:'Welcome to Xamarin Forms Dynamic!', DynamicList: [1,2,3,4,5,6], ListViewIsVisible:false}";var context = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);

    1. And proceed as you normally would:

    content.BindingContext = context; Application.Current.MainPage = content; (etc...)

Now in the XAML you can bind using "Binding Path=[Property]" with square brackets:

<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

<StackLayout VerticalOptions="Center">
    <Label TextColor="Red"  Text="XAML / JSON tests..."
       VerticalOptions="Center" HorizontalOptions="Center" />
    <Label TextColor="Green"  Text="{Binding Path=[Title], StringFormat='{0}'}"
       VerticalOptions="Center" HorizontalOptions="Center" />
    <ListView x:Name="itemListView"
              HeightRequest="300"
              ItemsSource="{Binding Path=[DynamicList]}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Orientation="Horizontal">
                        <Label Font="Large" Text="{Binding ., StringFormat='{0}'}">
                        </Label>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

And this xaml gives the lovely layouts that i send in attachments! IOS, Android and Windows Phone. All these example types are working: string, array, boolean (i attached an additional windows phone screenshot where i added the property "IsVisible" to the above ListView binded on "IsListViewVisible").

It seems a lot easier than dealing with all the refactoring boilerplate, and this works fine on Windows Phone too ;)

Let me know what you think,

Thanks

Nuno Android: [image: android] https://cloud.githubusercontent.com/assets/5241920/9297386/aa20d3b8-4496-11e5-81cd-559624887bfa.png IOS: [image: ios] https://cloud.githubusercontent.com/assets/5241920/9297387/aa2291f8-4496-11e5-8e24-da98c6c582a3.png Windows Phone: [image: wp_list] https://cloud.githubusercontent.com/assets/5241920/9297388/aa24261c-4496-11e5-9fd5-e78b73313842.png Windows Phone with "IsVisible" binded to "ListViewIsVisible": [image: wp_list_off] https://cloud.githubusercontent.com/assets/5241920/9297389/aa24aae2-4496-11e5-83ae-84dea0bdc901.png

— Reply to this email directly or view it on GitHub https://github.com/MobileEssentials/DynamicForms/issues/1#issuecomment-131668790 .

nfplay commented 9 years ago

Yes i did just that, i used this one: https://forums.xamarin.com/discussion/19361/data-binding-to-dictionary-object http://bit.ly/dictionary-bindings

It's a nice implementation and works very well, with this sample XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

    <StackLayout VerticalOptions="Center">
        <Entry HorizontalOptions="FillAndExpand" 
                    VerticalOptions="Center" 
                    Text="{Binding Path=[Input], StringFormat='{0}', Mode=TwoWay}" 
                    Placeholder="Insert title..." />
        <Label TextColor="Yellow"  Text="{Binding Path=[Input], StringFormat='{0}'}" 
           VerticalOptions="Center" HorizontalOptions="Center" />
    </StackLayout>
</ContentPage>

Binding the "Input" variable TwoWay, i can affect both the Entry and the subsequent Label ;) Very nice!

It would be good to add to the Nuget a Windows Phone 8.0 class library with just the LoadFromXaml code working (exactly the same as the other platforms), throwing perhaps NotImplementedException in JsonModel and DictionaryModel, or don't return any value when using either one, don't know. What do you think?

Thanks once again, i'm not sure why this isn't getting more traction, everybody talks about the need for a supposed XAML Forms Designer, what can be better than realtime design on actual devices? ;)

kzu commented 8 years ago

Hm... I think we could even drop JsonModel and have a single DictionaryModel. A new static factory method DictionaryModel.FromJson could use Json.NET as explained here to seamlessly convert on the fly using Json.NET's built in converter support, into a full fledged nested DictionaryModel :).

Another potential new candidate would be an instance ToJson method on the DictionaryModel, that does the reverse. This could potentially have the benefit of being able to base your viewmodels on a .NET provided contract (IDictionary<string, object>) while still having a straight-forward way to convert back&forth to Json as you get/post the data from/to online services...

Thoughts?

PS: For the WP version, I'd throw NotSupportedException instead.

kzu commented 8 years ago

Hey @nfplay I've been checking this out, and the fact that you have to change the syntax from the real view model to bind to the dictionary one, is not very nice. In fact, it kinda defeats the purpose of using dynamic models for prototyping and switching to real viewmodels for production.

But since this is a general purpose library, I think it should be ok, I guess? As long as expectations are properly set? Meaning: you'd get way better syntax in Android and iOS than you can get on WP.

I didn't find a way to customize the property infos on WP platform :(

kzu commented 8 years ago

Actually, the bidireccional binding tests don't pass when I swtich to index notation for the dictionary, so I don't think that will work either :(