I'm trying to integrate the MvxGeolocation plugin for android and I'm having issues getting the watcher to fire the success event. It just does not fire.
I've followed the documentation from MvvmCross (https://github.com/MvvmCross/MvvmCross/wiki/MvvmCross-plugins#location).
As per the documentation I've created a separate Service that publishes messages to the ViewModel, rather than have the IMvxLocationWatcher hooked directly up to the ViewModel.
public class GeoLocationService: IGeoLocationService
{
private readonly IMvxLocationWatcher _watcher;
private readonly IMvxMessenger _messenger;
public GeoLocationService(IMvxLocationWatcher watcher, IMvxMessenger messenger)
{
_watcher = watcher;
_messenger = messenger;
_watcher.Start(new MvxLocationOptions(), OnLocation, OnError);
}
public void OnLocation(MvxGeoLocation location)
{
var message = new LocationMessage(this, location.Coordinates.Latitude, location.Coordinates.Longitude);
_messenger.Publish(message);
}
public void OnError(MvxLocationError error)
{
Mvx.Error("Seen location error {0}", error.Code);
}
}
The OnLocation(MvxGeoLocation location) method is meant to publish a message that my ViewModel subscribes too as you can see below:-
public class MainViewModel : MvxViewModel
{
private readonly MvxSubscriptionToken _token;
public MainViewModel(IMvxMessenger messenger)
{
_token = messenger.SubscribeOnMainThread<LocationMessage>(OnLocationMessage);
}
private void OnLocationMessage(LocationMessage locationMessage)
{
Lat = locationMessage.Lat;
Lng = locationMessage.Lng;
}
double _latitude;
public double Lat
{
get
{
return _latitude;
}
set
{
_latitude = value;
RaisePropertyChanged(() => Lat);
}
}
double _longitude;
public double Lng
{
get
{
return _longitude;
}
set
{
_longitude = value;
RaisePropertyChanged(() => Lng);
}
}
string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged(() => Name);
}
}
}
I've added Bootstrapper classes to the android application that resolve both the Messenger and LocationWatcher plugins. Ive also registered the GeoLocationService in the App class in my core library like this :-
public class App : MvxApplication
{
public App()
{
Mvx.ConstructAndRegisterSingleton<IGeoLocationService, GeoLocationService>();
Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<MainViewModel>());
}
}
I've also edited the AndroidManifest.Xml and added the following user permissions :-
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Im debugging this against a plugged in Device (Samsung S6 Edge).
Ive tested my view.xaml to ensure that binding is working by passing it some default values.. and everything is as expected.
The issue is that The Action in the Watcher class for Success or Error are never called.
Related
I am currently working on a blazor server project based on .NET 6. there is a requirement to get the geo location into the application. I have tried several ways but they don't work.is there anyone who knows about it ?? please help me.
This shows how to call the browser API to get the current position.
geoLocationJsInterop.js (wwwroot\scripts)
export function getCurrentPosition(dotNetHelper) {
const options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
function success(pos) {
const coord = {
latitude: pos.coords.latitude,
longitude: pos.coords.longitude,
accuracy: pos.coords.accuracy
};
dotNetHelper.invokeMethodAsync('OnSuccessAsync', coord);
}
function error(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
navigator.geolocation.getCurrentPosition(success, error, options);
}
GeoLocation.razor
#using Microsoft.JSInterop
#implements IAsyncDisposable
<button #onclick=#GetLocationAsync>Get Location</button>
#if (geoCoordinates is not null)
{
<div>
Latitude : #geoCoordinates.Latitude <br />
Longitude : #geoCoordinates.Longitude<br />
Accuracy : #geoCoordinates.Accuracy
</div>
}
#code {
private readonly Lazy<Task<IJSObjectReference>> moduleTask = default!;
private readonly DotNetObjectReference<GeoLocation> dotNetObjectReference;
private GeoCoordinates? geoCoordinates = null;
[Inject]
private IJSRuntime jsRuntime { get; set; } = default!;
public GeoLocation()
{
moduleTask = new(() => jsRuntime!.InvokeAsync<IJSObjectReference>(
identifier: "import",
args: "./_content/ChatClient.Core/scripts/geoLocationJsInterop.js")
.AsTask());
dotNetObjectReference = DotNetObjectReference.Create(this);
}
public async Task GetLocationAsync()
{
var module = await moduleTask.Value;
await module.InvokeVoidAsync(identifier: "getCurrentPosition", dotNetObjectReference);
}
[JSInvokable]
public async Task OnSuccessAsync(GeoCoordinates geoCoordinates)
{
this.geoCoordinates = geoCoordinates;
await InvokeAsync(StateHasChanged);
}
public async ValueTask DisposeAsync()
{
if (moduleTask.IsValueCreated)
{
var module = await moduleTask.Value;
await module.DisposeAsync();
}
}
public class GeoCoordinates
{
public double Latitude { get; set; }
public double Longitude { get; set; }
public double Accuracy { get; set; }
}
}
Note: Change the path of the .js file to suite your project. In this case I was referencing a RCL called ChatClient.Core.
args: "./scripts/geoLocationJsInterop.js" for your root project.
This component runs on either wasm or blazor-server.
API Docs
I am new to MvvmCross, I have a question with regards to binding in Android. I can bind to single property but unable to data bind to an object. Not sure what I am doing wrong but here it is:
Model class:
public class Login : MvxNotifyPropertyChanged
{
private string _email;
public string Email
{
get { return _email; }
set
{
SetProperty(ref _email, value);
}
}
public string Password { get; set; }
}
Snippet of View Model Class:
public class LoginOptionViewModel: MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public LoginOptionViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
LoginCommand =
new MvxAsyncCommand(async () => await _navigationService.Navigate<RegistrationViewModel>());
}
public IMvxAsyncCommand LoginCommand { get; set; }
private Login _loginInfo;
public Login LoginInfo
{
get
{
return _loginInfo ?? new Login();
}
set
{
_loginInfo = value;
RaisePropertyChanged(() => LoginInfo);
}
}
}
Snippet of Android Axml:
<EditText
android:id="#+id/loginEmailTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/EmailHint"
android:textColor="#color/darkNavy"
android:inputType="textEmailAddress"
local:MvxBind="Text LoginInfo.Email" />
Where am I going wrong, I have placed a breakpoint but do not see it being hit. This is binded to EditText but nothing appears to happen. Am I missing or doing something wrong in order to bind to an object property ?
MvvmCross object data binding
You could implement the MvxNotifyPropertyChanged interface, so the system could notifies clients that a property value has changed.
Modify your object to :
public class Login : MvxNotifyPropertyChanged
{
private string _email;
public string Email
{
get => _email;
set => SetProperty(ref _email, value);
}
}
In the MainViewModel :
private Login _login;
public Login Login
{
get
{
return _login ?? new Login() { Email = "=-="};
}
set
{
_login = value;
RaisePropertyChanged(() => Login);
}
}
Then use it in axml :
local:MvxBind="Text Login.Email"
It works fine on my side.
Update :
I cant reproduce your problem, but here is my complete code, hope this can help you :
public class MainViewModel : MvxViewModel
{
public MainViewModel()
{
}
public override Task Initialize()
{
return base.Initialize();
}
public IMvxCommand ResetTextCommand => new MvxCommand(ResetText);
private void ResetText()
{
Text = "Hello MvvmCross";
}
private string _text = "Hello MvvmCross";
public string Text
{
get { return _text; }
set { SetProperty(ref _text, value); }
}
private Login _login;
public Login Login
{
get
{
return _login ?? new Login() { Email = "=-="};
}
set
{
_login = value;
RaisePropertyChanged(() => Login);
}
}
}
public class Login : MvxNotifyPropertyChanged
{
private string _email;
public string Email
{
get => _email;
set => SetProperty(ref _email, value);
}
}
Effect.
Hello I have an error 500 (internal server error) when I run the code below. My issue is that I have no trace at all of the error. It seems that visual studio is unable to catch it.
The following code returns a Candidate if I try to add pers to candidate the code fail and i get error 500. The thing is PersonAddressDescription implement AddressDescription is inheritance the problem ?
public class CheckController : ApiController
{
public Candidate Get()
{
PersonAddressDescription pers = new PersonAddressDescription();
Candidate candidate = new Candidate();
//IF I REMOVE THIS NO PROBLEM
candidate.address = pers;
return candidate;
}
}
AddressDescription class
/// <remarks/>
[System.Xml.Serialization.XmlIncludeAttribute(typeof(CompanyAddressDescription))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(PersonAddressDescription))]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.17626")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.crif-online.ch/webservices/crifsoapservice/v1.00")]
public abstract partial class AddressDescription : object, System.ComponentModel.INotifyPropertyChanged {
private Location locationField;
private ContactItem[] contactItemsField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
public Location location {
get {
return this.locationField;
}
set {
this.locationField = value;
this.RaisePropertyChanged("location");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("contactItems", Order=1)]
public ContactItem[] contactItems {
get {
return this.contactItemsField;
}
set {
this.contactItemsField = value;
this.RaisePropertyChanged("contactItems");
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
PersonAddressDescription class that implement AddressDescription
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.17626")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.crif-online.ch/webservices/crifsoapservice/v1.00")]
public partial class PersonAddressDescription : AddressDescription {
private string firstNameField;
private string lastNameField;
private string maidenNameField;
private Sex sexField;
private bool sexFieldSpecified;
private string birthDateField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
public string firstName {
get {
return this.firstNameField;
}
set {
this.firstNameField = value;
this.RaisePropertyChanged("firstName");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=1)]
public string lastName {
get {
return this.lastNameField;
}
set {
this.lastNameField = value;
this.RaisePropertyChanged("lastName");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=2)]
public string maidenName {
get {
return this.maidenNameField;
}
set {
this.maidenNameField = value;
this.RaisePropertyChanged("maidenName");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public Sex sex {
get {
return this.sexField;
}
set {
this.sexField = value;
this.RaisePropertyChanged("sex");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool sexSpecified {
get {
return this.sexFieldSpecified;
}
set {
this.sexFieldSpecified = value;
this.RaisePropertyChanged("sexSpecified");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=4)]
public string birthDate {
get {
return this.birthDateField;
}
set {
this.birthDateField = value;
this.RaisePropertyChanged("birthDate");
}
}
}
I suspect that the object you retrieved (addResp) contains circular references somewhere in its object graph. Circular references cannot be JSON serialized.
For example try putting the following code inside your controller to test what happens when you attempt to JSON serialize this instance:
TypeIdentifyAddressResponse addResp = ws.identifyAddress("test");
string json = JsonConvert.SerializeObject(addResp);
UPDATE:
It seems that AddressDescription is an abstract class and your actual instance is PersonAddressDescription. You need to indicate that to the serializer by using the [KnownType] attribute:
[KnownType(typeof(PersonAddressDescription))]
[KnownType(typeof(CompanyAddressDescription))]
...
public abstract partial class AddressDescription : object, System.ComponentModel.INotifyPropertyChanged {
{
...
}
As an alternative if you don't want to further pollute your (already polluted) domain models with other attributes you could also define the known type inside your WebApiConfig.cs:
config.Formatters.XmlFormatter.SetSerializer<Candidate>(
new DataContractSerializer(typeof(Candidate),
new Type[] { typeof(PersonAddressDescription) }));
Using db4o client/server, updates are not working for collection properties of an object. I'm using transparent persistence, but that's not helping. Then, I changed my Collection property to ActivatableCollection, but no luck.
This is the server setup:
private void StartDatabase()
{
IServerConfiguration serverConfiguration = Db4oClientServer.NewServerConfiguration();
serverConfiguration.Networking.MessageRecipient = this;
serverConfiguration.Common.Add(new TransparentActivationSupport());
serverConfiguration.Common.Add(new TransparentPersistenceSupport());
string db4oDatabasePath = AppDomain.CurrentDomain.BaseDirectory;
string db4oDatabaseFileName = ConfigurationManager.AppSettings["db4oDatabaseFileName"];
int databaseServerPort = Convert.ToInt32(ConfigurationManager.AppSettings["databaseServerPort"], CultureInfo.InvariantCulture);
_db4oServer = Db4oClientServer.OpenServer(serverConfiguration, db4oDatabasePath + db4oDatabaseFileName, databaseServerPort);
string databaseUser = ConfigurationManager.AppSettings["databaseUser"];
string databasePassword = ConfigurationManager.AppSettings["databasePassword"];
_db4oServer.GrantAccess(databaseUser, databasePassword);
}
This is the entity that I want to save:
public class Application : ActivatableEntity
And this is the property within the Application entity:
public ActivatableCollection<TaskBase> Tasks { get; private set; }
This is the client code to update each object within the collection:
Application application = (from Application app in db
where app.Name == "Foo"
select app).FirstOrDefault();
foreach (TaskBase task in application.Tasks)
{
task.Description += ".";
}
db.Store(application);
Curiously, db.Commit() didn't work either.
There are two work-arounds, but I'd rather do this the "right" way.
Work-around 1: Call db.Store(task) on each task as the change is made.
Work-around 2: Before calling db.Store(), do this:
db.Ext().Configure().UpdateDepth(5);
Can anyone tell me why the list isn't updating?
If it helps, here is the ActivatableCollection class:
public class ActivatableCollection<T> : Collection<T>, IActivatable
{
[Transient]
private IActivator _activator;
/// <summary>
/// Activates the specified purpose.
/// </summary>
/// <param name="purpose">The purpose.</param>
public void Activate(ActivationPurpose purpose)
{
if (this._activator != null)
{
this._activator.Activate(purpose);
}
}
/// <summary>
/// Binds the specified activator.
/// </summary>
/// <param name="activator">The activator.</param>
public void Bind(IActivator activator)
{
if (_activator == activator) { return; }
if (activator != null && null != _activator) { throw new System.InvalidOperationException(); }
_activator = activator;
}
}
Indeed, transparent persistence needs a call to it's activator before every field access. However the intentions is that you do this with the enhancer-tool instead of implementing manually.
Another note: When you're using CascadeOnUpdate(true) everywhere db4o will end up storing every reachable activated object. If the object-graph is huge, this can be a major performance bottle-neck.
I was able to get transparent activation and persistence to work. I decided not to go with the approach for the reasons mentioned in my comment above. I think the easiest way to handle cascading updates is to simply use a client config like this:
IClientConfiguration clientConfig = Db4oClientServer.NewClientConfiguration();
And then either a bunch of these (this isn't so bad because we can add an attribute to every domain entity, then reflectively do this on each one):
clientConfig.Common.ObjectClass(typeof(Application)).CascadeOnUpdate(true);
Or this:
clientConfig.Common.UpdateDepth = 10;
return Db4oClientServer.OpenClient(clientConfig, databaseServerName, databaseServerPort, databaseUser, databasePassword);
Now, here is the server config that allowed me to get transparent persistence working.
private void StartDatabase()
{
IServerConfiguration serverConfiguration = Db4oClientServer.NewServerConfiguration();
serverConfiguration.Networking.MessageRecipient = this;
serverConfiguration.Common.Add(new TransparentActivationSupport());
serverConfiguration.Common.Add(new TransparentPersistenceSupport());
string db4oDatabasePath = AppDomain.CurrentDomain.BaseDirectory;
string db4oDatabaseFileName = ConfigurationManager.AppSettings["db4oDatabaseFileName"];
int databaseServerPort = Convert.ToInt32(ConfigurationManager.AppSettings["databaseServerPort"], CultureInfo.InvariantCulture);
_db4oServer = Db4oClientServer.OpenServer(serverConfiguration, db4oDatabasePath + db4oDatabaseFileName, databaseServerPort);
string databaseUser = ConfigurationManager.AppSettings["databaseUser"];
string databasePassword = ConfigurationManager.AppSettings["databasePassword"];
_db4oServer.GrantAccess(databaseUser, databasePassword);
}
Hope this helps someone.
I had the same problem with Transparent Activation and Persistence in java. I managed to get it to work cleaning the database and starting from scratch. However, no works by calling commit() after changing the object graph. You must call store() on the root object.
This is a simple example:
/*************** Item.java ******************************************/
import com.db4o.activation.ActivationPurpose;
import com.db4o.activation.Activator;
import com.db4o.collections.ActivatableSupport;
import com.db4o.ta.Activatable;
public class Item implements Activatable {
private String name;
private transient Activator activator;
public Item(String name) {
this.name = name;
}
public String getName() {
activate(ActivationPurpose.READ);
return name;
}
public void setName(String name) {
activate(ActivationPurpose.WRITE);
this.name = name;
}
#Override
public String toString() {
activate(ActivationPurpose.READ);
return "Item [name=" + name + "]";
}
public void activate(ActivationPurpose purpose) {
ActivatableSupport.activate(this.activator, purpose);
}
public void bind(Activator activator) {
this.activator = ActivatableSupport.validateForBind(this.activator, activator);
}
}
/******************* Container.java *********************************/
import java.util.Set;
import com.db4o.activation.ActivationPurpose;
import com.db4o.activation.Activator;
import com.db4o.collections.ActivatableHashSet;
import com.db4o.collections.ActivatableSupport;
import com.db4o.ta.Activatable;
public class Container implements Activatable {
private String name;
private Set<Item> items;
private transient Activator activator;
public Container() {
items = new ActivatableHashSet<Item>();
}
public String getName() {
activate(ActivationPurpose.READ);
return name;
}
public void setName(String name) {
activate(ActivationPurpose.WRITE);
this.name = name;
}
public void addItem(Item item) {
activate(ActivationPurpose.WRITE);
items.add(item);
}
public Set<Item> getItems() {
activate(ActivationPurpose.READ);
return items;
}
#Override
public String toString() {
activate(ActivationPurpose.READ);
return "Container [items=" + items + "]";
}
public void activate(ActivationPurpose purpose) {
ActivatableSupport.activate(this.activator, purpose);
}
public void bind(Activator activator) {
this.activator = ctivatableSupport.validateForBind(this.activator, activator);
}
}
/************* Main.java ********************************************/
import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.config.EmbeddedConfiguration;
import com.db4o.ta.TransparentActivationSupport;
import com.db4o.ta.TransparentPersistenceSupport;
public class Main {
public static void main() {
EmbeddedConfiguration config = Db4oEmbedded.newConfiguration();
config.common().add(new TransparentActivationSupport());
config.common().add(new TransparentPersistenceSupport());
ObjectContainer db = Db4oEmbedded.openFile(config, System.getProperty("user.home") + "/testTP.db4o");
Container c = new Container();
c.setName("Container0");
ObjectSet<Container> result = db.queryByExample(c);
if(result.hasNext()) {
c = result.next();
System.out.println(c);
}
c.addItem(new Item("Item" + c.getItems().size()));
db.store(c);
System.out.println(c);
db.close();
}
}
I'd like TFS 2010 to run a bit of custom code whenever a particular workflow transition happens. Is that possible?
I've found documentation about Custom Actions, which seem to be actions that can automatically trigger work item transitions (am I getting that right?) I also found Custom Activities, which are related to Builds. But nothing that serves this particular requirement - am I missing something?
Thanks for your help!
This is very doable.
It is so doable, that there are many ways to do it. One of my favorites is to make a server side plugin. (Note, this only works on TFS 2010)
These blog posts show the basics:
In C#
In VB
Here is some code that I have modified from my open source project TFS Aggregator:
public class WorkItemChangedEventHandler : ISubscriber
{
/// <summary>
/// This is the one where all the magic starts. Main() so to speak.
/// </summary>
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs,
out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
{
statusCode = 0;
properties = null;
statusMessage = String.Empty;
try
{
if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
{
// Change this object to be a type we can easily get into
WorkItemChangedEvent ev = notificationEventArgs as WorkItemChangedEvent;
// Connect to the setting file and load the location of the TFS server
string tfsUri = TFSAggregatorSettings.TFSUri;
// Connect to TFS so we are ready to get and send data.
Store store = new Store(tfsUri);
// Get the id of the work item that was just changed by the user.
int workItemId = ev.CoreFields.IntegerFields[0].NewValue;
// Download the work item so we can update it (if needed)
WorkItem eventWorkItem = store.Access.GetWorkItem(workItemId);
if ((string)(eventWorkItem.Fields["State"].Value) == "Done")
{
// If the estimated work was changed then revert it back.
// We are in done and don't want to allow changes like that.
foreach (IntegerField integerField in ev.ChangedFields.IntegerFields)
{
if (integerField.Name == "Estimated Work")
{
eventWorkItem.Open();
eventWorkItem.Fields["Estimated Work"].Value = integerField.OldValue;
eventWorkItem.Save();
}
}
}
}
}
}
return EventNotificationStatus.ActionPermitted;
}
public string Name
{
get { return "SomeName"; }
}
public SubscriberPriority Priority
{
get { return SubscriberPriority.Normal; }
}
public WorkItemChangedEventHandler()
{
//DON"T ADD ANYTHING HERE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING.
//TFS DOES NOT LIKE CONSTRUCTORS HERE AND SEEMS TO FREEZE WHEN YOU TRY :(
}
public Type[] SubscribedTypes()
{
return new Type[1] { typeof(WorkItemChangedEvent) };
}
}
/// <summary>
/// Singleton Used to access TFS Data. This keeps us from connecting each and every time we get an update.
/// </summary>
public class Store
{
private readonly string _tfsServerUrl;
public Store(string tfsServerUrl)
{
_tfsServerUrl = tfsServerUrl;
}
private TFSAccess _access;
public TFSAccess Access
{
get { return _access ?? (_access = new TFSAccess(_tfsServerUrl)); }
}
}
/// <summary>
/// Don't use this class directly. Use the StoreSingleton.
/// </summary>
public class TFSAccess
{
private readonly WorkItemStore _store;
public TFSAccess(string tfsUri)
{
TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri(tfsUri));
_store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
}
public WorkItem GetWorkItem(int workItemId)
{
return _store.GetWorkItem(workItemId);
}
}
Here is an example of my singleton pattern
public class TFSSingleton
{
private static TFSSingleton _tFSSingletonInstance;
private TfsTeamProjectCollection _teamProjectCollection;
private WorkItemStore _store;
public static TFSSingleton Instance
{
get
{
if (_tFSSingletonInstance == null)
{
_tFSSingletonInstance = new TFSSingleton();
}
return _tFSSingletonInstance;
}
}
public TfsTeamProjectCollection TeamProjectCollection
{
get { return _teamProjectCollection; }
}
public WorkItemStore RefreshedStore
{
get
{
_store.RefreshCache();
return _store;
}
}
public WorkItemStore Store
{
get { return _store; }
}
private TFSSingleton()
{
NetworkCredential networkCredential = new NetworkCredential("pivotalautomation", "*********", "***********");
// Instantiate a reference to the TFS Project Collection
_teamProjectCollection = new TfsTeamProjectCollection(new Uri("http://********:8080/tfs/**********"), networkCredential);
_store = (WorkItemStore)_teamProjectCollection.GetService(typeof(WorkItemStore));
}
}
and here is how it is referenced.
WorkItemTypeCollection workItemTypes = TFSSingleton.Instance.Store.Projects[projectName].WorkItemTypes;