Not being able to change Title in a Caliburn.Micro Conductor View using MahApps MetroWindow - caliburn.micro

I'm doing like so:
<Controls:MetroWindow x:Class="BS.Expert.Client.App.Views.ShellView"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ShowTitleBar="True"
Title="My Title">
The thing is that this is at the same time a defined main conductor on the main window with which I control navigation through other windows, so I'm not able to inherit from MetroWindow to at least trying change the title in the ViewModel:
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IShell
{
public ShellViewModel()
{
#region mahApps Theme Loading
var theme = ThemeManager.DetectAppStyle(Application.Current);
var appTheme = ThemeManager.GetAppTheme(App.Configuration.Theme);
ThemeManager.ChangeAppStyle(Application.Current, theme.Item2, appTheme);
#endregion
//TODO: Changing Title here is not possible ((MetroWindow)this).Title = "No way";
// Tudo bem na seguinte liña
LocalizeDictionary.Instance.Culture = new System.Globalization.CultureInfo("pt-BR");
ShowPageOne();
}
public void ShowPageOne()
{
ActivateItem(new PageOneViewModel());
}
}
How should I change the title?

When using the MVVM pattern you should never try to set anything on the view directly in the view model like this. Instead using data binding to accomplish this.
So you would have a property on your ShellViewModel with something like:
public string MyTitle
{
get { return _myTitle; }
set
{
_myTitle = value;
//Insert your property change code here (not sure of the caliburn micro version)
}
}
and in your window xaml it would be something like:
<Controls:MetroWindow
Title="{Binding MyTitle}"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
...
>

Related

Xamarin.Forms Update Label Text From a Service

I have a Label on MainPage.xaml. I can edit Label Text from MainPage.xaml.cs.
There is a foregroung service running as well. There is function in this service to check a value from SQLite DB for every 10 secs. When value changes, Label text should be updated. I tried binding but it is a bit confusing. I manage updating by using like this: (foreground service timer changes App.SomeValue)
protected override void OnAppearing()
{
lblSyncID.Text = App.SomeValue;
}
But I need to see changes without OnAppearing or any other navigation change.
EDIT:
With #Jason's suggestion I used Messaging Center (and also binding) and it works now:
MainPage.xaml:
<Label Text="{Binding AppWaitingRecordValue}" ...
MainPage.xaml.cs:
public partial class MainPage : ContentPage
{
private string appWaitingRecordValue;
public string AppWaitingRecordValue
{
get { return appWaitingRecordValue; }
set
{
appWaitingRecordValue = value;
OnPropertyChanged(nameof(AppWaitingRecordValue));
}
}
public MainPage()
{
InitializeComponent();
BindingContext = this;
AppWaitingRecordValue = "0";
MessagingCenter.Subscribe<App>((App)Application.Current, "AppRecord", (sender) =>
{
AppWaitingRecordValue = App.recordWaiting.ToString();
});
}
.
.
TimestampService.cs (from Project.Android):
// get i from DB
App.recordWaiting = i;
Xamarin.Forms.MessagingCenter.Send<App>((App)Xamarin.Forms.Application.Current, "AppRecord");

How could I change the Navigastion's page arrow in Xamarin Forms?

I'm creating an app using xamarin Forms (multiplatform), I'm using a Navigation page, but I want to change the arrow ("<-") to text ("back")
Do you know how could i do it?
Thanks
(I'm going to use it in an Android App, but I'm creating the app using Xamarin forms)
You could use custom renderer to remove the navigation icon and set it with text. But, when you do that, you need to capture the click of the text and simulate the back event.
Create the interface:
public class CustomNavigationPage : NavigationPage
{
public CustomNavigationPage(Page startupPage) : base(startupPage)
{
}
}
The implementation of Android:
[assembly: ExportRenderer(typeof(CustomNavigationPage),
typeof(NavigationPageRenderer_Droid))]
namespace NavigationPageDemo.Droid
{
public class NavigationPageRenderer_Droid : NavigationPageRenderer
{
public Android.Support.V7.Widget.Toolbar toolbar;
public Activity context;
public NavigationPageRenderer_Droid(Context context) : base(context)
{
}
protected override Task<bool> OnPushAsync(Page view, bool animated)
{
var retVal = base.OnPushAsync(view, animated);
context = (Activity)Forms.Context;
toolbar = context.FindViewById<Android.Support.V7.Widget.Toolbar>(Droid.Resource.Id.toolbar);
if (toolbar != null)
{
//if (toolbar.NavigationIcon != null)
//{
//toolbar.NavigationIcon = Android.Support.V7.Content.Res.AppCompatResources.GetDrawable(context, Resource.Drawable.back);
//toolbar.NavigationIcon = null;
toolbar.NavigationIcon = null;
toolbar.Title = "back";
toolbar.SetOnClickListener(new OnClick());
//}
}
return retVal;
}
protected override Task<bool> OnPopViewAsync(Page page, bool animated)
{
return base.OnPopViewAsync(page, animated);
}
}
public class OnClick : Java.Lang.Object, IOnClickListener
{
void IOnClickListener.OnClick(Android.Views.View v)
{
App.Current.MainPage.Navigation.PopAsync();
}
}
In the custom renderer, use the OnClickListener to capture the click on text.
when you are working with xamarin forms it is suggested make use of common components and make least use of custom renderer.
Now for your requirement you want to create custom navigation bar
so here is how you can do it.
Create BaseContent Page
Create a Control Template inside your base page your can follow this link
Inside your control template using a grid view place your label with text binding (Back),also your can place a label in center to show title of page again u can make use of template binding which u would come to know when u go through the link
Now inherit your main page with your basecontentpage page
add your control template inside your main page
turn off your navigation bar of your main page
and you are done, this would give u more power to add more things like image or toolbar in your navbar
also to dynamically handle your back button u can check the count from navigationstack if its 0 u can show Humburger Icon or if its more than 0 u can show your label using IsVisible True/False

How to set Exrin TabbedPage tab title?

Context
I am using the ExrinSampleMobileApp from the Exrin repository.
Question
How can I set the main and detail tab's title?
I tried to set the appropriate view's title with no effect (DetaiView and MainView)
Because everything is wrapped in a NavigationPage, you need to set the Title of the NavigationPage. The easiest way to do this is via the Stack.
When you pass through a new NavigationPage, set it's title, as shown here.
public class MainStack : BaseStack
{
public MainStack(IViewService viewService)
: base(new NavigationProxy(new NavigationPage() { Title = "My Title" }),
viewService,
Stacks.Main,
nameof(Main.Main))
{
ShowNavigationBar = false;
}
protected override void Map()
{
base.NavigationMap<AboutView, AboutViewModel>(nameof(Main.About));
base.NavigationMap<MainView, MainViewModel>(nameof(Main.Main));
base.NavigationMap<SettingsView, SettingsViewModel>(nameof(Main.Settings));
base.NavigationMap<View.ListView, ListViewModel>(nameof(Main.List));
base.NavigationMap<DetailView, DetailViewModel>(nameof(Main.Detail));
}
}

Xamarin.Forms UserControl using XAML and Custom Renderer

There are a few good examples already of how to create a "custom control" by -
Deriving a Class from View or an existing built-in control and then creating a custom renderer for it per platform.
http://blog.xamarin.com/using-custom-controls-in-xamarin.forms-on-android/
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/custom-renderer/
I want to create a "compound custom control OR usercontrol" which contains multiple elements which are defined in XAML (in the shared code), and then customised with a renderer (to say tweak the styling per platform).
Does anyone have an example of doing this please? A simple example with a view that has a bindable label and an entry box should be enough to show the main principles.
Here is what I have so far -
Defined a ContentView to represent our usercontrols layout and contents.
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="News.Forms.VisualNewsContentView">
<ContentView.Content>
<StackLayout>
<Label x:Name="MyLabel" Text="Label"></Label>
<Entry x:Name="MyEntry" Text="Entry"></Entry>
</StackLayout>
</ContentView.Content>
</ContentView>
with codebehind -
public partial class VisualNewsContentView : ContentView
{
public VisualNewsContentView ()
{
InitializeComponent ();
}
// Not sure if I need this to access Entry ...
public Entry GetEntry ()
{
return MyEntry;
}
}
Add an Android Custom Renderer for that ContentView, how do I access and customise natively parts / controls of the ContentView?
[assembly:ExportRenderer (typeof(VisualNewsContentView), typeof(VisualNewsRenderer))]
namespace News.Forms.Android
{
public class VisualNewsRenderer: ViewRenderer
{
public VisualNewsRenderer () { }
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
if (newModel != null) {
VisualNewsContentView newsContentView = newModel as VisualNewsContentView;
// i.e. How could I get hold of EditText etc so I could natively customise its appearance? When you use a built in renderer like EntryRenderer you can use Control to access native control.
Console.WriteLine (newsContentView.GetLabel ().Text);
EditText ed = (EditText)newsContentView.GetEntry ().???
}
}
}
}
Just can't quite get the pieces together to work, the ContentView seems to render fine on page but cannot work out how to access its Child Native controls in the viewrenderer.
Be nice to also show how you can use Binding for the Label and Entry Text values.
I do not want to have to define a custom renderer for each single label / entry etc of the usercontrol.
Is this what you meant?
Some properties to access the Xamarin.Forms controls:
public partial class VisualNewsContentView : ContentView
{
public VisualNewsContentView()
{
InitializeComponent();
}
public Label Label
{
get
{
return MyLabel;
}
set
{
MyLabel = value;
}
}
public Entry Entry
{
get
{
return MyEntry;
}
set
{
MyEntry = value;
}
}
}
Some magic inside the Renderer to customize the controls on the page:
[assembly:ExportRenderer (typeof(VisualNewsContentView), typeof(VisualNewsRenderer))]
namespace News.Forms.Android
{
public class VisualNewsRenderer: ViewRenderer
{
public VisualNewsRenderer () { }
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
if (newModel != null) {
VisualNewsContentView newsContentView = newModel as VisualNewsContentView;
newsContentView.Label.Text = "It´s some kind of..";
newsContentView.Entry.Text = "MAGIC!";
newsContentView.Entry.BackgroundColor = Color.Blue;
newsContentView.Entry.RotationX = 180;
newsContentView.Entry.Focus();
}
}
}
}
EDIT:
I don't know if it's possible to map your controls from the XAML-page to native controls. You could add the controls which you want to customize natively # the renderer.
[assembly:ExportRenderer (typeof(VisualNewsContentView), typeof(VisualNewsRenderer))]
namespace News.Forms.Android
{
public class VisualNewsRenderer: NativeRenderer
{
public VisualNewsRenderer () { }
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
if (newModel != null) {
LinearLayout layout = new LinearLayout (Application.Context);
layout.Orientation = Orientation.Vertical;
TextView tv = new TextView (Application.Context);
tv.Ellipsize = TextUtils.TruncateAt.Middle;
tv.Text = "It´s some kind of..";
EditText et = new EditText (Application.Context);
et.SetTextColor (Graphics.Color.Chocolate);
et.Text = "MAGIC!";
layout.AddView (tv);
layout.AddView (et);
SetNativeControl (layout);
}
}
}
}
But like this you won't be using your ContentView.. I'm sorry, I have nothing better than this..
My solution for customizing compound user control is make a custom control for each control used in compound user control.
For example, which this control:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="News.Forms.VisualNewsContentView">
<ContentView.Content>
<StackLayout>
<Label x:Name="MyLabel" Text="Label"></Label>
<Entry x:Name="MyEntry" Text="Entry"></Entry>
</StackLayout>
</ContentView.Content>
</ContentView>
I will do something like this:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:CustomControls="clr-namespace:App.CustomControls;assembly=App" x:Class="News.Forms.VisualNewsContentView">
<ContentView.Content>
<CustomControls:StackLayout>
<CustomControls:Label x:Name="MyLabel" Text="Label"></CustomControls:Label>
<CustomControls:Entry x:Name="MyEntry" Text="Entry"></CustomControls:Entry>
</CustomControls:StackLayout>
</ContentView.Content>
</ContentView>
Example class for CustomControls:StackLayout is:
(in StackLayout.cs)
using Xamarin.Forms;
namespace App.CustomControls
{
public class StackLayout : Xamarin.Forms.StackLayout
{
}
}
(in StackLayoutRenderer.cs for android project)
[assembly: ExportRenderer(typeof(App.CustomControls.StackLayout), typeof(App.Droid.CustomRenderers.StackLayoutRenderer))]
namespace App.Droid.CustomRenderers.MapView
{
public class StackLayoutRenderer : ViewRenderer<StackLayout, Android.Widget.LinearLayout>
{
protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
{
base.OnElementChanged(e);
}
}
}

Defining a custom UINavigationBar through subclassing removes navigation items

I'm trying to follow the standard approach to creating a custom UINavigationBar in order to change its background image, but have found an issue in the subclassing process. If I subclass UINavigationController, with the intent of overriding the virtual NavigationBar property to provide my own implementation, all navigation items (any left or right buttons, and the title view) disappear. At first I thought it was due to the background being rendered over top of the navigation items, but I can reproduce the problem with a no-op subclass.
It's reproducible with the following code:
[Register("NavigationBar")]
public class NavigationBar : UINavigationBar
{
public NavigationBar () : base()
{
}
public NavigationBar (NSCoder coder) : base(coder)
{
}
public NavigationBar (IntPtr ptr) : base(ptr)
{
}
public NavigationBar (NSObjectFlag t) : base(t)
{
}
public NavigationBar (RectangleF frame) : base(frame)
{
}
}
[Register("NavigationController")]
public class NavigationController : UINavigationController
{
private UINavigationBar _navBar;
public NavigationController () : base()
{
}
public NavigationController (NSCoder coder) : base(coder)
{
}
public NavigationController (IntPtr ptr) : base(ptr)
{
}
public NavigationController (NSObjectFlag t) : base(t)
{
}
public override UINavigationBar NavigationBar
{
get
{
if(_navBar == null)
{
return base.NavigationBar;
}
return _navBar;
}
}
public void SetNavigationBar(UINavigationBar navigationBar)
{
_navBar = (UINavigationBar)navigationBar;
}
}
Now, all you need to do to lose your navigation items is to use the custom classes instead of the default ones:
var navigationBar = new NavigationBar();
navigationBar.BarStyle = UIBarStyle.Black;
navigationBar.TintColor = HeaderColor;
var navigationController = new NavigationController();
navigationController.SetNavigationBar(navigationBar);
// ...
Well, your SetNavigationBar() method doesn't pass that down to the native base class and since you don't do any explicit drawing yourself, how is the native drawing code ever supposed to be invoked for your custom NavigationBar class?
In your example code, that NavigationBar is just floating around in space and never gets told to draw.
In order to subclass UINavigationBar, you must define the IntPtr constructor in your derived class and instantiate the UINavigationController using the public UINavigationController(Type navigationBarType, Type toolbarType) constructor. Example:
public class MyNavigationBar: UINavigationBar
{
public MyNavigationBar(IntPtr h) : base(h)
{
}
// Do something.
}
....
var navController = new UINavigationController(typeof(MyNavigationBar), typeof(UIToolbar));
Took me a while to figure it out. More information on this page: http://developer.xamarin.com/guides/ios/platform_features/introduction_to_ios_6/ in section Subclassing UINavigationBar.
Can you create a sample project where you're adding NavigationItems directly to a UINavigationController and then using the sub-classed UINavigationController/UINavigationBar causes these buttons to disappear?
Thanks,
ChrisNTR
After a lot of research and back and forth with Xamarin, the answer to this problem is that you must use an IB stub file that is essentially no-op, but exists to shuttle the desired base type for your navigation elements. There is a working example on my OSS project: http://github.com/danielcrenna/artapp

Resources