Im using Xamarin Forms Maps and I implemented location button:
Map.IsShowingUser = true;
Also I added Permissions (Xamarin Essentials nuget) and implemented like this in my view model:
public class MapViewModel : BaseViewModel
{
public MapViewModel(CustomMap map)
{
Map = map;
GetPermissions();
Task.Run(async () => { await GetImage(); });
}
public void SetPins()
{
if (App.FilterPins != null && App.FilterPins.Count > 0)
{
Device.BeginInvokeOnMainThread(() =>
{
Map.CustomPins.Clear();
Map.CustomPins.AddRange(App.FilterPins);
foreach (var item in App.FilterPins)
{
Map.Pins.Add(item);
App.SelectedPin = item;
item.InfoWindowClicked += Pin_InfoWindowClicked;
}
Map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(App.SelectedPin.Position.Latitude, App.SelectedPin.Position.Longitude), Distance.FromMiles(1.0)));
OnPropertyChanged(nameof(Map.CustomPins));
OnPropertyChanged(nameof(Map));
});
}
else
{
GetMapDefaultData();
}
}
public void SetMapToSelectedPin()
{
Device.BeginInvokeOnMainThread(() =>
{
if (App.SelectedPin != null)
{
//gledam da li je u listi pinova App.FilterPins ili u DefaultPins (iz default servisa)
if (Map.CustomPins.Any(x => x.Id == App.SelectedPin.Id))
{
//focusOnPin
Map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(App.SelectedPin.Position.Latitude, App.SelectedPin.Position.Longitude), Distance.FromMiles(1.0)));
}
else
{
//add pin to list -> Map.Pins.Add(pin);
//focusonpin
if (App.FilterPins != null && App.FilterPins.Count > 0)
{
Map.CustomPins.Add(App.SelectedPin);
Map.Pins.Add(App.SelectedPin);
Map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(App.SelectedPin.Position.Latitude, App.SelectedPin.Position.Longitude), Distance.FromMiles(1.0)));
}
}
}
else
{
Map.MoveToRegion(MapSpan.FromCenterAndRadius(Constants.BelgradeCoordinates, Distance.FromMiles(1.0)));
}
OnPropertyChanged(nameof(Map));
});
}
private async Task GetImage()
{
App.PinImages = new List<PinImageResponseModel>();
var result = await ApiServiceProvider.GetPinImages();
Device.BeginInvokeOnMainThread(() =>
{
App.PinImages = result;
});
}
public CustomPin _pin { get; set; }
public CustomPin Pin
{
get { return _pin; }
set { _pin = value; OnPropertyChanged(); }
}
public ICommand PositionMapOnPinCommand { get; set; }
private async void GetMapDefaultData()
{
try
{
DefaultRegionsAndClassesResponseModel regionsAndPinsResponse = new DefaultRegionsAndClassesResponseModel();
#region Regions
var regions = await ApiServiceProvider.GetRegionsQuery(null, 0, 5000);
//if (regions != null && regions.Data != null)
//{
// var polygon = new Polygon();
// foreach (var region in regions.Data.Where(x => x.Checked).ToList())
// {
// polygon.StrokeWidth = 8;
// polygon.StrokeColor = Color.Green;
// polygon.FillColor = Color.FromRgba(255, 0, 0, 64);
// foreach (var point in region.Points)
// {
// polygon.Geopath.Add(new Position(point.Latitude, point.Longitude));
// }
// Map.MapElements.Add(polygon);
// }
//}
#endregion
#region Pins & Infoboxes
regionsAndPinsResponse = await ApiServiceProvider.GetDefaultRegionsAndClasses();
Device.BeginInvokeOnMainThread(() =>
{
if (regionsAndPinsResponse.Succeeded && regionsAndPinsResponse.Data != null && regionsAndPinsResponse.Data.Count > 0)
{
foreach (var mainItem in regionsAndPinsResponse.Data)
{
CustomPin pin = new CustomPin();
if (mainItem != null && mainItem.Points.Count > 0)
{
pin.Id = mainItem.IdObjectInstance;
pin.ClassId = mainItem.ObjectClassIdObjectClass;
pin.Label = mainItem.ObjectClassName;
pin.IsFavorite = mainItem.IsFavorite.HasValue;
foreach (var item in App.PinImages)
{
if (mainItem.Status != null && mainItem.Status.ClassStatus.ClassStatusIcon != null && item.Name.Equals(mainItem.Status.ClassStatus.ClassStatusIcon))
{
string base64 = item.Base64String.Substring(item.Base64String.IndexOf(',') + 1);
base64 = base64.Trim('\0');
pin.InfoBox.ImageString = base64;
if (pin.InfoBox.ImageString != null)
{
var source = Convert.FromBase64String(pin.InfoBox.ImageString);
pin.InfoBox.PinImageSource = ImageSource.FromStream(() => new MemoryStream(source));
}
}
}
if (mainItem.Points != null)
{
pin.Position = new Position(mainItem.Points.FirstOrDefault().Latitude, mainItem.Points.FirstOrDefault().Longitude);
}
else
{
//add polygon
}
foreach (var item in mainItem.Strings)
{
pin.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo { BoldLabelTitle = item.ClassParameterName + ": ", LabelValue = item.StringValue });
}
foreach (var item in mainItem.Integers)
{
pin.InfoBox.DetailsObjectInfos.Add(new Models.MapModels.DetailsObjectInfo { BoldLabelTitle = item.ClassParameterName + ": ", LabelValue = item.IntValue.ToString() });
}
}
pin.InfoWindowClicked += Pin_InfoWindowClicked;
Map.CustomPins.Add(pin);
Map.Pins.Add(pin);
}
}
});
#endregion
}
catch (Exception ex)
{
await Shell.Current.DisplayAlert("Error", "Something went wrong with maps", "OK");
}
}
private void Pin_InfoWindowClicked(object sender, PinClickedEventArgs e)
{
Device.BeginInvokeOnMainThread(async () =>
{
var pin = sender as CustomPin;
App.SelectedPin = pin;
await Shell.Current.Navigation.PushAsync(new ObjectParametersPage());
});
}
private async void GetPermissions()
{
var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
if (status != PermissionStatus.Granted)
{
status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
}
if (status == PermissionStatus.Granted)
{
Map.IsShowingUser = true;
}
else
{
await Shell.Current.DisplayAlert("Permission Denied", "We Need to access your Location. But it is not granted", "OK");
}
}
public CustomMap Map { get; set; }
public ICommand SetCameraToChosenPinCommand { get; set; }
}
My XAML:
</ContentPage>
<ContentPage.Content>
<renderers:CustomMap x:Name="map" IsShowingUser="True"/>
</ContentPage.Content>
</ContentPage>
CodeBehind:
public partial class MapPage : ContentPage
{
MapViewModel mapViewModel;
public MapPage()
{
InitializeComponent();
BindingContext = mapViewModel = new MapViewModel(map);
}
protected override void OnAppearing()
{
base.OnAppearing();
mapViewModel.SetPins();
mapViewModel.SetMapToSelectedPin();
}
}
my CustomMap:
public class CustomMap : Map
{
//public List<CustomPin> CustomPins { get; set; }
public CustomMap()
{
CustomPins = new ObservableCollection<CustomPin>();
CustomPins.CollectionChanged += PinsSourceOnCollectionChanged;
}
public ObservableCollection<CustomPin> CustomPins
{
get { return (ObservableCollection<CustomPin>)GetValue(PinsSourceProperty); }
set { SetValue(PinsSourceProperty, value); OnPropertyChanged(nameof(CustomPins)); }
}
public static readonly BindableProperty PinsSourceProperty = BindableProperty.Create(
propertyName: "PinsSource",
returnType: typeof(ObservableCollection<CustomPin>),
declaringType: typeof(CustomMap),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
validateValue: null,
propertyChanged: PinsSourcePropertyChanged);
public MapSpan MapSpan
{
get { return (MapSpan)GetValue(MapSpanProperty); }
set { SetValue(MapSpanProperty, value); }
}
public static readonly BindableProperty MapSpanProperty = BindableProperty.Create(
propertyName: "MapSpan",
returnType: typeof(MapSpan),
declaringType: typeof(CustomMap),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
validateValue: null,
propertyChanged: MapSpanPropertyChanged);
private static void MapSpanPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var thisInstance = bindable as CustomMap;
var newMapSpan = newValue as MapSpan;
thisInstance?.MoveToRegion(newMapSpan);
}
private static void PinsSourcePropertyChanged(BindableObject bindable, object oldvalue, object newValue)
{
var thisInstance = bindable as CustomMap;
var newPinsSource = newValue as ObservableCollection<CustomPin>;
if (thisInstance == null ||
newPinsSource == null)
return;
UpdatePinsSource(thisInstance, newPinsSource);
}
private void PinsSourceOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdatePinsSource(this, sender as IEnumerable<CustomPin>);
}
private static void UpdatePinsSource(CustomMap bindableMap, IEnumerable<CustomPin> newSource)
{
bindableMap.IsShowingUser = true;
bindableMap.Pins.Clear();
foreach (var pin in newSource)
bindableMap.Pins.Add(pin);
}
}
So, I have a bug only on first time installing app on my phone - it doesnt show location button, because its async method.
Each next tiem when I open the Map page there is a button.
So, my question would be: how to properly integrate permissions and map, in order to present location button on the first startup of application?
Related
I want to use Dynamic Data as WPF's CompositeCollection alternative in an AvaloniaUI project.
Here is some code to expose the issue :
public class MainWindowViewModel : ViewModelBase
{
private readonly ReadOnlyObservableCollection<ViewModelBase> _testBind;
public ReadOnlyObservableCollection<ViewModelBase> TestBind => _testBind;
public IObservable<IChangeSet<ViewModelBase>> SeveralListTypes { get; set; }
public IObservable<IChangeSet<ViewModelBase>> SeveralListTypes2 { get; set; }
public IObservable<IChangeSet<ViewModelBase>> SeveralListTypes3 { get; set; }
public ObservableCollection<ViewModelBase> ListTypesObject1 { get; set; }
public ObservableCollection<ViewModelBase> ListTypesObject2 { get; set; }
public ObservableCollection<ViewModelBase> ListTypesObject3 { get; set; }
public IObservable<IChangeSet<ViewModelBase>> InBoth { get; set; }
private readonly ReadOnlyObservableCollection<ViewModelBase> _testBindTypes;
public ReadOnlyObservableCollection<ViewModelBase> TestBindTypes => _testBindTypes;
public MainWindowViewModel()
{
// TODO : those object collections should be of the real type and not from ancestor
// ListTypesObject1 = new ObservableCollection<Object1>()
ListTypesObject1 = new ObservableCollection<ViewModelBase>()
{
new Object1(),
};
ListTypesObject2 = new ObservableCollection<ViewModelBase>()
{
new Object2(),
};
ListTypesObject3 = new ObservableCollection<ViewModelBase>()
{
new Object3(),
};
// Change observableCollection to IObservable to be running with engine ReactiveUI
SeveralListTypes = ListTypesObject1.ToObservableChangeSet();
SeveralListTypes2 = ListTypesObject2.ToObservableChangeSet();
SeveralListTypes3 = ListTypesObject3.ToObservableChangeSet();
//Group All Observable into one with Or operator
InBoth = SeveralListTypes.Or(SeveralListTypes2).Or(SeveralListTypes3);
// Bind => output to Binded Property for xaml
// Subscribe => to be notified when changes
var t = InBoth.Bind(out _testBindTypes)
.DisposeMany()
.Subscribe();
}
public void AddObject1()
{
var obj1 = new Object1("Added Object 1");
ListTypesObject1.Add(obj1);
}
public void AddObject2()
{
var obj2 = new Object2("Added Object 2");
ListTypesObject2.Add(obj2);
}
public void AddObject3()
{
if (ListTypesObject3 == null)
return;
var obj3 = new Object3("Added Object 3");
ListTypesObject3.Add(obj3);
}
public void DeleteObject1()
{
if(ListTypesObject1 != null && ListTypesObject1.Count > 0)
ListTypesObject1.RemoveAt(0);
}
public void DeleteObject2()
{
if (ListTypesObject2 != null && ListTypesObject2.Count > 0)
ListTypesObject2.RemoveAt(0);
}
public void DeleteObject3()
{
if (ListTypesObject3 != null && ListTypesObject3.Count > 0)
ListTypesObject3.RemoveAt(0);
}
public void DeleteObjectClear()
{
if (ListTypesObject3 == null)
return;
ListTypesObject3.Clear();
ListTypesObject3 = null;
ListTypesObject3 = new ObservableCollection<ViewModelBase>()
{
new Object3("Added object 3 from new list 3"),
};
SeveralListTypes3 = ListTypesObject3.ToObservableChangeSet();
InBoth = InBoth.Or(SeveralListTypes3);
// TODO : the collection we want to remove is still binded, the new one is not
}
public void DeleteObject3List()
{
if (ListTypesObject3 == null)
return;
ListTypesObject3.Clear();
ListTypesObject3 = null;
// TODO : remove the Object3List from DynamicData
}
public void CreateObject3List()
{
if (ListTypesObject3 != null)
return;
ListTypesObject3 = new ObservableCollection<ViewModelBase>()
{
new Object3("Added object 3 from new list 3"),
};
SeveralListTypes3 = ListTypesObject3.ToObservableChangeSet();
InBoth = InBoth.Or(SeveralListTypes3);
// TODO : the collection we want to remove is still binded, the new one is not
}
}
Object1,Object2 and Object3 are an heritage from ViewModelBase.
DeleteObjectClear method remove all Object3 from the binding but then the new list isn't displayed.
How to add or remove an ObservableCollection and refresh the binded object (TestBind) ?
As a second issue, is it possible to use the real type of object in ObservableCollection (with a common ancestor) instead of ViewModelBase and still use Dynamic Data to agregate all collections ?
Here is the full github repository POC to spotlight the issue : https://github.com/Whiletru3/pocbindingdmo
Thanks
I can't really do it only with DynamicData, so I came with this solution.
Not really elegant but it works...
I created an ObservableCollectionAggregate class. I can Assign and Unassign the different (typed) ObservableCollections.
public class ObservableCollectionAggregate : ObservableCollection<ViewModelBase>
{
private ObservableCollection<Object1> _subCollection1;
private ObservableCollection<Object2> _subCollection2;
private ObservableCollection<Object3> _subCollection3;
public ObservableCollectionAggregate()
{
_subCollection1 = null;
_subCollection2 = null;
_subCollection3 = null;
}
public void UnassignCollectionObject1()
{
if (_subCollection1 != null)
{
RemoveItems(_subCollection1);
_subCollection1.CollectionChanged -= OnSubCollectionChanged;
_subCollection1 = null;
}
}
public void AssignCollectionObject1(ObservableCollection<Object1> collection)
{
if (_subCollection1 != null)
{
UnassignCollectionObject1();
}
_subCollection1 = collection;
AddItems(_subCollection1);
_subCollection1.CollectionChanged += OnSubCollectionChanged;
}
public void UnassignCollectionObject2()
{
if (_subCollection2 != null)
{
RemoveItems(_subCollection2);
_subCollection2.CollectionChanged -= OnSubCollectionChanged;
_subCollection2 = null;
}
}
public void AssignCollectionObject2(ObservableCollection<Object2> collection)
{
if (_subCollection2 != null)
{
UnassignCollectionObject2();
}
_subCollection2 = collection;
AddItems(_subCollection2);
_subCollection2.CollectionChanged += OnSubCollectionChanged;
}
public void UnassignCollectionObject3()
{
if (_subCollection3 != null)
{
RemoveItems(_subCollection3);
_subCollection3.CollectionChanged -= OnSubCollectionChanged;
_subCollection3 = null;
}
}
public void AssignCollectionObject3(ObservableCollection<Object3> collection)
{
if (_subCollection3 != null)
{
UnassignCollectionObject3();
}
_subCollection3 = collection;
AddItems(_subCollection3);
_subCollection3.CollectionChanged += OnSubCollectionChanged;
}
private void AddItems(IEnumerable<ViewModelBase> items)
{
foreach (ViewModelBase me in items)
Add(me);
}
private void RemoveItems(IEnumerable<ViewModelBase> items)
{
foreach (ViewModelBase me in items)
Remove(me);
}
private void OnSubCollectionChanged(object source, NotifyCollectionChangedEventArgs args)
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
AddItems(args.NewItems.Cast<ViewModelBase>());
break;
case NotifyCollectionChangedAction.Remove:
RemoveItems(args.OldItems.Cast<ViewModelBase>());
break;
case NotifyCollectionChangedAction.Replace:
RemoveItems(args.OldItems.Cast<ViewModelBase>());
AddItems(args.NewItems.Cast<ViewModelBase>());
break;
case NotifyCollectionChangedAction.Move:
throw new NotImplementedException();
case NotifyCollectionChangedAction.Reset:
if (source is ObservableCollection<Object1>)
{
RemoveItems(this.Where(c => c is Object3).ToList());
}
if (source is ObservableCollection<Object2>)
{
RemoveItems(this.Where(c => c is Object3).ToList());
}
if (source is ObservableCollection<Object3>)
{
RemoveItems(this.Where(c => c is Object3).ToList());
}
break;
}
}
}
then I can use it in my viewmodel using DynamicData for the binding :
public class MainWindowViewModel : ViewModelBase
{
private readonly ReadOnlyObservableCollection<ViewModelBase> _testBind;
public ReadOnlyObservableCollection<ViewModelBase> TestBind => _testBind;
public ObservableCollectionAggregate AggregatedCollection { get; set; }
public IObservable<IChangeSet<ViewModelBase>> AggregatedChangeSetFull { get; set; }
public ObservableCollection<Object1> ListTypesObject1 { get; set; }
public ObservableCollection<Object2> ListTypesObject2 { get; set; }
public ObservableCollection<Object3> ListTypesObject3 { get; set; }
private readonly ReadOnlyObservableCollection<ViewModelBase> _testBindTypes;
public ReadOnlyObservableCollection<ViewModelBase> TestBindTypes => _testBindTypes;
public MainWindowViewModel()
{
ListTypesObject1 = new ObservableCollection<Object1>()
{
new Object1(),
};
ListTypesObject2 = new ObservableCollection<Object2>()
{
new Object2(),
};
AggregatedCollection = new ObservableCollectionAggregate();
AggregatedCollection.AssignCollectionObject1(ListTypesObject1);
AggregatedCollection.AssignCollectionObject2(ListTypesObject2);
AggregatedChangeSetFull = AggregatedCollection.ToObservableChangeSet();
// Bind => output to Binded Property for xaml
// Subscribe => to be notified when changes
var t = AggregatedChangeSetFull
.DisposeMany()
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(out _testBindTypes)
.Subscribe();
}
public void AddObject1()
{
if (ListTypesObject1 == null)
return;
var obj1 = new Object1("Added Object 1");
ListTypesObject1.Add(obj1);
}
public void AddObject2()
{
if (ListTypesObject2 == null)
return;
var obj2 = new Object2("Added Object 2");
ListTypesObject2.Add(obj2);
}
public void AddObject3()
{
if (ListTypesObject3 == null)
return;
var obj3 = new Object3("Added Object 3");
ListTypesObject3.Add(obj3);
}
public void DeleteObject1()
{
if(ListTypesObject1 != null && ListTypesObject1.Count > 0)
ListTypesObject1.RemoveAt(0);
}
public void DeleteObject2()
{
if (ListTypesObject2 != null && ListTypesObject2.Count > 0)
ListTypesObject2.RemoveAt(0);
}
public void DeleteObject3()
{
if (ListTypesObject3 != null && ListTypesObject3.Count > 0)
ListTypesObject3.RemoveAt(0);
}
public void DeleteObject3List()
{
if (ListTypesObject3 == null)
return;
ListTypesObject3.Clear();
ListTypesObject3 = null;
AggregatedCollection.UnassignCollectionObject3();
}
public void CreateObject3List()
{
if (ListTypesObject3 != null)
return;
ListTypesObject3 = new ObservableCollection<Object3>()
{
new Object3("Added object 3 from new list 3"),
};
AggregatedCollection.AssignCollectionObject3(ListTypesObject3);
}
}
Full working example in this branch of the repository :
https://github.com/Whiletru3/pocbindingdmo/tree/ObservableCollectionAggregate
I have created a signalR hub which is solving purpose to show timer at UI of grouped person. If one person starts a play with another one, timer runs very nice.
But the problem is when another group start a new play and previous one is still in progress, I mean Timer is already running, then it overlaps the timer and hold one group. Timer runs once at a time. But I want it to have threading and run for every group.
here is my code:
ConnectionMapping.cs
public class ConnectionMapping<T>
{
private readonly Dictionary<T, HashSet<string>> _connections = new Dictionary<T, HashSet<string>>();
public int Count { get { return _connections.Count; } }
public void Add(T key, string connectionId)
{
lock (_connections)
{
HashSet<string> connections;
if (!_connections.TryGetValue(key, out connections))
{
connections = new HashSet<string>();
_connections.Add(key, connections);
}
lock (connections)
{
connections.Add(connectionId);
}
}
}
public IEnumerable<string> GetConnections(T key)
{
HashSet<string> connections;
if (_connections.TryGetValue(key, out connections))
{
return connections;
}
return Enumerable.Empty<string>();
}
public void Remove(T key, string connectionId)
{
lock (_connections)
{
HashSet<string> connections;
if (!_connections.TryGetValue(key, out connections))
{
return;
}
lock (connections)
{
connections.Remove(connectionId);
if (connections.Count == 0)
{
_connections.Remove(key);
}
}
}
}
}
Below is a Hub class:
public class TimeSyncingHub : Hub
{
private readonly static ConnectionMapping<int> _connections = new ConnectionMapping<int>();
private readonly PlayerPickTicker _playerPickTicker;
private readonly object _PickStateLock = new object();
private IUserBusiness userBusiness;
public TimeSyncingHub() :
this(PlayerPickTicker.Instance)
{
}
public TimeSyncingHub(PlayerPickTicker playerPickTicker)
{
_playerPickTicker = playerPickTicker;
}
public Task LeaveRoom(string roomName)
{
return Groups.Remove(Context.ConnectionId, roomName);
}
public async Task JoinRoom(string roomName)
{
await Groups.Add(Context.ConnectionId, roomName);
Clients.Group(roomName).JoinedRoom("Enter into group - " + roomName);
}
}
Another class where I have written time code is PlayerPickTicker class which is depends in same and implemented in constructor of hub class as shown in class above.
Below is PlayerPickTicker class:
public class PlayerPickTicker : IDisposable
{
private readonly static Lazy<PlayerPickTicker> _instance = new Lazy<PlayerPickTicker>(
() => new PlayerPickTicker(GlobalHost.ConnectionManager.GetHubContext<TimeSyncingHub>()));
private IHubContext _context;
public UserPlayerPickModel UserPlayerPick { get; set; }
public static PlayerPickTicker Instance { get { return _instance.Value; } }
private Timer TickTimer;
private Timer InitialTickTimer;
public int StartSeconds { get; set; }
public int StopSeconds { get; set; }
public bool IsTimerOver { get; set; }
private PlayerPickTicker(IHubContext context)
{
_context = context;
}
public void StartInitialTimer(Model.QueryModel queryModel)
{
try
{
MyDraftBusiness myDraft = new MyDraftBusiness();
myDraft.UdpatePlaysOneMinuteTimerPending(queryModel);
//lock (_InitialTimerStateLock)
//{
//StartSeconds = 60;
//if (InitialTickTimer != null)
//{
// InitialTickTimer.Dispose();
//}
States = new Dictionary<string, bool>() {
{ "IsInitialTimerOver", false},
{ "CallInitialTimerOverMethod", true},
};
PickPlayer = new Dictionary<string, long>() { { "LastPlayerPickId", 0 } };
//lock (States)
//{
StartSeconds = 60;
StopSeconds = 0;
IsInitialTimerOver = false;
CallInitialTimerOverMethod = true;
//}
InitialTickTimer = new Timer();// OnTimerElapsedInitialTimer, queryModel, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
InitialTickTimer.Interval = 1000;
InitialTickTimer.Enabled = true;
InitialTickTimer.Elapsed += (sender, e) => OnTimerElapsedInitialTimer(queryModel, e);
InitialTickTimer.AutoReset = false;
//}
//}
}
catch (Exception ex)
{
Helpers.ExceptionsLog.LogFile(" -( At StartInitialTimer Mehtod )- " + ex.Message);
}
}
private void OnTimerElapsedInitialTimer(object sender, ElapsedEventArgs e)
{
Model.QueryModel queryModel = (Model.QueryModel)sender;
try
{
//lock (_InitialtickStateLock)
//{
var states = (Dictionary<string, bool>)States;
var IsInitialTimerOver = states.FirstOrDefault(x => x.Key == "IsInitialTimerOver").Value;
//Clients.
if (StartSeconds <= StopSeconds && !IsInitialTimerOver)
{
if (InitialTickTimer != null)
{
InitialTickTimer.Dispose();
}
//IsInitialTimerOver = true;
states["IsInitialTimerOver"] = true;
//lock (States)
//{
//************** from client to server
var JsonResult = new JObject();
JsonResult.Add("data", JToken.FromObject(queryModel));
string GroupName = "Group" + queryModel.playId.ToString();
_context.Clients.Group(GroupName).initialTimerCompleted(JsonResult);
//_context.Clients.Group(GroupName, _context.Clients.All).initialTimerCompleted(JsonResult);
//_context.Clients.All.initialTimerCompleted(JsonResult);
MyDraftBusiness myDraft = new MyDraftBusiness();
try
{
myDraft.UdpatePlaysOneMinuteTimerRunning(queryModel);
DraftModel draftModel = myDraft.GetDraftById(queryModel);
if (draftModel != null)
{
var userPlayerPicks = myDraft.GetUserPlayerPickByPlayId(draftModel.PlayId);
if (draftModel.IsDraftFilled)
{
if (draftModel.Play != null && draftModel.Play.IsOneMinuteTimerPending == true)
{
myDraft.UdpatePlaysOneMinuteTimerPending(queryModel);
}
else
{
var activeUserPick = userPlayerPicks.Where(x => !x.Picked).FirstOrDefault();
if (activeUserPick != null)
{
StartTimer(activeUserPick);
}
}
}
}
}
catch (Exception ex)
{
Helpers.ExceptionsLog.LogFile(" -( At OnTimerElapsedInitialTimer Mehtod inner catch )- " + ex.Message);
var userPlayerPicks = myDraft.GetUserPlayerPickByPlayId(queryModel.playId);
var activeUserPick = userPlayerPicks.Where(x => !x.Picked).FirstOrDefault();
if (activeUserPick != null)
{
StartTimer(activeUserPick);
}
}
//}
}
else if (StartSeconds > 0)
{
//IsInitialTimerOver = false;
states["IsInitialTimerOver"] = false;
//lock (States)
//{
StartSeconds -= 1;
var GroupName = "Group" + Convert.ToString(queryModel.playId);
_context.Clients.Group(GroupName).intialTimerElapsed(StartSeconds);
_context.Clients.All.pickRunning(queryModel.playId);
InitialTickTimer.Stop();
InitialTickTimer.Start();
//StartInitialTimer(queryModel);
//}
}
//}
}
catch (Exception ex)
{
Helpers.ExceptionsLog.LogFile(" -( At OnTimerElapsedInitialTimer Mehtod )- " + ex.Message);
}
}
I know it's big code and hard to understand. But I hope for Any Good Developer here, Much appreciation for helper from core of my heart!
Like the title says, I try to notify a property change, the method RaisePropertyChanged is called coorectly, but PropertyChanged is always null.
Here the shortened class:
public class BluetoothManager : INotifyPropertyChanged {
private string selectedBluetoothResult;
private List<string> foundDevices = new List<string>(5);
public List<DeviceInformation> penDevices = new List<DeviceInformation>();
private GattCharacteristic TxCharacteristic;
public string SelectedBluetoothResult {
get {
return selectedBluetoothResult;
}
set {
selectedBluetoothResult = value;
RaisePropertyChanged();
}
}
public List<string> FoundDevices {
get
{
return foundDevices;
}
set
{
foundDevices = value;
RaisePropertyChanged();
}
}
public BluetoothManager() {
StartScanWatcher();
}
public void StartScanWatcher() {
Debug.WriteLine("Starting device watcher...");
String query = "";
//query for Bluetooth LE devices
query += "System.Devices.DevObjectType:=5 AND System.Devices.Aep.ProtocolId:=\"{BB7BB05E-5972-42B5-94FC-76EAA7084D49}\"";
//query for devices with controllers' name
query += " AND (System.ItemNameDisplay:=\"" + DeviceName + "\" )";
var deviceWatcher = DeviceInformation.CreateWatcher(query); //, requestedProperties, DeviceInformationKind.AssociationEndpoint);
deviceWatcher.Added += DeviceWatcher_OnAdded;
deviceWatcher.EnumerationCompleted += DeviceWatcher_OnEnumComplete;
deviceWatcher.Removed += DeviceWatcher_Removed;
deviceWatcher.Stopped += DeviceWatcher_Stopped;
deviceWatcher.Updated += DeviceWatcher_Updated;
deviceWatcher.Start();
Debug.WriteLine(" StartScanWatcher end");
}
private void DeviceWatcher_OnAdded(DeviceWatcher sender, DeviceInformation deviceInfo) {
Debug.WriteLine(" DeviceWatcher_OnAdded Start");
lock (foundDevices) {
if (foundDevices.Contains(deviceInfo.Id)) {
return;
}
foundDevices.Add(deviceInfo.Id);
RaisePropertyChanged("FoundDevices");
}
Debug.WriteLine($"[{deviceInfo.Name}] DeviceWatcher_OnAdded...");
if (SelectedBluetoothResult == null)
{
SelectedBluetoothResult = deviceInfo.Id;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
Debug.WriteLine("<<<<<<<<<<<<< BluetoothManager, PropertyChanging: " + propertyName);
if (PropertyChanged == null) {
Debug.WriteLine("============ BluetoothManager, PropertyChanged == null, " + propertyName);
return;
}
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
Debug.WriteLine(">>>>>>>>>>>>> BluetoothManager, PropertyChanged: " + propertyName);
}
}
}
And here the Binding in the XAML file:
<ListView ItemsSource="{Binding BluetoothManager.FoundDevices}" SelectedItem="{Binding BluetoothManager.SelectedBluetoothResult}">
<ListView.Resources>
<DataTemplate x:Key="BluetoothDeviceTemplate">
<TextBlock Text="{Binding Path=Sap}"/>
</DataTemplate>
</ListView.Resources>
</ListView>
The binding seems to work properly.
Please note, that the class in which the PropertyChanged is always null is not the DataContext auf the XAML file. Does that mean I have to work differently with the PropertyChange notification?
Thanks in advance.
EDIT:
The complete MainWindowViewModel:
public class MainWindowViewModel : INotifyPropertyChanged {
private ObservableCollection<BookGame> _booksToDisplay = new ObservableCollection<BookGame>();
private ObservableCollection<BookGame> _games = new ObservableCollection<BookGame>();
private string _url;
private int[] _newBooksMID;
private int[] _oldBooksMID;
private Dictionary<int, int> _newBooksVersionNumbers;
private Dictionary<int, int> _oldBooksVersionNumbers;
private Dictionary<int, int> _allVersionNumbers;
private List<BookGame> _booksToAdd;
private long _downloadSpeed;
private bool _isDownloading = true;
private bool _toggleLastSearchKeyWasReturn = false;
string _volumeLabel = "";
FileInfo[] _filesTxt = { };
FileInfo[] _filesAll = { };
private string _folderPath = "";
private string _driveName = null;
List<BookGame> _allGames;
List<BookGame> _allBooks;
List<MP3> _allMP3;
long lengthAllBooks = 0;
long lengthAllGames = 0;
int _percentDownloaded = 100;
private long _amountBytesToDownload;
private long _amountBytesDownloaded;
private long _amountMBytesToDownload;
private long _amountMBytesDownloaded;
private int _downloadTime;
//private bool _isDownloadAborted;
ServerCommi serverComm;
public BluetoothManager BluetoothManager { get; set; }
public MainWindowViewModel() {
DownloadTime = 0;
AmountBytesToDownload = 0;
AmountBytesDownloaded = 0;
DriveInfo drive = null;
foreach (DriveInfo driveInfo in DriveInfo.GetDrives()) {
if (driveInfo.IsReady && driveInfo.VolumeLabel == _volumeLabel) {
drive = driveInfo;
_driveName = drive.Name;
_folderPath = _driveName + _folderPath;
}
}
DirectoryInfo di = new DirectoryInfo(_folderPath);
if (di.Exists)
{
_filesTxt = di.GetFiles("*.txt");
FilesAll = di.GetFiles("*.*");
foreach (FileInfo file in _filesTxt)
{
try
{
Convert.ToInt32(file.Name.Split('_')[0]);
AddBookGameToList(file);
}
catch (Exception e)
{
}
}
}
SearchResults = new ObservableCollection<ResultItem>();
MenuCommand = new RelayCommand(o => {
Debug.WriteLine("Menu Command " + o);
SwitchBooks(o);
});
SearchReturnKeyCommand = new RelayCommand(o => {
Debug.WriteLine("00000000000000000000000000000000 SearchReturnKeyCommand " + o);
SearchActivated();
});
BrowserCommand = new RelayCommand(o => {
Debug.WriteLine("Browser Command main" + o);
CallBrowser("");
});
DeleteCommand = new RelayCommand(o => {
Debug.WriteLine("Delete Command main" + o);
});
ToggleDownloadsCommand = new RelayCommand(o => {
Debug.WriteLine(" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ");
Debug.WriteLine(" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ");
Debug.WriteLine("ToggleDownloadsCommand Command main" + o);
ToggleDownloads();
});
_viewModelMusic = new ViewModelMusic(_driveName);
AllGames = Games.ToList<BookGame>();
AllBooks = BooksToDisplay.ToList<BookGame>();
AllMP3 = _viewModelMusic.Mp3s.ToList<MP3>();
long lengthAllMP3 = 0;
foreach (MP3 mp3 in AllMP3) {
lengthAllMP3 += mp3.LengthValue;
}
_viewModelBooks = new ViewModelBooks(BooksToDisplay);
_viewModelGames = new ViewModelGames(Games);
_viewModelFiles = new ViewModelFiles(FilesAll);
_viewModelLumi = new ViewModelLumi(drive, lengthAllBooks, lengthAllGames, lengthAllMP3);
_viewModelOverview = new ViewModelOverview(AllBooks, AllGames, AllMP3);
_screens[0] = _viewModelOverview;
_screens[1] = _viewModelBooks;
_screens[2] = _viewModelGames;
_screens[3] = _viewModelMusic;
_screens[4] = _viewModelFiles;
_screens[5] = _viewModelVideos;
_screens[6] = _viewModelAdults;
_screens[7] = _viewModelLumi;
SearchText = "";
SelectedItem = _viewModelBooks;
Debug.WriteLine("CALLING ServerCommi! Ring, ring!");
serverComm = new ServerCommi(this);
//serverComm.DownloadBooksAsync();
BluetoothManager = new BluetoothManager();
}
private void ToggleDownloads() {
IsDownloading = !IsDownloading;
serverComm.ToggleDownloads(IsDownloading);
_viewModelBooks.ToggleDownloads(IsDownloading);
}
internal void DownloadStateChange(int mid, int newState) {
_viewModelBooks.DownloadStateChange(mid, newState);
}
// params bool[] isDownload : varargs
// returns the mid
public int AddBookGameToList(FileInfo file, bool isDownload = false) {
BookGame bg = new BookGame(file);
if (isDownload) {
bg.DownloadState = 2;
if (bg.Mid == serverComm.DownloadingMID) {
bg.DownloadState = 1;
}
}
if (bg.Group.StartsWith("B")) {
bg.Group = "Bücher";
}
switch (bg.Group) {
case "Bücher":
if (isDownload) {
BooksToDisplay.Insert(0, bg);
} else {
BooksToDisplay.Add(bg);
}
lengthAllBooks += bg.LengthValue;
break;
case "Spiele":
Games.Add(bg);
lengthAllGames += bg.LengthValue;
break;
default:
Debug.WriteLine("Default: " + bg.Title);
break;
}
return bg.Mid;
}
private void CallBrowser(string url) {
Debug.WriteLine("Url: " + Url);
try {
System.Diagnostics.Process.Start(Url);
} catch (System.ComponentModel.Win32Exception noBrowser) {
if (noBrowser.ErrorCode == -2147467259)
MessageBox.Show(noBrowser.Message);
} catch (System.Exception other) {
MessageBox.Show(other.Message);
}
}
string _searchText;
public string SearchText {
get {
return _searchText;
}
set {
Debug.WriteLine("SearchText Value= " + value);
if (!_toggleLastSearchKeyWasReturn) {
_searchText = value;
SearchResults.Clear();
List<ResultItem> _allBooksRI = new List<ResultItem>();
List<ResultItem> _allBooksHelperList = _allBooks.ToList<ResultItem>();
List<ResultItem> _allGamesHelperList = _allGames.ToList<ResultItem>();
List<ResultItem> _allMP3HelperList = _allMP3.ToList<ResultItem>();
if (SelectedItem != null && SelectedItem.Equals(_viewModelGames)) {
AddAllResultItemsIf(SearchResults, _allGamesHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allBooksHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allMP3HelperList, _searchText);
Debug.WriteLine("===================================== Games - " + SearchResults);
Debug.WriteLine("SelectedItem - " + SelectedItem);
} else if (SelectedItem != null && SelectedItem.Equals(_viewModelMusic)) {
AddAllResultItemsIf(SearchResults, _allMP3HelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allGamesHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allBooksHelperList, _searchText);
Debug.WriteLine("====================================== Music " + SearchResults);
Debug.WriteLine("SelectedItem - " + SelectedItem);
} else {
AddAllResultItemsIf(SearchResults, _allBooksHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allGamesHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allMP3HelperList, _searchText);
Debug.WriteLine("====================================== Books " + SearchResults);
}
if (SearchResults.Count == 0) {
SearchResults.Add(new ErrorResultItem("Error", "Nichts passendes gefunden."));
}
} else {
_toggleLastSearchKeyWasReturn = false;
}
}
}
private ObservableCollection<ResultItem> AddAllResultItemsIf(ObservableCollection<ResultItem> searchResults, List<ResultItem> toAdd, string searchText) {
foreach (ResultItem item in toAdd) {
if (item.Title.ToLower().Contains(_searchText.ToLower())) {
searchResults.Add(item);
}
}
return searchResults;
}
public ObservableCollection<ResultItem> SearchResults {
get; set;
}
ResultItem _selectedResult;
public ResultItem SelectedResult {
get {
return _selectedResult;
}
set {
_selectedResult = value;
SearchItemSelected(value);
}
}
private void SearchItemSelected(ResultItem value) {
switch (value.Group) {
case "Bücher":
SelectedItem = _viewModelBooks;
break;
case "Spiele":
SelectedItem = _viewModelGames;
break;
case "Musik":
SelectedItem = _viewModelMusic;
break;
default:
Debug.WriteLine("Search Item Selected, jumped to default: " + value);
break;
}
Unmark(Marked);
Mark(value);
}
ResultItem _marked;
internal void Mark(ResultItem value) {
Marked = value;
value.Marked = true;
}
internal void Unmark(ResultItem value) {
Marked = null;
if (value != null) {
value.Marked = false;
}
}
public ResultItem Marked {
get => _marked;
set => _marked = value;
}
private bool _isSearchResult;
public bool IsSearchResult {
get {
return _isSearchResult;
}
set {
_isSearchResult = value;
Debug.WriteLine("IsSearchResult= " + value);
RaisePropertyChanged();
}
}
private void SearchActivated() {
_toggleLastSearchKeyWasReturn = true;
SelectedItem = _viewModelOverview;
IsSearchResult = true;
}
private object _selectedItem;
public object SelectedItem {
get {
return _selectedItem;
}
set {
_selectedItem = value;
Debug.WriteLine("SELECTED_ITEM SETTER: " + value);
Unmark(Marked);
IsSearchResult = false;
if (SearchText != null) {
SearchText = SearchText;
}
RaisePropertyChanged();
}
}
ViewModelOverview _viewModelOverview;
ViewModelBooks _viewModelBooks;
ViewModelGames _viewModelGames;
ViewModelMusic _viewModelMusic;
ViewModelFiles _viewModelFiles;
ViewModelVideos _viewModelVideos = new ViewModelVideos();
ViewModelAdults _viewModelAdults = new ViewModelAdults();
ViewModelLumi _viewModelLumi;
object[] _screens = new object[8];
public object[] Screens {
get {
return _screens;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string propertyName = null) {
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public ICommand MenuCommand {
get; set;
}
public ICommand SearchReturnKeyCommand {
get; set;
}
public ICommand BrowserCommand {
get; set;
}
public ICommand ToggleDownloadsCommand {
get; set;
}
public RelayCommand DeleteCommand {
get;
private set;
}
public List<BookGame> AllGames {
get => _allGames;
set => _allGames = value;
}
public List<BookGame> AllBooks {
get => _allBooks;
set => _allBooks = value;
}
public List<MP3> AllMP3 {
get => _allMP3;
set => _allMP3 = value;
}
public ViewModelBooks ViewModelBooks {
get => _viewModelBooks;
set => _viewModelBooks = value;
}
public ObservableCollection<BookGame> BooksToDisplay {
get => _booksToDisplay;
set => _booksToDisplay = value;
}
public ObservableCollection<BookGame> Games {
get => _games;
set => _games = value;
}
public string Url {
get {
return _url;
}
set {
_url = value;
RaisePropertyChanged();
}
}
public int[] NewBooksMID {
get => _newBooksMID;
set => _newBooksMID = value;
}
public int[] OldBooksMID {
get => _oldBooksMID;
set => _oldBooksMID = value;
}
public Dictionary<int, int> NewBooksVersionNumbers {
get => _newBooksVersionNumbers;
set => _newBooksVersionNumbers = value;
}
public Dictionary<int, int> OldBooksVersionNumbers {
get => _oldBooksVersionNumbers;
set => _oldBooksVersionNumbers = value;
}
public Dictionary<int, int> AllVersionNumbers {
get => _allVersionNumbers;
set => _allVersionNumbers = value;
}
public int[] OldBooksMID1 {
get => _oldBooksMID;
set => _oldBooksMID = value;
}
public List<BookGame> BooksToAdd {
get => _booksToAdd;
set => _booksToAdd = value;
}
public FileInfo[] FilesAll {
get => _filesAll;
set => _filesAll = value;
}
public string FolderPath {
get => _folderPath;
set => _folderPath = value;
}
public int PercentDownloaded {
get {
return _percentDownloaded;
}
set {
_percentDownloaded = value;
RaisePropertyChanged();
}
}
public long DownloadSpeed {
get {
return _downloadSpeed;
}
set {
_downloadSpeed = value;
RaisePropertyChanged();
}
}
public long AmountBytesToDownload {
get {
return _amountBytesToDownload;
}
set {
_amountBytesToDownload = value;
Debug.WriteLine("Property Changed: " + "AmountBytesToDownload");
AmountMBytesToDownload = value / 1024 / 1024;
}
}
public long AmountBytesDownloaded {
get {
return _amountBytesDownloaded;
}
set {
_amountBytesDownloaded = value;
AmountMBytesDownloaded = value / 1024 / 1024;
}
}
public int DownloadTime {
get {
return _downloadTime;
}
set {
_downloadTime = value;
RaisePropertyChanged();
}
}
/*
public bool IsDownloadAborted {
get {
return _isDownloadAborted;
}
set {
_isDownloadAborted = value;
RaisePropertyChanged();
}
}
*/
public long AmountMBytesDownloaded {
get {
return _amountMBytesDownloaded;
}
set {
_amountMBytesDownloaded = value;
RaisePropertyChanged();
}
}
public long AmountMBytesToDownload {
get {
return _amountMBytesToDownload;
}
set {
_amountMBytesToDownload = value;
RaisePropertyChanged();
}
}
public bool IsDownloading {
get {
return _isDownloading;
}
set {
_isDownloading = value;
RaisePropertyChanged();
}
}
internal void SwitchBooks(object o) {
Debug.WriteLine("SwitchBooksEx " + o);
if (o.ToString().Equals("Tessloff.ViewModelBooks")) {
((ViewModelBooks)_screens[0]).SwitchView();
Debug.WriteLine("SwitchBooksIn " + o);
}
}
}
public class CommandViewModel {
private MainWindowViewModel _viewmodel;
public CommandViewModel(MainWindowViewModel viewmodel) {
_viewmodel = viewmodel;
Debug.WriteLine("LALALALALA");
MenuCommand = new RelayCommand(o => {
Debug.WriteLine("CommandViewModel " + o);
_viewmodel.SwitchBooks(o);
});
DeleteCommand = new RelayCommand(o => {
Debug.WriteLine("Delte Command CVM" + o);
});
}
public ICommand MenuCommand {
get; set;
}
public ICommand DeleteCommand {
get; set;
}
public string Title {
get;
private set;
}
}
public class RelayCommand : ICommand {
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null) {
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute) {
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter) {
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged {
add {
CommandManager.RequerySuggested += value;
}
remove {
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter) {
_execute(parameter);
}
#endregion // ICommand Members
}
public class ViewModelAdults {
public ViewModelAdults() {
Title = "Erwachsene";
ImgUrl = "/Resources/Erwachsene.png";
}
public string Title {
get; set;
}
public string ImgUrl {
get;
private set;
}
}
Edit tl;dr:
Why do all "direct" properties of MainWindowViewModel update great (like MainWindowViewModel.IsSearchResult), but the two "indirect" properties don't (MainWindowViewModel.BluetoothManager.SelectedBluetoothResult).
List.add() doesnt trigger PropertyChange. You need to use ObservableCollection or raise PropertyChange yourself after adding item.
I'm pretty new to C#, I'm trying to make an app with Xamarin forms. I want a picker, what can choose from ($,£,etc) values. Keep in mind that I'm using SQLite.net. Soo, for learning how to make an app I'm using an example from github. There is a long code for bindablepicker:
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using Xamarin.Forms;
namespace TodoScheduler.Controls
{
public class BindablePicker : Picker
{
bool _disableNestedCalls;
public static readonly BindableProperty PickerTitleProperty =
BindableProperty.Create("PickerTitle", typeof(string), typeof(BindablePicker),
null);
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(BindablePicker),
null, propertyChanged: OnItemsSourceChanged);
public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create("SelectedItem", typeof(Object), typeof(BindablePicker),
null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);
public static readonly BindableProperty SelectedValueProperty =
BindableProperty.Create("SelectedValue", typeof(Object), typeof(BindablePicker),
null, BindingMode.TwoWay, propertyChanged: OnSelectedValueChanged);
public String DisplayMemberPath { get; set; }
public string PickerTitle
{
get { return (string)GetValue(PickerTitleProperty); }
set { SetValue(PickerTitleProperty, value); }
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set
{
if (this.SelectedItem != value)
{
SetValue(SelectedItemProperty, value);
InternalSelectedItemChanged();
}
}
}
public object SelectedValue
{
get { return GetValue(SelectedValueProperty); }
set
{
SetValue(SelectedValueProperty, value);
InternalSelectedValueChanged();
}
}
public string SelectedValuePath { get; set; }
public BindablePicker()
{
this.SelectedIndexChanged += OnSelectedIndexChanged;
}
public event EventHandler<SelectedItemChangedEventArgs> ItemSelected;
void InstanceOnItemsSourceChanged(Object oldValue, Object newValue)
{
_disableNestedCalls = true;
this.Items.Clear();
var oldCollectionINotifyCollectionChanged = oldValue as INotifyCollectionChanged;
if (oldCollectionINotifyCollectionChanged != null)
{
oldCollectionINotifyCollectionChanged.CollectionChanged -= ItemsSource_CollectionChanged;
}
var newCollectionINotifyCollectionChanged = newValue as INotifyCollectionChanged;
if (newCollectionINotifyCollectionChanged != null)
{
newCollectionINotifyCollectionChanged.CollectionChanged += ItemsSource_CollectionChanged;
}
if (!Equals(newValue, null))
{
var hasDisplayMemberPath = !String.IsNullOrWhiteSpace(this.DisplayMemberPath);
foreach (var item in (IEnumerable)newValue)
{
if (hasDisplayMemberPath)
{
var type = item.GetType();
var prop = type.GetRuntimeProperty(this.DisplayMemberPath);
this.Items.Add(prop.GetValue(item).ToString());
}
else
{
this.Items.Add(item.ToString());
}
}
this.SelectedIndex = -1; // select first item by default
this._disableNestedCalls = false;
if (this.SelectedItem != null)
{
this.InternalSelectedItemChanged();
}
else if (hasDisplayMemberPath && this.SelectedValue != null)
{
this.InternalSelectedValueChanged();
}
}
else
{
_disableNestedCalls = true;
this.SelectedIndex = -1;
this.SelectedItem = null;
this.SelectedValue = null;
_disableNestedCalls = false;
}
}
void InternalSelectedItemChanged()
{
if (_disableNestedCalls)
{
return;
}
var selectedIndex = -1;
Object selectedValue = null;
if (this.ItemsSource != null)
{
var index = 0;
var hasSelectedValuePath = !String.IsNullOrWhiteSpace(this.SelectedValuePath);
foreach (var item in ItemsSource)
{
if (item != null && item.Equals(this.SelectedItem))
{
selectedIndex = index;
if (hasSelectedValuePath)
{
var type = item.GetType();
var prop = type.GetRuntimeProperty(this.SelectedValuePath);
selectedValue = prop.GetValue(item);
}
break;
}
index++;
}
}
_disableNestedCalls = true;
this.SelectedValue = selectedValue;
this.SelectedIndex = selectedIndex;
_disableNestedCalls = false;
}
void InternalSelectedValueChanged()
{
if (_disableNestedCalls)
{
return;
}
if (String.IsNullOrWhiteSpace(this.SelectedValuePath))
{
return;
}
var selectedIndex = -1;
Object selectedItem = null;
var hasSelectedValuePath = !String.IsNullOrWhiteSpace(this.SelectedValuePath);
if (this.ItemsSource != null && hasSelectedValuePath)
{
var index = 0;
foreach (var item in ItemsSource)
{
if (item != null)
{
var type = item.GetType();
var prop = type.GetRuntimeProperty(this.SelectedValuePath);
if (Object.Equals(prop.GetValue(item), this.SelectedValue))
{
selectedIndex = index;
selectedItem = item;
break;
}
}
index++;
}
}
_disableNestedCalls = true;
this.SelectedItem = selectedItem;
this.SelectedIndex = selectedIndex;
_disableNestedCalls = false;
}
void ItemsSource_CollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
{
var hasDisplayMemberPath = !String.IsNullOrWhiteSpace(this.DisplayMemberPath);
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
if (hasDisplayMemberPath)
{
var type = item.GetType();
var prop = type.GetRuntimeProperty(this.DisplayMemberPath);
this.Items.Add(prop.GetValue(item).ToString());
}
else
{
this.Items.Add(item.ToString());
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.NewItems)
{
if (hasDisplayMemberPath)
{
var type = item.GetType();
var prop = type.GetRuntimeProperty(this.DisplayMemberPath);
this.Items.Remove(prop.GetValue(item).ToString());
}
else
{
this.Items.Remove(item.ToString());
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Replace)
{
foreach (var item in e.NewItems)
{
if (hasDisplayMemberPath)
{
var type = item.GetType();
var prop = type.GetRuntimeProperty(this.DisplayMemberPath);
this.Items.Remove(prop.GetValue(item).ToString());
}
else
{
var index = this.Items.IndexOf(item.ToString());
if (index > -1)
{
this.Items[index] = item.ToString();
}
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Reset)
{
this.Items.Clear();
if (e.NewItems != null)
{
foreach (var item in e.NewItems)
{
if (hasDisplayMemberPath)
{
var type = item.GetType();
var prop = type.GetRuntimeProperty(this.DisplayMemberPath);
this.Items.Remove(prop.GetValue(item).ToString());
}
else
{
var index = this.Items.IndexOf(item.ToString());
if (index > -1)
{
this.Items[index] = item.ToString();
}
}
}
}
else
{
_disableNestedCalls = true;
this.SelectedItem = null;
this.SelectedIndex = -1;
this.SelectedValue = null;
_disableNestedCalls = false;
}
}
}
static void OnItemsSourceChanged(BindableObject bindable, Object oldValue, Object newValue)
{
if (Equals(newValue, null) && Equals(oldValue, null))
{
return;
}
var picker = (BindablePicker)bindable;
picker.InstanceOnItemsSourceChanged(oldValue, newValue);
}
void OnSelectedIndexChanged(Object sender, EventArgs e)
{
if (_disableNestedCalls)
{
return;
}
if (this.SelectedIndex < 0 || this.ItemsSource == null || !this.ItemsSource.GetEnumerator().MoveNext())
{
_disableNestedCalls = true;
if (this.SelectedIndex != -1)
{
//this.SelectedIndex = -1;
this.SelectedIndex = 0;
}
this.SelectedItem = null;
this.SelectedValue = null;
_disableNestedCalls = false;
return;
}
_disableNestedCalls = true;
var index = 0;
var hasSelectedValuePath = !String.IsNullOrWhiteSpace(this.SelectedValuePath);
foreach (var item in ItemsSource)
{
if (index == this.SelectedIndex)
{
this.SelectedItem = item;
if (hasSelectedValuePath)
{
var type = item.GetType();
var prop = type.GetRuntimeProperty(this.SelectedValuePath);
this.SelectedValue = prop.GetValue(item);
}
break;
}
index++;
}
_disableNestedCalls = false;
}
static void OnSelectedItemChanged(BindableObject bindable, Object oldValue, Object newValue)
{
var boundPicker = (BindablePicker)bindable;
boundPicker.ItemSelected?.Invoke(boundPicker, new SelectedItemChangedEventArgs(newValue));
boundPicker.InternalSelectedItemChanged();
}
static void OnSelectedValueChanged(BindableObject bindable, Object oldValue, Object newValue)
{
var boundPicker = (BindablePicker)bindable;
boundPicker.InternalSelectedValueChanged();
}
}
}
The form code:
<controls:BindablePicker Margin="20,5"
ItemsSource="{Binding PriorityList}"
SelectedItem="{Binding Priority, Mode=TwoWay}"
DisplayMemberPath="Title"
Title="Choose"
VerticalOptions="EndAndExpand"/>
Model:
TodoPriority _priority = TodoPriority.Low;
[NotNull] public TodoPriority Priority {
get { return _priority; }
set { SetProperty(ref _priority, value); }
}
ViewModel:
TodoPriority _priority = TodoPriority.Low;
public TodoPriority Priority
{
get { return _priority; }
set { SetProperty(ref _priority, value); }
}
IEnumerable<TodoPriority> _priorityList = Enum.GetValues(typeof(TodoPriority)).Cast<TodoPriority>();
public IEnumerable<TodoPriority> PriorityList
{
get { return _priorityList; }
set { SetProperty(ref _priorityList, value); }
}
TodoPriority:
namespace TodoScheduler.Enums
{
public enum TodoPriority
{
Low = 0,
Normal,
High
}
}
At the moment I can choose from picker (low,normal,high), but how can I change this? I know I cant change those values from Todopriority to currency token, because its enum. I tried to make them all strings, but then I caught on a problem that how I can make these values. I know its a bit dumb question, but I've search alot and cant figute it out.
You could try to create a class to represent each picker item
class PriorityPickerValue {
public string Title { get; set; }
public TodoPriority Priority { get; set; }
}
That way you can specify how your values look in the picker and still have access to the TodoPriority property
I created a reference to load big data into a datagrid with a dapper extension. I have a Behavior that detects when the scroll is then down load the following data using this RelayCommand:
XAML in Datagrid Properties :
Behavior:ScrollViewerMonitor.AtEndCommand="{Binding LoadCommand}"
My Behavior (Detect when scroll is down) :
public class ScrollViewerMonitor
{
public static DependencyProperty AtEndCommandProperty
= DependencyProperty.RegisterAttached(
"AtEndCommand", typeof(ICommand),
typeof(ScrollViewerMonitor),
new PropertyMetadata(OnAtEndCommandChanged));
public static ICommand GetAtEndCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(AtEndCommandProperty);
}
public static void SetAtEndCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(AtEndCommandProperty, value);
}
public static void OnAtEndCommandChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
if (element != null)
{
element.Loaded -= element_Loaded;
element.Loaded += element_Loaded;
}
}
static void element_Loaded(object sender, RoutedEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
element.Loaded -= element_Loaded;
ScrollViewer scrollViewer = FindChildOfType<ScrollViewer>(element);
if (scrollViewer == null)
{
// throw new InvalidOperationException("ScrollViewer not found.");
return;
}
var dpd = DependencyPropertyDescriptor.FromProperty(ScrollViewer.VerticalOffsetProperty, typeof(ScrollViewer));
dpd.AddValueChanged(scrollViewer, delegate (object o, EventArgs args)
{
bool atBottom = scrollViewer.VerticalOffset
>= scrollViewer.ScrollableHeight;
if (atBottom)
{
var atEnd = GetAtEndCommand(element);
if (atEnd != null)
{
atEnd.Execute(null);
}
}
});
}
static T FindChildOfType<T>(DependencyObject root) where T : class
{
var queue = new Queue<DependencyObject>();
queue.Enqueue(root);
while (queue.Count > 0)
{
DependencyObject current = queue.Dequeue();
for (int i = VisualTreeHelper.GetChildrenCount(current) - 1; 0 <= i; i--)
{
var child = VisualTreeHelper.GetChild(current, i);
var typedChild = child as T;
if (typedChild != null)
{
return typedChild;
}
queue.Enqueue(child);
}
}
return null;
}
}
My ViewModel with LoadCommand :
//Init mmy ObservableCollection for DataGrid
var myObservableCollection = new ObservableCollection<Mouvement_Brouillard>();
//Init my Object
//Parameters(NumberPerPage,Conditions,OrderBy,Connection)
var myReference = new Paged2<Mouvement_Brouillard>(150, "", "Swmo_Id", new ConnectionProvider());
//Load First Datas
myReference.AddDatas(myObservableCollection);
//Call LoadCommand when Scroll is down
LoadCommand = new RelayCommand<object>(myReference.LoadCommand(myObservableCollection));
And my reference Paged2 (AddData in ObservableCollection and execute LoadCommand:
public class Paged2<T>
{
private T Value { get; set; }
public int NumberPage { get; set; }
public int RowsPerPage { get; set; }
public string Conditions { get; set; }
public string OrderBy { get; set; }
public ConnectionProvider Cnn { get; set; }
public static bool Busy;
public Paged2(int _RowsPerPage, string _Conditions, string _OrdeBy, ConnectionProvider _Cnn)
{
this.RowsPerPage = _RowsPerPage;
this.Conditions = _Conditions;
this.OrderBy = _OrdeBy;
this.NumberPage = 1;
this.Cnn = _Cnn;
}
public async void AddDatas(ObservableCollection<T> myList)
{
IEnumerable<T> myNewBlocList;
//DAL
using (var myCnn = this.Cnn.GetOpenConnection())
{
myNewBlocList = await myCnn.GetListPagedAsync<T>(this.NumberPage, this.RowsPerPage, this.Conditions, this.OrderBy);
}
NumberPage++;
foreach (var Item in myNewBlocList)
myList.Add(Item);
}
public Action<object> LoadCommand(Ref<ObservableCollection<T>> myList)
{
return new Action<object>(
obj =>
{
if (Busy)
return;
Busy = true;
System.Threading.ThreadPool.QueueUserWorkItem(
delegate
{
Application.Current.Dispatcher.BeginInvoke(new Action(
delegate
{
AddDatas(myList);
Busy = false;
}));
});
});
}
public class Ref<T>
{
public Ref() { }
public Ref(T value) { Value = value; }
public T Value { get; set; }
public override string ToString()
{
T value = Value;
return value == null ? "" : value.ToString();
}
public static implicit operator T(Ref<T> r) { return r.Value; }
public static implicit operator Ref<T>(T value) { return new Ref<T>(value); }
}
}
Everything works but since I outsource (place in another file ) method LoadCommand the next part of the code no longer works :
public Action<object> LoadCommand(Ref<ObservableCollection<T>> myList)
{
return new Action<object>(
obj =>
{
if (Busy)
return;
Busy = true;
System.Threading.ThreadPool.QueueUserWorkItem(
delegate
{
Application.Current.Dispatcher.BeginInvoke(new Action(
delegate
{
AddDatas(myList);
Busy = false;
}));
});
});
}