microsoft / xaml-standard

XAML Standard : a set of principles that drive XAML dialect alignment
Other
804 stars 50 forks source link

Add mechanism for platform checks in markup #14

Open harinikmsft opened 7 years ago

harinikmsft commented 7 years ago

In order to access native controls/elements specific to a platform from markup, there needs to be a common mechanism for platform checks. Example - something like:

<UserControl ...
    xmlns:iOS="http://schemas.xamarin.com/ios/2017/xaml;targetPlatform=iOS">

    <iOS:UILabel Text=”You can only see this text on iOS devices” />

</UserControl>
mdtauk commented 7 years ago

Good to see it has been considered. Would be cool to extend it throughout though. So not just per control (which would mean adding multiple buttons in the XAML, and putting it per property eventually) <Button ios:Content="Click me on iOS" android:Content="Click me on Android" uwp:Content="Click me on Windows" />

birbilis commented 7 years ago

As long as it would allow one to make their own, potentially overriding existing ones with same name to aid when porting existing markup that uses such.

Btw, how would you do a switch/case there? E.g show this on iOS, that on Android, but that elsewhere? With a node child and nesting down multiple levels could do if-else. Or :not, :elsewhere or something if :other isn't obvious. For switch would need special parent node like and children (could be panels or anything starting with iOS:, Android: etc) and parent would render only current platform children and could have an other child or only render non platform specific children if none specific child for current platform was found

bondarenkod commented 7 years ago

UWP (XAML) has great mechanism for adding metadata as properties to XAML elements (Controls, DataTemplates). I think that's a good option to use it in the XAML Standart. I think we can use it for Controls, Styles, ControlTemplates and DataTemplates: control style and templates cases

skendrot commented 7 years ago

Not sure adding platform properties makes sense as it would be a lot of work. However, allowing platform definitions might be easier

<Button >
    <Button.Content>
        <platform:ios>
            <x:String>On iOS!</x:String>
        </platform.ios>
    </Button.Content>
</Button>

Something along those lines instead of platform.ios:Content="On iOS!"

mrlacey commented 7 years ago

I think this is a good idea but it needs further clarifying/qualification. Given this code (from the OP)

<UserControl ...
    xmlns:iOS="http://schemas.xamarin.com/ios/2017/xaml;targetPlatform=iOS">
    <iOS:UILabel Text="You can only see this text on iOS devices" />
</UserControl>

How does the system know that that control is only rendered on an iOS device? If this is in a XAMLStandard document then shouldn't I be able to put it in a UWP app? - And then how does the UWP compiler know it can safely ignore this namespace/control? Is it because there is (will be) something in the standard to say that this XMLNameSpace (or alias), and a select few others, can be ignored if not supported by that platform? If the standard does include a specific set of namespaces that can be ignored then that's potentially limiting to other platforms adopting the standard. They wouldn't be able to add additional namespaces and still maintain compatibility with others that already support the standard. If anything will arbitrarily be ignored if not known by the compiler then we lose the ability to get design and compile time checking of XAML.

Surely we'll need to tell the compiler that the iOS namespace, in the example, can be ignored by any compiler that doesn't understand it. Fortunately there's already a standard way to do that.

<UserControl ...
    xmlns:iOS="http://schemas.xamarin.com/ios/2017/xaml;targetPlatform=iOS"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
    mc:Ignorable="iOS">
    <iOS:UILabel Text="You can only see this text on iOS devices" />
</UserControl>

Now my compiler knows it can ignore anything in the iOS namespace if it doesn't support it.

This would also apply to any additional properties that were added on a platform-specific basis to a standard control.

Hopefully this was obvious but I just wanted to make sure it was documented. Or have I missed something and there's some way of automagically knowing which namespaces and controls can be safely or intentionally ignored and which can't?

birbilis commented 7 years ago

Indeed, Ignorable was used by Blend and other tools I think (mostly for design-time metadata I guess)

birbilis commented 7 years ago

could we have the same conditionals checking in XAML as in the codebehind? Copying from my comment at https://github.com/Microsoft/xaml-standard/issues/141#issuecomment-303555828

BTW, would be nice if XAML had support for conditional for parts of the XML tree (like XML comments with some special annotation). Older parsers would just ignore all those and newer ones would check only the parts that match the given conditionals. Could even do that with preparsing btw, at the IDE level I mean with some VS extension. That way I could write XAML that could be added as linked file at multiple projects in a solution

could do it with the Ignorable namespace maybe, like mentioned above (if previous XAML parsers do ignore it indeed), or with custom comments (although I'd prefer the Ignorable namespace pattern - question though about the ignorable is if there is any dummy logical grouping XAML tag that one can use with the ignorable to avoid putting related namespace at multiple tags [I mean put at a parent grouping tag instead for it to work like it would if specially annotated comments - that can contain multiple tags - where used])

birbilis commented 7 years ago

Just noticed the use of OnPlatform tag at a Xamarin sample: https://blog.xamarin.com/accessbility-xamarin-forms

<toolkit:EntryLine
        Text="{Binding Email}" 
        Keyboard="Email"
        HorizontalOptions="FillAndExpand"
        Placeholder="email address"
        x:Name="EntryEmail"
        StyleId="EmailTextField"
        IsEnabled="{Binding IsNotBusy}"
        BorderColor="#ECECEC" 
        AutomationProperties.Hint="Enter your email here" 
        AutomationProperties.IsInAccessibleTree="true" 
        AutomationProperties.Name="Email entry field">

        <toolkit:EntryLine.HorizontalTextAlignment>
            <OnPlatform x:TypeArguments="TextAlignment" iOS="Center"/>
        </toolkit:EntryLine.HorizontalTextAlignment>
</toolkit:EntryLine>

Seems they use it here for platform specific properties (so it could cover the issue https://github.com/Microsoft/xaml-standard/issues/70), but if it allows child nodes, then one could put platform-specific markup in it. As long as parent nodes that expect specific child nodes skip the OnPlatform node in their checks (are there any such?) and check its children instead (plus treat multiple platform nodes or nested ones correctly in any checks)

Mike-E-angelo commented 7 years ago

Am I to understand that iOS is a property of OnPlatform? Is OnPlatform a markup extension? Just not a fan of tightly coupling a platform to ... well, anything. 😛

birbilis commented 7 years ago

as I commented at that accessibility issue:

Actually there are several issues logged already (#14, #35, #70) on both platform specific markup and platform specific properties. Despite one's personal taste there are scenarios where those are needed, especially to cover cases till something is added/standardized at a newer evolution cycle in the XAML standard

birbilis commented 7 years ago

btw, the "Ignorable" mentioned above should make it work with older XAML implementations that honor, whereas they'd choke upon OnPlatform. However, not sure what a node that expects a certain child subnode does if they find that child under an ignorable namespace (do they treat it as if it had the default namespace or does the parser strip the ignorable namespace when it understands it and loads the child node under the default namespace? or can one chain namespaces like <iOS:someNamespace:someTag ...> when iOS namespace is defined using Ignorable which would be the best option?)

birbilis commented 7 years ago

btw, the "Ignorable" mentioned above should make it work with older XAML implementations that honor it, whereas they'd choke upon OnPlatform.

However, not sure what a node that expects a certain child subnode does if they find that child under an ignorable namespace (do they treat it as if it had the default namespace or does the parser strip the ignorable namespace when it understands it and loads the child node under the default namespace? or can one chain namespaces like <iOS:someNamespace:someTag ...> when iOS namespace is defined using Ignorable which would be the best option?)

Mike-E-angelo commented 7 years ago

(Answering here as it seems more relevant.)

Don't get me wrong, I'm OK with platform-specific markup. I am just not a fan of tightly-coupling it with the mechanism that is responsible with implementing its behavior. It would seem you would have a Platforms (attached?) property with different platform profiles with each offering its own set of definitions and associated behaviors. I know it doesn't correlate very well, but I am thinking of the VisualStateManager and how it had its groups of states. Groups in this case would be the platforms.

Think of it this way: What happens when the next latest and greatest platform hits (and it will). How will that look? The way it is setup now, you have to go through each and every class that implements in this way and update with a new property with the name of the platform. Rather than simply introducing a new platform profile and be done with it.

birbilis commented 7 years ago

@Mike-EEE what would a platform profile do though? who would introduce it? you wouldn't need to update platform specific stuff when they get some standard name, they would be available (possibly deprecated if renamed at standard) at those platforms even after they get standardized. So would just remove optionally the platform specific prefix if such is used (with the Ignorable approach I mean) instead of OnPlatform that Xamarin seems to use currently (with that one you'd have to remove those OnPlatform tags if you want to modernize to the standardized version of something)

monkeynoises commented 7 years ago

Lets say you have developed an app using XF "5"....and one of the platforms you are targeting is IOS 14.

Apple then release IOS 15, and a new XF comes out say 5.1 that aligns with support for the new native controls - you decide to use some of the new controls in IOS 15 in your XAML.

You want to create an app that targets IOS 14, and IOS 15....as not everyone has moved to 15......you just want the new controls to light up if on IOS 15

OR

you want to be able to target/build packages, one for IOS 14, and one for IOS 15, from one code base.

Will this be doable?

Mike-E-angelo commented 7 years ago

@birbilis I was hoping to somehow allude to some magic functionality without actually having to write pseudo-code. Silly me. 😄

The "platform profile" could simply be a profile used to describe a platform and/or particular version. Think of it like NuGet packages. So in the case above, it might look something like this:

<OnPlatform x:TypeArguments="TextAlignment">
    <x:Platform x:Name="iOS" Version="10">
        <Setter Value="Center" />
    </x:Platform>
</OnPlatform>

Or maybe even more succinctly:

<OnPlatform x:TypeArguments="TextAlignment">
    <x:Platform x:Name="iOS" Version="10">Center</x:Platform>
</OnPlatform>

Or maybe even more succinctly yet:

<OnPlatform x:TypeArguments="TextAlignment">
    <x:Platform x:Name="iOS" Version="10" Value="Center" />
</OnPlatform>

The actual "profile" is described/defined elsewhere. Furthermore, if the Version isn't used, then it defaults to any, iOS, etc (like NuGet). At the end of the day, this is a switch-case, much like VisualStateManager, which is why I referenced it earlier as an example.

nickrandolph commented 7 years ago

One of the challenges with platform specific functionality (either platform values, or platform controls) is that the standard would then need a mechanism for referring to each platform - this would seem to immediately close off the standard, limiting the number of platforms, without versioning the standard. With this in mind, I'm not sure platform specific features belong in the standard, or at least in the first version

Mike-E-angelo commented 7 years ago

@nickrandolph certainly not explicit platform details, but having a general container (profile) object that allows to describe the platform and capabilities which is then used to reference further functionality would be acceptable and worth considering.

michael-hawker commented 7 years ago

I think it's not only being able to call out to specific platforms, but also versions of those platforms like the conditional xaml setup.

I think it'd also be useful if the xaml could fall back on other controls on those platforms. i.e. if the XAML is specifying running on UWP then you could pull in a UWP based control from its current XAML platform.