Currently my location not updating when I change it to different location via emulator. But it will change after I restart my application. This is what I write when the app launch
private void Application_Launching(object sender, LaunchingEventArgs e)
{
IsolatedStorageSettings Settings = IsolatedStorageSettings.ApplicationSettings;
GeoCoordinate DefaultLocation = new GeoCoordinate(-6.595139, 106.793801);
Library.GPSServices MyGPS;
if (!Settings.Contains("FirstLaunch") || (bool)Settings["FirstLaunch"] == true)
{
Settings["FirstLaunch"] = false;
Settings["LastLocation"] = DefaultLocation;
Settings["SearchRadius"] = 1;
}
//If key not exist OR key value was set to false, ask for permission to use location
if (!Settings.Contains("LocationService") || (bool)Settings["LocationService"] == false)
{
var result = MessageBox.Show(
"Jendela Bogor need to know your location to work correctly, do you want to allow it?",
"Allow access to your location?",
MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
Settings["LocationService"] = true;
MyGPS = new Library.GPSServices();
}
else
{
Settings["LocationService"] = false;
}
Settings.Save();
}
else if ((bool)Settings["LocationService"] == true)
{
MyGPS = new Library.GPSServices();
}
}
I store my location in my application setting IsolatedStorage with name Settings["LastLocation"]
How should I do to constantly update my location in the Background using MVVM Pattern (MVVM-Light) so my PushPin on map in the ThirdPageView always updated?
EDIT
public GPSServices()
{
if ((bool)Settings["LocationService"] == true)
{
if (_watcher == null)
{
_watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
_watcher.MovementThreshold = 20;
}
StartWatcher();
_watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
_watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
}
else if ((bool)Settings["LocationService"] == false)
{
StopWatcher();
}
}
private void StartWatcher()
{
_watcher.Start();
}
private void StopWatcher()
{
if (_watcher != null)
_watcher.Stop();
}
private void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
if (e.Position.Location.IsUnknown)
{
MessageBox.Show("Please wait while your position is determined....");
return;
}
Settings["LastLocation"] = e.Position.Location;
Settings.Save();
}
System.Device.Location.GeoCoordinateWatcher provides what you need.
var geoWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
// This event fires every time the device location changes
geoWatcher.PositionChanged += (s, e) => {
//e.Position.Location will contain the current GeoCoordinate
};
geoWatcher.TryStart(false, TimeSpan.FromMilliseconds(2000));
is this helpful for you ? using GeocoordinateWatcher.PositionChanged event?
public Location()
{
GeoCoordinateWatcher location == new GeoCoordinateWatcher();
location.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(location_PositionChanged);
location.Start();
}
//event to track the location change
public void location_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
}
Related
I'm trying to use maui webView to load a map.
how to use navigator.geolocation.getCurrentPosition to get location?
Android and kotlin has the same implementation。
You and use the code to get the location:
private CancellationTokenSource _cancelTokenSource;
private bool _isCheckingLocation;
public async Task GetCurrentLocation()
{
try
{
_isCheckingLocation = true;
GeolocationRequest request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromSeconds(10));
_cancelTokenSource = new CancellationTokenSource();
Location location = await Geolocation.Default.GetLocationAsync(request, _cancelTokenSource.Token);
if (location != null)
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
}
catch (Exception ex)
{
// Unable to get location
}
finally
{
_isCheckingLocation = false;
}
}
public void CancelRequest()
{
if (_isCheckingLocation && _cancelTokenSource != null && _cancelTokenSource.IsCancellationRequested == false)
_cancelTokenSource.Cancel();
}
Here is the website which you can refer to: https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/device/geolocation?tabs=ios
I'm building a class that tracks orders origin to deliver packages, im getting an error message that states that FusedLocationProviderApi is deprecated and seems now i have to use FusedLocationProviderClient instead, when i applied FusedLocationProviderApi i also implemented a LocationListener a ConnectionCallback and GoogleaApiClient which i suppose should be removed.
how can i implemente this here
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tracking_order);
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
requestRuntimePermission();
}
else
{
if (checkPlayServices())
{
buildGoogleApiClient();
createLocationRequest();
}
}
displayLocation();
}
private void displayLocation() {
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
requestRuntimePermission();
}
else
{
mLastLocation = LocationServices.fused(null).getLastLocation(mGoogleApiClient);
if (mLastLocation != null)
{
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
LatLng yourLocation = new LatLng(latitude,longitude);
mMap.addMarker(new MarkerOptions().position(yourLocation).title("Tu ubicacion"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(yourLocation));
mMap.animateCamera(CameraUpdateFactory.zoomTo(17.0f));
}
else
{
Toast.makeText(this, "No se pudo obtener ubicacion", Toast.LENGTH_SHORT).show();
}
}
}
ended up with a new approach that worked finer
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tracking_order);
mService = Common.geoCodeService();
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mapFrag = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
mapFrag.getMapAsync(this);
}
public void onMapReady(GoogleMap googleMap)
{
mMap=googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(120000); // two minute interval
mLocationRequest.setFastestInterval(120000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Location Permission already granted
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
mMap.setMyLocationEnabled(true);
} else {
//Request Location Permission
checkLocationPermission();
}
}
else {
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
mMap.setMyLocationEnabled(true);
}
}
LocationCallback mLocationCallback = new LocationCallback(){
#Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
Log.i("MapsActivity", "Location: " + location.getLatitude() + " " + location.getLongitude());
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//Place current location marker
LatLng yourLocation = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(yourLocation);
markerOptions.title("Current Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
mCurrLocationMarker = mMap.addMarker(markerOptions);
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(yourLocation, 11));
//after add marker for your location add marker for this order
drawRoute(yourLocation,Common.currentRequest.getAddress());
}
}
};
The AutoCompleteTextField seems to work exactly as intended until I start backspacing in the TextField. I am not sure what the difference is, but if I type in something like "123 M" then I get values that start with "123 M". If I backspace and delete the M leaving "123 " in the field, the list changes, but it does not scroll to the top of the list.
I should note that everything works fine on the simulator and that I am experiencing this behavior when running a debug build on my iPhone.
EDIT: So this does not only seem to happen when backspacing. This image shows the results I have when typing in an address key by key. In any of the pictures where the list isn't viewable or is clipped, I am able to drag down on the list to get it to then display properly. I have not tried this on an Android device.
EDIT2:
public class CodenameOneTest {
private Form current;
private Resources theme;
private WaitingClass w;
private String[] properties = {"1 MAIN STREET", "123 E MAIN STREET", "12 EASTER ROAD", "24 MAIN STREET"};
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
}
public void start() {
if(current != null) {
current.show();
return;
}
Form form = new Form("AutoCompleteTextField");
form.setLayout(new BorderLayout());
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
protected boolean filter(String text) {
if(text.length() == 0) {
options.removeAll();
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
};
};
Container container = new Container(BoxLayout.y());
container.setScrollableY(true); // If you comment this out then the field works fine
container.add(ac);
form.addComponent(BorderLayout.CENTER, container);
form.show();
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
if(w != null) {
w.actionPerformed(null);
}
w = new WaitingClass();
String[] properties = getProperties(text);
if(Display.getInstance().isEdt()) {
Display.getInstance().invokeAndBlock(w);
}
else {
w.run();
}
return properties;
}
}
catch(Exception e) {
Log.e(e);
}
return null;
}
private String[] getProperties(String text) {
List<String> returnList = new ArrayList<>();
List<String> propertyList = Arrays.asList(properties);
for(String property : propertyList) {
if(property.startsWith(text)) {
returnList.add(property);
}
}
w.actionPerformed(null);
return returnList.toArray(new String[returnList.size()]);
}
class WaitingClass implements Runnable, ActionListener<ActionEvent> {
private boolean finishedWaiting;
public void run() {
while(!finishedWaiting) {
try {
Thread.sleep(30);
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
public void actionPerformed(ActionEvent e) {
finishedWaiting = true;
return;
}
}
public void stop() {
current = Display.getInstance().getCurrent();
if(current instanceof Dialog) {
((Dialog)current).dispose();
current = Display.getInstance().getCurrent();
}
}
public void destroy() {
}
}
I used this code on an iPhone 4s:
public void start() {
if(current != null){
current.show();
return;
}
Form hi = new Form("AutoComplete", new BorderLayout());
if(apiKey == null) {
hi.add(new SpanLabel("This demo requires a valid google API key to be set in the constant apiKey, "
+ "you can get this key for the webservice (not the native key) by following the instructions here: "
+ "https://developers.google.com/places/web-service/get-api-key"));
hi.getToolbar().addCommandToRightBar("Get Key", null, e -> Display.getInstance().execute("https://developers.google.com/places/web-service/get-api-key"));
hi.show();
return;
}
Container box = new Container(new BoxLayout(BoxLayout.Y_AXIS));
box.setScrollableY(true);
for(int iter = 0 ; iter < 30 ; iter++) {
box.add(createAutoComplete());
}
hi.add(BorderLayout.CENTER, box);
hi.show();
}
private AutoCompleteTextField createAutoComplete() {
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
#Override
protected boolean filter(String text) {
if(text.length() == 0) {
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
}
};
ac.setMinimumElementsShownInPopup(5);
return ac;
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
ConnectionRequest r = new ConnectionRequest();
r.setPost(false);
r.setUrl("https://maps.googleapis.com/maps/api/place/autocomplete/json");
r.addArgument("key", apiKey);
r.addArgument("input", text);
NetworkManager.getInstance().addToQueueAndWait(r);
Map<String,Object> result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData()), "UTF-8"));
String[] res = Result.fromContent(result).getAsStringArray("//description");
return res;
}
} catch(Exception err) {
Log.e(err);
}
return null;
}
I was able to create this issue but not the issue you describe.
I have a following scenario that I am trying to define in workflow foundation:
My workflow gets to a stage from which it can continue in 3 paths, each path has some conditions that must be satisfied before the path is taken. After each path is finished, a termination condition is checked, and if not terminated, the workflow gets back to the decision stage where the 3 paths are allowed.
I wanted to solve this with Pick activity, set up a branch with a trigger for each one (triggered by Receive), but I don't know how to add the conditions there (PickBranches have no conditions on them, just triggers).
You can implement your Custom Pick Activity to add new conditions.
namespace System.Activities.Statements
{
using System.Activities.DynamicUpdate;
using System.Activities.Validation;
using System.Collections.ObjectModel;
using System.Runtime;
using System.Runtime.Collections;
using System.Runtime.Serialization;
using System.Windows.Markup;
[ContentProperty("Branches")]
public sealed class Pick : NativeActivity
{
const string pickStateProperty = "System.Activities.Statements.Pick.PickState";
Collection<PickBranch> branches;
Variable<PickState> pickStateVariable;
Collection<Activity> branchBodies;
public Pick()
{
this.pickStateVariable = new Variable<PickState>();
}
protected override bool CanInduceIdle
{
get
{
return true;
}
}
public Collection<PickBranch> Branches
{
get
{
if (this.branches == null)
{
this.branches = new ValidatingCollection<PickBranch>
{
// disallow null values
OnAddValidationCallback = item =>
{
if (item == null)
{
throw FxTrace.Exception.ArgumentNull("item");
}
}
};
}
return this.branches;
}
}
protected override void OnCreateDynamicUpdateMap(NativeActivityUpdateMapMetadata metadata, Activity originalActivity)
{
metadata.AllowUpdateInsideThisActivity();
}
protected override void UpdateInstance(NativeActivityUpdateContext updateContext)
{
PickState pickState = updateContext.GetValue(this.pickStateVariable);
Fx.Assert(pickState != null, "Pick's Execute must have run by now.");
if (updateContext.IsCancellationRequested || pickState.TriggerCompletionBookmark == null)
{
// do not schedule newly added Branches once a Trigger has successfully completed.
return;
}
CompletionCallback onBranchCompleteCallback = new CompletionCallback(OnBranchComplete);
foreach (PickBranchBody body in this.branchBodies)
{
if (updateContext.IsNewlyAdded(body))
{
updateContext.ScheduleActivity(body, onBranchCompleteCallback, null);
}
}
}
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
if (this.branchBodies == null)
{
this.branchBodies = new Collection<Activity>();
}
else
{
this.branchBodies.Clear();
}
foreach (PickBranch branch in this.Branches)
{
if (branch.Trigger == null)
{
metadata.AddValidationError(new ValidationError(SR.PickBranchRequiresTrigger(branch.DisplayName), false, null, branch));
}
PickBranchBody pickBranchBody = new PickBranchBody
{
Action = branch.Action,
DisplayName = branch.DisplayName,
Trigger = branch.Trigger,
Variables = branch.Variables,
};
this.branchBodies.Add(pickBranchBody);
metadata.AddChild(pickBranchBody, origin: branch);
}
metadata.AddImplementationVariable(this.pickStateVariable);
}
protected override void Execute(NativeActivityContext context)
{
if (this.branchBodies.Count == 0)
{
return;
}
PickState pickState = new PickState();
this.pickStateVariable.Set(context, pickState);
pickState.TriggerCompletionBookmark = context.CreateBookmark(new BookmarkCallback(OnTriggerComplete));
context.Properties.Add(pickStateProperty, pickState);
CompletionCallback onBranchCompleteCallback = new CompletionCallback(OnBranchComplete);
//schedule every branch to only run trigger
for (int i = this.branchBodies.Count - 1; i >= 0; i--)
{
context.ScheduleActivity(this.branchBodies[i], onBranchCompleteCallback);
}
}
protected override void Cancel(NativeActivityContext context)
{
context.CancelChildren();
}
void OnBranchComplete(NativeActivityContext context, ActivityInstance completedInstance)
{
PickState pickState = this.pickStateVariable.Get(context);
ReadOnlyCollection<ActivityInstance> executingChildren = context.GetChildren();
switch (completedInstance.State)
{
case ActivityInstanceState.Closed:
pickState.HasBranchCompletedSuccessfully = true;
break;
case ActivityInstanceState.Canceled:
case ActivityInstanceState.Faulted:
if (context.IsCancellationRequested)
{
if (executingChildren.Count == 0 && !pickState.HasBranchCompletedSuccessfully)
{
// All of the branches are complete and we haven't had a single
// one complete successfully and we've been asked to cancel.
context.MarkCanceled();
context.RemoveAllBookmarks();
}
}
break;
}
//the last branch should always resume action bookmark if it's still there
if (executingChildren.Count == 1 && pickState.ExecuteActionBookmark != null)
{
ResumeExecutionActionBookmark(pickState, context);
}
}
void OnTriggerComplete(NativeActivityContext context, Bookmark bookmark, object state)
{
PickState pickState = this.pickStateVariable.Get(context);
string winningBranch = (string)state;
ReadOnlyCollection<ActivityInstance> children = context.GetChildren();
bool resumeAction = true;
for (int i = 0; i < children.Count; i++)
{
ActivityInstance child = children[i];
if (child.Id != winningBranch)
{
context.CancelChild(child);
resumeAction = false;
}
}
if (resumeAction)
{
ResumeExecutionActionBookmark(pickState, context);
}
}
void ResumeExecutionActionBookmark(PickState pickState, NativeActivityContext context)
{
Fx.Assert(pickState.ExecuteActionBookmark != null, "This should have been set by the branch.");
context.ResumeBookmark(pickState.ExecuteActionBookmark, null);
pickState.ExecuteActionBookmark = null;
}
[DataContract]
internal class PickState
{
[DataMember(EmitDefaultValue = false)]
public bool HasBranchCompletedSuccessfully
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public Bookmark TriggerCompletionBookmark
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public Bookmark ExecuteActionBookmark
{
get;
set;
}
}
class PickBranchBody : NativeActivity
{
public PickBranchBody()
{
}
protected override bool CanInduceIdle
{
get
{
return true;
}
}
public Collection<Variable> Variables
{
get;
set;
}
public Activity Trigger
{
get;
set;
}
public Activity Action
{
get;
set;
}
protected override void OnCreateDynamicUpdateMap(NativeActivityUpdateMapMetadata metadata, Activity originalActivity)
{
PickBranchBody originalBranchBody = (PickBranchBody)originalActivity;
if ((originalBranchBody.Action != null && metadata.GetMatch(this.Trigger) == originalBranchBody.Action) || (this.Action != null && metadata.GetMatch(this.Action) == originalBranchBody.Trigger))
{
metadata.DisallowUpdateInsideThisActivity(SR.PickBranchTriggerActionSwapped);
return;
}
metadata.AllowUpdateInsideThisActivity();
}
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
Collection<Activity> children = null;
if (this.Trigger != null)
{
ActivityUtilities.Add(ref children, this.Trigger);
}
if (this.Action != null)
{
ActivityUtilities.Add(ref children, this.Action);
}
metadata.SetChildrenCollection(children);
metadata.SetVariablesCollection(this.Variables);
}
protected override void Execute(NativeActivityContext context)
{
Fx.Assert(this.Trigger != null, "We validate that the trigger is not null in Pick.CacheMetadata");
context.ScheduleActivity(this.Trigger, new CompletionCallback(OnTriggerCompleted));
}
void OnTriggerCompleted(NativeActivityContext context, ActivityInstance completedInstance)
{
PickState pickState = (PickState)context.Properties.Find(pickStateProperty);
if (completedInstance.State == ActivityInstanceState.Closed && pickState.TriggerCompletionBookmark != null)
{
// We're the first trigger! We win!
context.ResumeBookmark(pickState.TriggerCompletionBookmark, context.ActivityInstanceId);
pickState.TriggerCompletionBookmark = null;
pickState.ExecuteActionBookmark = context.CreateBookmark(new BookmarkCallback(OnExecuteAction));
}
else if (!context.IsCancellationRequested)
{
// We didn't win, but we haven't been requested to cancel yet.
// We'll just create a bookmark to keep ourselves from completing.
context.CreateBookmark();
}
// else
// {
// No need for an else since default cancelation will cover it!
// }
}
void OnExecuteAction(NativeActivityContext context, Bookmark bookmark, object state)
{
if (this.Action != null)
{
context.ScheduleActivity(this.Action);
}
}
}
}
}
Hi I was wondering if EntityReference.Load method includes
If Not ref.IsLoaded Then ref.Load()
My question is basically:
Dim person = Context.Persons.FirstOrDefault
person.AddressReference.Load()
person.AddressReference.Load() 'Does it do anything?
It does Load again. I verified this by Profiler and it shown two queries. Default merge option is MergeOption.AppendOnly and it doesn't prevent from querying again. Code from Reflector:
public override void Load(MergeOption mergeOption)
{
base.CheckOwnerNull();
ObjectQuery<TEntity> query = base.ValidateLoad<TEntity>(mergeOption, "EntityReference");
base._suppressEvents = true;
try
{
List<TEntity> collection = new List<TEntity>(RelatedEnd.GetResults<TEntity>(query));
if (collection.Count > 1)
{
throw EntityUtil.MoreThanExpectedRelatedEntitiesFound();
}
if (collection.Count == 0)
{
if (base.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One)
{
throw EntityUtil.LessThanExpectedRelatedEntitiesFound();
}
if ((mergeOption == MergeOption.OverwriteChanges) || (mergeOption == MergeOption.PreserveChanges))
{
EntityKey entityKey = ObjectStateManager.FindKeyOnEntityWithRelationships(base.Owner);
EntityUtil.CheckEntityKeyNull(entityKey);
ObjectStateManager.RemoveRelationships(base.ObjectContext, mergeOption, (AssociationSet) base.RelationshipSet, entityKey, (AssociationEndMember) base.FromEndProperty);
}
base._isLoaded = true;
}
else
{
base.Merge<TEntity>(collection, mergeOption, true);
}
}
finally
{
base._suppressEvents = false;
}
this.OnAssociationChanged(CollectionChangeAction.Refresh, null);
}
Just for reference for anyone else finding the accepted answer, here is the extension method I created for my current project.
using System.Data.Objects.DataClasses;
namespace ProjectName
{
public static class EntityFrameworkExtensions
{
public static void EnsureLoaded<TEntity>(this EntityReference<TEntity> reference)
where TEntity : class, IEntityWithRelationships
{
if (!reference.IsLoaded)
reference.Load();
}
}
}
And usage:
Patient patient = // get patient
patient.ClinicReference.EnsureLoaded();
patient.Clinic.DoStuff();