Caliburn.Micro Xamarin.Forms ViewModel does not initialize - c#

I created a new Xamarin.Forms project and I'm having issues with the view model initializing. Nothing happens. I'm using the samples from the Features. I modified the sample code to the following:
public FormsApp(SimpleContainer container)
{
//...
DisplayRootView<ConductorView>();
}
This works as expected, but on my project it simply does not work.
I am using .NET Standard 1.5 (not sure if this is causing the issue). In any case here is my code
App.cs:
using System;
using Caliburn.Micro;
using Caliburn.Micro.Xamarin.Forms;
using UniversalSqlManager.ViewModels;
using Xamarin.Forms;
using INavigationService = Caliburn.Micro.Xamarin.Forms.INavigationService;
using UniversalSqlManager.Views;
namespace UniversalSqlManager
{
public class App : FormsApplication
{
private readonly SimpleContainer container;
public App(SimpleContainer container)
{
this.container = container;
container
.PerRequest<ShellViewModel>();
this.DisplayRootView<ShellView>();
}
protected override void PrepareViewFirst(NavigationPage navigationPage)
{
container.Instance<INavigationService>(new NavigationPageAdapter(navigationPage));
}
}
}
ShellView.xaml:
<?xml version="1.0" encoding="utf-8"?>
<TabbedPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:UniversalSqlManager"
x:Class="UniversalSqlManager.Views.ShellView"
xmlns:cm="clr-namespace:Caliburn.Micro.Xamarin.Forms;assembly=Caliburn.Micro.Platform.Xamarin.Forms"
ItemsSource="{Binding Items}"
SelectedItem="{Binding ActiveItem, Mode=TwoWay}"
Title="Universal SQL Manager">
<TabbedPage.ItemTemplate>
<DataTemplate>
<ContentPage Title="{Binding DisplayName}" cm:View.Model="{Binding}" />
</DataTemplate>
</TabbedPage.ItemTemplate>
</TabbedPage>
ShellView.xaml.cs:
using Xamarin.Forms;
namespace UniversalSqlManager.Views
{
public partial class ShellView
{
public ShellView()
{
InitializeComponent();
}
}
}
ShellViewModel.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using Caliburn.Micro;
using Caliburn.Micro.Xamarin.Forms;
using UniversalSqlManager.ViewModels.Interfaces;
namespace UniversalSqlManager.ViewModels
{
public class ShellViewModel : Conductor<ITabItem>.Collection.OneActive
{
protected override void OnInitialize()
{
//both view models implement ITabItem (which has no methods) and inherit form Screen
Items.Add(new ServersViewModel());
Items.Add(new SettingsViewModel());
ActivateItem(Items[0]);
}
}
}
I'll show iOS as that's the first platform I'm testing on
AppDelegate.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using Caliburn.Micro;
using Foundation;
using UIKit;
namespace UniversalSqlManager.iOS
{
[Register(nameof(AppDelegate))]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
private readonly CaliburnAppDelegate appDelegate = new CaliburnAppDelegate();
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(IoC.Get<App>());
return base.FinishedLaunching(app, options);
}
}
}
CaliburnAppdelegate.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Caliburn.Micro;
using UniversalSqlManager.ViewModels.Interfaces;
namespace UniversalSqlManager.iOS
{
public class CaliburnAppDelegate : CaliburnApplicationDelegate
{
private SimpleContainer container;
public CaliburnAppDelegate()
{
Initialize();
}
protected override void Configure()
{
container = new SimpleContainer();
container.Instance(container);
container.Singleton<App>();
container.Singleton<IEventAggregator, EventAggregator>();
}
protected override void BuildUp(object instance)
{
container.BuildUp(instance);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return container.GetAllInstances(service);
}
protected override object GetInstance(Type service, string key)
{
return container.GetInstance(service, key);
}
}
}
So when I run this the ShellView UI shows up, but the ShellViewModel does not get initialized and I get no tabs. Even if I switch to SettingsView or ServersView, the corresponding view models never get initialized. What am I doing wrong? This is my first time with Caliburn Micro on Xamarin.Forms. I've used WPF in the past without issues. Just the documentation is confusing, because it just seems like we have these examples to go by and some blogs that aren't as detailed as the WPF documentation. Any help would be appreciated. I can post my csproj and project.json if that will help too, but I'm hesitant to switch the project type as it was a pain to set that up. I guess another alternative would be to create a new project with a PCL and see if that works? Running out of ideas. Any help is appreciated!

So it turns out the problem was that I was not telling the framework which assemblies to use. The Features samples don't use libraries for the share code. So I added this to CaliburnAppDelegate.cs and to Application.cs to iOS and Android respectively:
protected override IEnumerable<Assembly> SelectAssemblies()
{
return this.GetAssemblies();
}
This is an extension I created in my class library:
public static class Bootstrapper
{
//...
public static IEnumerable<Assembly> GetAssemblies(this object o)
{
IEnumerable<Assembly> assemblies =
new[]
{
o.GetType().GetTypeInfo().Assembly,
typeof(ShellViewModel).GetTypeInfo().Assembly
};
return assemblies;
}
//...
}
and this solves the problem. I hope this help someone else who is having issues hooking up the sample using a class library. By the way I figured this out when comparing with the setup samples.

Related

Xamarin OnLaunched event

I'm looking to create styles (and eventually some of the pages) using C# code behind. Was looking at the write up on https://learn.microsoft.com/en-us/windows/apps/design/style/xaml-resource-dictionary and when I duplicate that code it gives me an error that LaunchActivatedEventArgs is unknown.
My starting App.xaml.cs file:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace FieldDataTemplateSelectorSample
{
sealed partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// add styles here
}
}
}
It doesn't know the type or namespace for LaunchActivatedEventArgs. If I look at the list of potential fixes, it suggests that I add a using for Windows.ApplicationModel.Activation to the list of usings. If I do that, then it complains about OnLaunched not having a suitable method to override. If I take out the override, and change the signature to
using System;
using Windows.ApplicationModel.Activation;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using FieldDataTemplateSelectorSample.AppStyles;
namespace FieldDataTemplateSelectorSample
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
protected void OnLaunched(LaunchActivatedEventArgs e)
{
Resources = InitStyles.GetAppStyles();
}
}
}
The application compiles but the OnLaunched method never gets hit if I put a break point in there. What am I missing? Right now I'm using a UWP project for getting my feet wet, and eventually will add android and ios.
Thanks
OnLaunched is a Windows or UWP API, not a Xamarin API.
Put your code in OnStart instead.
For cross-platform code, find "Windows.Forms" docs, instead of "Windows App Development" docs.
OR sometimes you'll want code in your .UWP or .Windows project - but I don't think this is one of those situations.

Google Maps Bindings Xamarin.Forms - Pins not showing on map when using BindingPinsBehavior

Kia ora StackOverFlow,
I'm creating a Google Maps page which has numerous bindings (I used Google Maps bindings). An example of this bindings is a pin bindings - as you will see below:
XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:maps="clr-namespace:Xamarin.Forms.GoogleMaps;assembly=Xamarin.Forms.GoogleMaps"
xmlns:bindings="clr-namespace:Xamarin.Forms.GoogleMaps.Bindings;assembly=Xamarin.Forms.GoogleMaps.Bindings"
x:Class="standard.MainPage">
<StackLayout>
<maps:Map VerticalOptions="FillAndExpand"
MyLocationEnabled="True">
<maps:Map.Behaviors>
<bindings:BindingPinsBehavior Value="{Binding Pins}" />
</maps:Map.Behaviors>
</maps:Map>
</StackLayout>
</ContentPage>
ViewModel:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms.GoogleMaps;
using Xamarin.Forms.GoogleMaps.Bindings;
namespace standard.ViewModels
{
public class MainPageViewModel : BaseViewModel
{
private ObservableCollection<Pin> _pins;
public ObservableCollection<Pin> Pins
{
get => _pins;
set
{
_pins = value;
RaisePropertyChanged();
}
}
public MainPageViewModel()
{
Pins = new ObservableCollection<Pin>();
Pins.Add(new Pin()
{
Type = PinType.Place,
Position = new Position(78,77)
});
}
}
}
Xaml.CS:
using standard.ViewModels;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.GoogleMaps;
namespace standard
{
public partial class MainPage : ContentPage
{
public MainPageViewModel MainPageViewModel;
public MainPage()
{
InitializeComponent();
this.BindingContext = MainPageViewModel = new MainPageViewModel();
}
}
Now - the problem is - I've set the BindingContext as expected but the pin is NOWHERE to be seen on the map.
It's important that I can see the pins on the map because I am making an app in which the user needs to see the location of the event/party. I also want a solution in an MVVM approach.
(using Android lollipop)
Where it should be on the map
image
This is my problem.
Thank you,
Kia pai to ra
Have a great day
Edit: Thank you to Leo Zhu who kind of solved my question - I am looking for an MVVM-based solution for now but thank you anyways
Things I've tried
Result
Tried to set the Binding of the pins using the default maps item template.
Still did not work or show on the map
Tried to call OnPropertyChanged after adding an item to the observable collection
Still the pin did not show on the map
Tried using a Pin instead of an ObservableCollections of Pins
Still the Pin was nowhere to be seen on the map
Tried setting the BindingContext of the map itself to the MainPageViewModel
Still the Pin is nowhere to be seen
Tried to use an earlier update of the Google Maps Binding NuGet package
Still - you guessed it - I cannot see the pin
Please do not initialize ObservableCollection<Pin> Pins.
MainPageViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms.GoogleMaps;
using Xamarin.Forms.GoogleMaps.Bindings;
namespace standard.ViewModels
{
public class MainPageViewModel : BaseViewModel
{
public ObservableCollection<Pin> Pins { get; set; }
public MainPageViewModel()
{
}
internal void AddPins()
{
Pins?.Add(new Pin()
{
Label = $"Pin1",
Position = new Position(78, 77)
});
}
}
}
Xaml.CS:
using standard.ViewModels;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.GoogleMaps;
namespace standard
{
public partial class MainPage : ContentPage
{
public MainPageViewModel MainPageViewModel;
public MainPage()
{
MainPageViewModel = new MainPageViewModel();
this.BindingContext = MainPageViewModel;
InitializeComponent();
MainPageViewModel.AddPins();
}
}
}
I meet the same issue, and one workaround was not to add a Pin in the viewModel's constructor, but in page.xaml.cs, as follows:
<maps:Map VerticalOptions="FillAndExpand" x:Name = "myMap"
MyLocationEnabled="True">
<maps:Map.Behaviors>
<bindings:BindingPinsBehavior Value="{Binding Pins}" />
</maps:Map.Behaviors>
</maps:Map>
public MapPage()
{
InitializeComponent();
myMap.Pins.Add(new Pin
{
Label = $"Pin1",
Position = new Position(78, 77)
});
}

Trying to use Application.Current in TestCase, however Application cannot be imported from System.Windows

I try to unit-test a Gui application code that uses
Application.Current.Dispatcher.Invoke() and would like to use the solution provided by #informatorius in the similar thread Using the WPF Dispatcher in unit tests. The code is listed below.
The problem I have is that Application is not resolved, even if I add using System.Windows. Is there some special mechanism to resolve
Application from within a class library that defines the testcases ?
I have the MSTest.TestFramework and MSTest.TestAdapter packages installed.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class ApplicationInitializer
{
[AssemblyInitialize]
public static void AssemblyInitialize(TestContext context)
{
var waitForApplicationRun = new TaskCompletionSource<bool>();
Task.Run(() =>
{
var application = new Application();
application.Startup += (s, e) => { waitForApplicationRun.SetResult(true); };
application.Run();
});
waitForApplicationRun.Task.Wait();
}
[AssemblyCleanup]
public static void AssemblyCleanup()
{
Application.Current.Dispatcher.Invoke(Application.Current.Shutdown);
}
}
[TestClass]
public class MyTestClass
{
[TestMethod]
public void MyTestMethod()
{
// implementation can access Application.Current.Dispatcher
}
}
Answer pointed me into the right direction:
using System.Windows is not enough, I also needed to add reference to PresentationFramework to the project. Dont really understand the auto magic behind that.

Castle Windsor StartableFacility does not start

I was following the example (Aggressive old mode) given in:
http://docs.castleproject.org/Default.aspx?Page=Startable-Facility&NS=Windsor&AspxAutoDetectCookieSupport=1
Here is my full source code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Castle.Facilities.Startable;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
namespace Test
{
public interface IStartable
{
void Start();
void Stop();
}
public class Startable : IStartable
{
public Startable()
{
Console.WriteLine("Created!");
}
public void Start()
{
Console.WriteLine("Started!");
}
public void Stop()
{
Console.WriteLine("Stopped!");
}
}
[TestFixture]
public class StartableFacilityContainerTest
{
[Test]
public void TestOperation()
{
IKernel container = new DefaultKernel();
container.AddFacility<StartableFacility>();
container.Register(Component.For<Startable>());
Console.WriteLine("Registered!");
container.Dispose();
Console.WriteLine("Released!");
}
}
}
However when I run it, I get:
Registered!
Released!
when I expect to get (as given in the example):
Created!
Started!
Registered!
Stopped!
Released!
Basically my Startable did not start.
This is tested in .Net 4.0 and Castle Windsor 3.0
What did I do wrong?
I'm using Installers. This helped me:
container.AddFacility<StartableFacility>(f => f.DeferredTryStart());
try
container.Register(Component.For<Startable>()
.StartUsingMethod(s => s.Start)
.StopUsingMethod(s => s.Stop);
The problem is you have created and implemented your own IStartable interface instead of just implementing the Castle.Core.IStartable

How does one use ManagementEventWatcher to keep track of suspend/resume?

I am trying to use ManagementEventWatcher in a service to keep track of when a computer goes in and out of sleep mode. I am new to .NET and C# so I am struggling quite a bit to come up with syntax to make this work.
I have found a blog post that details how he used ManagementEventWatcher to keep track of this status, but he did not post up his entire code. I am trying to go through and make a simple service that creates a .txt log file stating that the computer has been suspended/resumed but am running into problems with the namespaces and types.
Here is the code to the service.cs file:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Management;
namespace SleepNotifierService
{
public class WqlEventQuery : EventQuery { }
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WqlEventQuery query = new WqlEventQuery("Win32_PowerManagementEvent");
_watcher = new ManagementEventWatcher(query);
_watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
_watcher.Start();
}
protected override void OnStop()
{
_watcher.Stop();
}
void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
try
{
int eventType = Convert.ToInt32(e.NewEvent.Properties["EventType"].Value);
switch (eventType)
{
case 4:
Sleep();
break;
case 7:
Resume();
break;
}
}
catch (Exception ex)
{
//Log(ex.Message);
}
}
public void Sleep()
{
}
public void Resume()
{
}
}
}
Again, this is the first time that I am programming with .NET and C# so I apologize for my ignorance.
I am getting namespace errors such as:
The type or namespace name
'ManagementEventWatcher' could not be
found (are you missing a using
directive or an assembly reference?)
Thanks,
Tomek
You need the System.Management namespace, which is included in the code sample provided by you. I believe you need to reference the System.Management library in your project settings. Follow the following steps to do this( I am assuming you are suing Visual Studio):
Go to the Solution Explorer, and expand your project, right click on the References folder/option and select Add References from the context menu. Now select the .Net tab and select the System.Management from the list and click OK.

Categories