Reputation: 11
In my ContentPage, I'm using an IMarkupExtension to localize Strings. How can I access the root ContentPage from the IMarkupExtension ProvideValue() Method?
Within the ProvideValue() method, I see no possibility to access the ContentPage object. But for error handling etc, I need to access some members of the ContentPage object.
ContentPage:
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
[...]
x:Name="Page1"
>
<ToolbarItem [...] Text="{local:Translate MENUE_LOGIN}" />
[...]
</ContentPage>
IMarkupExtension:
[ContentProperty("Text")]
public class TranslateExtension : IMarkupExtension
{
[...]
public string Text { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
// How can I access Page1 here???
}
}
As I don't can insert an object reference via constructor, how I can access the ContentPage at all to use its methods?
Upvotes: 0
Views: 255
Reputation: 13601
ParentObjects
You can use serviceProvider
to access the service that implements IProvideParentValues
; which in turn should be able to provide the parent-object(s) for target element.
Caution: This solution uses reflection, so use this option sparingly - as it might break with later versions of Xamarin.Forms
Note: Only tested with current version Xamarin.Forms <= 4.5.0
For example:
private PropertyInfo cachedPropertyInfo = null;
public object ProvideValue(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
throw new ArgumentNullException(nameof(serviceProvider));
var valueProvider = serviceProvider.GetService<IProvideValueTarget>()
?? throw new ArgumentException("serviceProvider does not provide an IProvideValueTarget");
cachedPropertyInfo = cachedPropertyInfo ??
valueProvider.GetType().GetProperty("Xamarin.Forms.Xaml.IProvideParentValues.ParentObjects", BindingFlags.NonPublic | BindingFlags.Instance);
if(cachedPropertyInfo != null)
{
var parentObjects = cachedPropertyInfo.GetValue(valueProvider) as IEnumerable<object>;
if (parentObjects == null)
throw new ArgumentException("Unable to access parent objects");
foreach (var target in parentObjects)
{
if (!(target is Page page))
continue;
// ---->>> Access target here for root parent page.
}
}
throw new XamlParseException($"Unable to access parent page");
}
This is how StaticResource
or Reference
extensions access the parent or root objects.
Ref: https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Xaml/MarkupExtensions/StaticResourceExtension.cs https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Xaml/MarkupExtensions/ReferenceExtension.cs
Upvotes: 1
Reputation: 687
While I don't always agree with using this method of notifying other classes and such via this method, this might be the best situation for you. Look into MessagingCenter
. This allows you to register strings as an event and when you notify the Exception event, your page can listen to that event and do the appropriate action(s).
Here is the documentation for Messaging Center
If you aren't displaying the error to the user and just logging it to a file or AppCenter
, you can register to listen for the particular MessagingCenter action via your logger class.
Upvotes: 0