The code below was working until around preview 11 of Maui. But with preview 13 I get a compiler error: 'EntryHandler' does not contain a definition for 'EntryMapper'.
A similar error is shown for PickerMapper.
The code has been copied from the official documentation.
#if ANDROID
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
#endif
using Application = Microsoft.Maui.Controls.Application;
namespace myapp;
public partial class App : Application
{
public App(AuthenticationService authenticationService, SyncService syncService)
{
InitializeComponent();
// Remove underline from all pickers and entries in app
#if ANDROID
Microsoft.Maui.Handlers.PickerHandler.PickerMapper.AppendToMapping("NoUnderline", (h, v) =>
{
h.NativeView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());
});
Microsoft.Maui.Handlers.EntryHandler.EntryMapper.AppendToMapping("NoUnderline", (h, v) =>
{
h.NativeView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Colors.Transparent.ToAndroid());
});
#endif
MainPage = new AppShell(authenticationService, syncService);
}
}
Anyone who sees the solution?
I have been searching high and low, but the consensus seems to be that the code is correct.
I think all the EntryMapper and PickerMapper, basically all {Control}Mapper got renamed to just Mapper.
Additionally, I see you have references to NativeView whenever you upgrade to preview 14, those will be renamed to PlatformView so you will have to rename those accordingly as well.
Related
Seems like a simple question, but I haven't been able to find a simple answer. Essentially I want to choose which page in the app to start on based on some stored state. I added a GoToAsync call in the AppShell constructor, but this didn't work--which makes sense because the AppShell hasn't been fully constructed yet.
I found this answer, but it feels like it kind of skirts around the issue:
Maui AppShell - Navigate on Open
Where is the best place to inject some code that will run once on startup and can successfully navigate a .NET Maui app to a chosen page?
After playing around with overrides, it seems like overriding Application.OnStart works! Shell.Current is set at this point and navigation works.
Here's additional code that allows for asynchronous initialization and uses a Loading Page until the initialization is complete:
using MyApp.Services;
using MyApp.UI;
namespace MyApp;
public partial class App : Application
{
ConfigurationProviderService m_configProvider;
public App(ConfigurationProviderService configProvider)
{
m_configProvider = configProvider;
InitializeComponent();
MainPage = new LoadingPage();
}
protected override void OnStart()
{
var task = InitAsync();
task.ContinueWith((task) =>
{
MainThread.BeginInvokeOnMainThread(() =>
{
MainPage = new AppShell();
// Choose navigation depending on init
Shell.Current.GoToAsync(...);
});
});
base.OnStart();
}
private async Task InitAsync()
{
await m_configProvider.InitAsync();
}
}
I try to add LocalNotification to the application, everything works in Debug mode, but when I change to Release mode, notifications do not work.
Anyone know how to deal with it?
using Plugin.LocalNotification;
namespace TestNotif;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseLocalNotification()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
return builder.Build();
}
}
I got this error CS1061:
Severity Code Description Project File Line Suppression State
Error CS1061 'MauiAppBuilder' does not contain a definition for
'UseLocalNotification' and no accessible extension method
'UseLocalNotification' accepting a first argument of type
'MauiAppBuilder' could be found (are you missing a using directive or
an assembly reference?) TestNotif (net6.0-maccatalyst), TestNotif
(net6.0-windows10.0.19041.0) C:\Users---\source\repos\TestNotif\TestNotif\MauiProgram.cs 14 Active
using Plugin.LocalNotification;
using System;
namespace TestNotif;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
NotificationGet();
}
public async void Button_Clicked(object sender, EventArgs e)
{
var notification6 = new NotificationRequest
{
BadgeNumber = 1,
Description = "Test Description",
Title = "Notification!",
ReturningData = "Dummy Data",
NotificationId = 1327,
Schedule =
{
NotifyTime = DateTime.Now.AddSeconds(5)
}
};
await LocalNotificationCenter.Current.Show(notification6);
}
Fix #1: Only build for Android, to avoid errors when Maui attempts to build release for MacCatalyst and Windows:
Rt-click your Maui project, "Properties".
Application > General, find "iOS Targets > Target the iOS platform: Enable targeting of the iOS platform. UNCHECK.
Similarly find and UNCHECK: Windows Targets > Target ..: Enable targetting of the Windows platform.
Fix #2: Notifications don't work on Android:
Test on an actual device, not on an emulator.
If after both of these, it still doesn't work, then contact author of that plug-in for help.
I've seen various answers to this question for older versions but not sure how to translate to MAUI. The question being, is there a way that you can minimize the soft keyboard on a device from the Text Completed event of an Entry control?
I finally figured out how to do this. This solution is for Android only right now. It doesn't use a custom handler since I could not get the window token from PlatformView. Instead the code looks like this:
#if ANDROID
var imm = (Android.Views.InputMethods.InputMethodManager)MauiApplication.Current.GetSystemService(Android.Content.Context.InputMethodService);
if (imm != null)
{
//this stuff came from here: https://www.syncfusion.com/kb/12559/how-to-hide-the-keyboard-when-scrolling-in-xamarin-forms-listview-sflistview
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
Android.OS.IBinder wToken = activity.CurrentFocus?.WindowToken;
imm.HideSoftInputFromWindow(wToken, 0);
}
#endif
So credit to the syncfusion folks that published their version, and this code above is modified from that to work in MAUI.
The code belongs in a custom handler. Based on Customize a control with a mapper.
In that Maui handler, handler.PlatformView is the Android control. Xamarin.Android properties/methods would be on that.
Something like:
using Microsoft.Maui.Platform;
namespace CustomizeHandlersDemo;
public partial class CustomizeEntryPage : ContentPage
{
public CustomizeEntryPage()
{
InitializeComponent();
ModifyEntry();
}
void ModifyEntry()
{
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(
"MyCustomization", (handler, view) =>
{
#if ANDROID
handler.PlatformView....
#elif IOS
#elif WINDOWS
#endif
});
}
}
NOTE: That example modifies ALL Entries.
If you want to modify only SOME Entries, you instead define a subclass (e.g. public class MyEntry : Entry {}), and do this:
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(
"MyEntryCustomizationOrWhatever", (handler, view) =>
{
if (view is MyEntry)
{
#if ANDROID
handler.PlatformView....
#elif IOS
#elif WINDOWS
#endif
}
});
For your specific situation, the line you were having trouble adapting to Maui contains btnSignIn.WindowToken.
Replace that with handler.PlatformView.WindowToken.
I have a file chooser button that triggers a change in the titlebar whenever a file is selected with it. And it seems to work fine in my non-flatpak build.
import gtk.Application : Application;
import gtk.ApplicationWindow : ApplicationWindow;
import gio.Application : GioApp = Application;
import gtkc.gtktypes : GApplicationFlags, FileChooserAction;
import gtk.FileChooserButton : FileChooserButton;
const string AppID = `org.github.flatfcbtest`;
int main(string[] args)
{
auto app = new App();
return app.run(args);
}
public class App : Application
{
public:
this(const string appID = AppID, const GApplicationFlags flags = GApplicationFlags.FLAGS_NONE)
{
super(appID, flags);
addOnActivate(delegate void(GioApp _) {
auto pw = new PrimaryWindow(this);
pw.showAll();
});
}
}
class PrimaryWindow : ApplicationWindow
{
this(Application app)
{
super(app);
setSizeRequest(500, 300);
auto fcb = new FileChooserButton(`Select file`, FileChooserAction.OPEN);
fcb.addOnFileSet(delegate void (FileChooserButton _) {
setTitle(`file set!`);
});
add(fcb);
}
}
(GtkD reference)
However in my flatpak builds, the file selected with the chooser button does not select anything and it keeps saying (None). However my titlebar is changes accordingly so I know that the signal was emitted by the file chooser button.
Here is my flatpak permissions list:
finish-args:
- --socket=fallback-x11
- --share=ipc
- --filesystem=host
- --device=all
- --socket=session-bus
What's causing this?
Typically if you're shipping a flatpak, you want to avoid --filesystem=host and just use GtkFileChooserNative instead. This class supports portals, allowing a user to select files the application does not have permission to access by itself.
This is a much better approach than giving the application full filesystem access. GtkFileChooserNative will still work in a non-flatpak application and you shouldn't notice any difference unless you're doing something fancy.
As for your question of why GtkFileChooser is not working with --filesystem=host however, I do not know.
I’m trying to make work Akavache in a Windows Universal Application (8.1 for now, using ReactiveUI 6.5).
To make sure that it is not related to my architecture, I did an empty solution that has all the necessary packages and requirements (VC++ for both platforms), and I still get the same issue. This is a blocker for me since I want all my queries to be cached.
Here's the code:
BlobCache.ApplicationName = "MyApp"; // In AppBootstrapper`
// In My ViewModel
SubmitCommand = ReactiveCommand.CreateAsyncTask(async _ =>
{
var isTrue = await BlobCache.UserAccount.GetOrFetchObject("login_credentials",
async () => await Task.FromResult(true)
);
// My Code never goes further than this
if (!isTrue)
{
throw new Exception("I'm false!");
}
return isTrue;
});
SubmitCommand.Subscribe(isTrue => {
Debug.WriteLine("I got a new value!");
});
SubmitCommand.ThrownExceptions.Subscribe(ex => {
UserError.Throw(ex.Message, ex);
});
// In The View
ViewModel = new MainPageViewModel();
this.BindCommand(ViewModel, x => x.SubmitCommand, x => x.SubmitCommand);
public MainPageViewModel ViewModel
{
get { return (MainPageViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(MainPageViewModel), typeof(MainPage), new PropertyMetadata(null));
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (MainPageViewModel)value; }
}
Edit After some debug, Windows Phone 8.1 Silverlight works, not Jupiter.
So what's missing?
I'm using RXUI 6.5 (latest) with a Windows Phone 8.1 (Jupiter) (with shared Universal Projects)
Updated: Akavache.Sqlite3 is causing the issue. InMemoryCache is working (removing Akavache.Sqlite3 "fixes" the problem), but not Sqlite3.
Also, registering BlobCache's different types of cache (copy paste from https://github.com/akavache/Akavache/blob/3c1431250ae94d25cf7ac9637528f4445b131317/Akavache.Sqlite3/Registrations.cs#L32) is working apparently.. so I suppose the Registration class aren't working properly and calling
new Akavache.Sqlite3.Registrations().Register(Locator.CurrentMutable); is not working.
Edit: My temporary solution is to copy paste this into my application, and I invoke it after BlobCache.ApplicationName. It works, but I shouldn't technically have to do that.
Thanks for your help