I implemented a blur behavior for images in a .NET MAUI app using multi-targetting so that it is available in both Android and iOS.
The shared class looks like this:
public partial class BlurBehavior
{
public static readonly BindableProperty RadiusProperty = BindableProperty.Create(nameof(Radius), typeof(float), typeof(BlurBehavior), 10f, propertyChanged: OnRadiusChanged);
public float Radius
{
get => (float)GetValue(RadiusProperty);
set => SetValue(RadiusProperty, value);
}
static void OnRadiusChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (BlurBehavior)bindable;
if (behavior.imageView is null)
{
return;
}
behavior.SetRendererEffect(behavior.imageView, Convert.ToSingle(newValue));
}
}
The Android class like this:
public partial class BlurBehavior : PlatformBehavior<Image, ImageView>
{
ImageView? imageView;
protected override void OnAttachedTo(Image bindable, ImageView platformView)
{
imageView = platformView;
SetRendererEffect(platformView, Radius);
}
protected override void OnDetachedFrom(Image bindable, ImageView platformView)
{
SetRendererEffect(platformView, 0);
}
void SetRendererEffect(ImageView imageView, float radius)
{
if (OperatingSystem.IsAndroidVersionAtLeast(31))
{
var renderEffect = radius > 0 ? GetEffect(radius) : null;
imageView.SetRenderEffect(renderEffect);
}
else
{
}
}
static RenderEffect? GetEffect(float radius)
{
return OperatingSystem.IsAndroidVersionAtLeast(31) ?
RenderEffect.CreateBlurEffect(radius, radius, Shader.TileMode.Clamp!) :
null;
}
}
Both files are located in a subfolder (/Behaviors/BlurBehavior) and have specific suffixes (BlurBehavior.[Android|iOS|Shared].cs).
So that multi-targetting works, I added filter to the project file like this:
<!-- Android -->
<ItemGroup Condition="'$(TargetFramework)'!='net7.0-android'">
<Compile Remove="**\**\*.Android.cs" />
<None Include="**\**\*.Android.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
<Compile Remove="**\Android\**\*.cs" />
<None Include="**\Android\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
<!-- iOS -->
<ItemGroup Condition="'$(TargetFramework)'!='net7.0-ios'">
<Compile Remove="**\**\*.iOS.cs" />
<None Include="**\**\*.iOS.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
<Compile Remove="**\iOS\**\*.cs" />
<None Include="**\iOS\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
In Visual Studio, when I open the BlurBehavior.Android.cs file for instance and set the target platform dropdown to net7.0-android, the file looks good - no error messages. Also then I open the BlurBehavior.Shared.cs file, and set the target platform dropdown to either net7.0-android or net7.0-ios, everything looks fine.
However, when I try to compile the source, the compiler then gives me a lot of error messages about
- BlurBehavior not containing a definition for imageView
- BlurBehavior not containing a definition of SetRenderEffect
- The compiler not being able to convert the BindableObject type to my BlurBehavior type
- GetValue and SetValue not existing in the current context
It is as if the compiler is not able to understand that the partial classes belong together, so it is missing the point that the mentioned fields and methods are defined in the respective platform implementation...
I really feel like a blockhead... and I hope that anyone here has a good hint for me. :)
EDIT: When I select the target in the respective Drop Down (my Android device for example) and hit the "Play" button directly, building and deployment works. When I use the menu to build the solution instead, the errors above are reported...