How to access a property of an element of a page in xamarin forms from Android and IOS projects?
For example:
Button1.IsVisible = false;
but since the Android project.
you could access properties of page elements in the code behind file, but that is generally not a good or clean strategy.
A simple sample would be Page.xaml:
<Button x:Name="Button1" Content="Sample String"/>
And then in your Page.xaml.cs
Button1.IsVisible = false;
The better way is that you might want to check out the DataBinding mechanism:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/
As a small example you would have a BindingContext/ViewModel that implements INotifyPropertyChanged. With that you could go like this:
private bool _isVisible;
public bool IsVisible
{
get => this._isVisible;
set
{
if(this._isVisible != value){
this.IsVisible;
}
}
And then in your Page.xaml:
<Button IsVisibile="{Binding IsVisible} Content="Sample String"/>
You can set the BindingContext inside your Page.xaml.cs:
this.BindingContext = new ViewModel(); //If the properties are in a separate class (preferred)
this.BindingContext = this; //If the properties are in the page class
Thanks, I solved it with this:
MessagingCenter.Subscribe<object>(this, "btButton1Visible", (sender) =>
{
Button1.IsVisible = false;
});
Related
In my AppShell.xaml.cs page I can easily access the FlyoutItems of the Shell:
accountFlyoutItem.IsEnabled = false;
accountFlyoutItem.IsVisible = false;
However, how do you access these from another page? The only way I found was to try to iterate through the "Shell.Current.FlyoutItems". Is there a simpler way I'm missing?
Shell.Current.CurrentItem is used to get the current selected flyout .
If we want to access specific FlyoutItem after you named it in xaml (<FlyoutItem x:Name="a">) , we can get it from the following two ways
Create a global public variable in AppShell and assign the value in constructor.
public ShellItem AItem;
public AppShell()
{
InitializeComponent();
RegisterRoutes();
BindingContext = this;
AItem = a;
}
//In another page
var item = (Shell.Current as AppShell).AItem;
Create a method to return the item , in this way we don't need to create the public variable .
public ShellItem GetA()
{
return a;
}
//In another page
var item = (Shell.Current as AppShell).GetA();
I have an Xamarin Forms app with MvvmCross for Android and IOS and I would like to add a dark theme. My idea was to have to dictionaries with the ressources for either the dark or the light theme and load the one I need on startup.
I added this after I registered the dependencies in my MvxApplication:
if (Mvx.IoCProvider.Resolve<ISettingsManager>().Theme == AppTheme.Dark)
{
Application.Current.Resources.Add(new ColorsDark());
}
else
{
Application.Current.Resources.Add(new ColorsLight());
}
ColorsDark and ColorsLight are my ResourceDictionary. After that i can see the new Dictionary under Application.Current.Resources.MergedDictionaries but the controls can't find the resources as it seems. However it does work when I add it to the App.xaml
<ResourceDictionary Source="Style/ColorsDark.xaml" />
Do I have to put move that another part in the code or is that a wrong approach at all?
Personally don't like this approach at all. What i do: have a static class with all the colors, sizes etc. defined in static fields. At app startup or at app reload after changing skin just call ex: UiSettings.Init() for this ui definitions static class, like follows:
public static class UiSettings
{
public static Init()
{
if (Settings.AppSettings.Skin=="butterfly")
{
ColorButton = Color.Blue;
TitleSize= 12.0;
}
else
if (Settings.AppSettings.Skin=="yammy")
{
ColorButton = Color.Red;
if (Core.IsAndroid)
ButtonsMargin = new Thickness(0.5,0.6,0.7,0.8);
}
// else just use default unmodified field default values
}
public static Color ColorButton = Color.Green;
public static Thickness ButtonsMargin = new Thickness(0.3,0.3,0.2,0.2);
public static double TitleSize= 14.0;
}
in XAML use example:
Color= "{x:Static xam:UiSettings.ColorProgressBack}"
in code use example:
Color = UiSettings.ColorProgressBack;
UPDATE:
Remember that if you access a static class from different assemblies it is possible that you will access a fresh copy of it with default values where Init() didn't happen, if you face such case call Init() from this assembly too.
If you want something to load up when your app loads then you have to code it in App.xaml.cs
protected override void OnStart ()
{
if (Mvx.IoCProvider.Resolve<ISettingsManager>().Theme == AppTheme.Dark)
{
Application.Current.Resources.Add(new Xamarin.Forms.Style(typeof(ContentPage))
{
ApplyToDerivedTypes = true,
Setters = {
new Xamarin.Forms.Setter { Property = ContentPage.BackgroundImageProperty, Value = "bkg7.png"},
}
});
}
else
{
Application.Current.Resources.Add(new Xamarin.Forms.Style(typeof(ContentPage))
{
ApplyToDerivedTypes = true,
Setters = {
new Xamarin.Forms.Setter { Property = ContentPage.BackgroundImageProperty, Value = "bkg7.png"},
}
});
}
}
In this code I'm setting the BackgroungImage of all of my pages. Hope you'll get the idea from this code.
I have a Xamarin.Form MainPage:ContentPage with a ToolbarItems Bar on top. The toolbar items are bound to my ViewModel like so:
<ToolbarItem Text="Sync" Command="{Binding ReloadCommand}" >
</ToolbarItem>
The availability of the Item depends on some logic:
private bool canReloadExecute(object arg)
{
bool result = (!IsReloading && (App.GetPersistentSetting("DeviceID") != "") && (App.GetPersistentSetting("BuildingID") != ""));
return result;
}
There is a separate dialog controlling the DeviceID and BuildingID on a different settings page. Once any of those ids is entered it is persistently stored away
App.SetPersistentSetting("DeviceID",value);
Problem is, that the menu items don't change their appearance once my code uses popAsync() to return to the Main page. I need to restart my app to see the changes. According to the debugger, canReloadExecute isn't called. Why this?
What I tried to work around this issue is to force a refresh in the MainPage's OnAppearing method like this:
public void RefreshToolbarItems()
{
TestApp.ViewModels.MainViewModel mvm = (TestApp.ViewModels.MainViewModel)BindingContext;
mvm.RefreshToolbarItems();
}
... and in the ViewModel:
public void RefreshToolbarItems()
{
OnPropertyChanged("BuildingScanCommand");
OnPropertyChanged("ReloadCommand");
}
but this code runs through but changes nothing, while the Debugger shows that the routine is indeed firing the events, they seem to go nowhere.
Any ideas how I can get my menu going?
Edit 1: "Show command initalization"
I am not shre what specifically you mean, but here is the whole code dealing with the command:
private ICommand _reloadCommand;
public ICommand ReloadCommand => _reloadCommand ?? (_reloadCommand = new Command(ExecuteReloadCommand, canReloadExecute));
private bool _isReloading = false;
public bool IsReloading
{
get => _isReloading;
set
{
_isReloading = value;
((Command)_reloadCommand).ChangeCanExecute();
OnPropertyChanged(nameof(ReloadCommand));
}
}
private bool canReloadExecute(object arg)
{
bool result = (!IsReloading && (App.GetPersistentSetting("DeviceID") != "") && (App.GetPersistentSetting("BuildingID") != ""));
return result;
}
private async void ExecuteReloadCommand(object obj)
{
IsReloading = true;
// Some code ...
IsReloading = false;
}
The goal is to disable the command, if either the command handler is already running, or if the configuration of DeviceID and/or BuildingId hasn't been done yet.
The enable/disable does almost work, if I set the DeviceId and BuildingId, and restart the app, the command is properly enabled or disabled. It doesn't work, however, if I set the Ids in a sub-page and return to the main page.
meanwhile I came to the conclusion, that firing onPropertyChange obviously doesn't make the command check its canReloadExecute. So the question is, how do I trigger this?
I finally solved the issue myself, this code works nicely for me:
public void RefreshToolbarItems()
{
((Command)BuildingScanCommand).ChangeCanExecute();
((Command)ReloadCommand).ChangeCanExecute();
}
Well then , I got something like this in my manipange.xaml , my application bar declaration, and my button declaration/definition
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar x:Name="xxxx" IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton
x:Name="appBarRegisterButton"
IconUri="/Images/next.png"
Text="Login"
Click="appBarRegisterButton_Click_1" IsEnabled="True"/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
when i try to change some property from some other model, fe.
this is my registartion Model.
public RegisterViewModel()
{
RegisterTitle = Resources.AppResources.RegisterTitle;
Messenger.Default.Register<RegisterButtonPressed>(this, msg => AttemptToRegister(msg.reg));
}
private void AttemptToRegister(Register reg)
{
reg.appBarRegisterButton.IsEnabled = true;
}
It does not change,better my register button is a null object, anyone got a point how to solve this? ;/
You have to access the button like this:
var applicationBarIconButton = ApplicationBar.Buttons[0] as ApplicationBarIconButton;
if (applicationBarIconButton != null)
{
//do stuff
}
The index depending on where it is located in the appbar.
I am trying to write an application, but it is constantly crashing when using the uiimagepickercontroller. I thought that it might be because I was not disposing of the picker after each use, but it will often freeze up on first run as well. Usually I'll take a picture and it just freezes, never asking to "use" the picture.
Do you have any suggestions? Here is my code. Has anyone gotten this to work?
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
myPicker = new UIImagePickerController();
myPicker.Delegate = new myPickerDelegate(this);
myAlbumButton.Clicked += delegate {
if(UIImagePickerController.IsSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary)){
myPicker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
myPicker.AllowsEditing = true;
this.PresentModalViewController (myPicker, true);
}else{
Console.WriteLine("cannot get album");
}
};
myCameraButton.Clicked += delegate {
if(UIImagePickerController.IsSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)){
myPicker.SourceType = UIImagePickerControllerSourceType.Camera;
//myPicker.AllowsEditing = true;
this.PresentModalViewController (myPicker, true);
}else{
Console.WriteLine("cannot get camera");
}
};
}
private class myPickerDelegate : UIImagePickerControllerDelegate
{
private TestView _vc;
public myPickerDelegate ( TestView controller):base()
{
_vc = controller;
}
public override void FinishedPickingImage (UIImagePickerController myPicker, UIImage image, NSDictionary editingInfo)
{
// TODO: Implement - see: http://go-mono.com/docs/index.aspx?link=T%3aMonoTouch.Foundation.ModelAttribute
_vc.myImageView.Image = image;
myPicker.DismissModalViewControllerAnimated(true);
}
}
Try to call your event handlers code from the main thread by using BeginInvokeOnMainThread().
So my issue was very similar.
Instead of having a delegate class, I had the delegates inline for the picker.
For some reason the app froze every time after talking the image, not stopping in any breakpoint after that.
The solution that worked for me was to use this book:
http://www.scribd.com/doc/33770921/Professional-iPhone-Programming-with-MonoTouch-and-NET-C