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
Related
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?
I am trying to Generically set the Field Values in the ItemsRow class (and others that are similar in format - but properties and fields are different.
I want to do something like what I do with hard coding
public Dictionary<object, Action<T, object>> SetFieldValues = new Dictionary<object, Action<T, object>>
{
{"Description", (m,v) => m.Description = (string)v};
}
public class Mapping<T> where T:Row
{
public Dictionary<object, Action<T, object>> SetFieldValues(string[] headers)
{
Dictionary<object, Action<T, object>> myDict = new Dictionary<object, Action<T, object>>();
// Activator
var objectType = typeof(T); // Type.GetType(T);
var tRow = Activator.CreateInstance(objectType) as Row;
foreach (var item in headers)
{
var myfield = tRow.FindFieldByPropertyName(item);
//myDict[item] = myfield =
//myDict[item] = (m, v) => m.FindFieldByPropertyName(item) = (Type.GetType(myfield.Type.ToString()))v;
}
// I want this to be dynamic header[i],(m,v) => m.(property to set for object) = (cast to type m.property type)v
//{"ItemName", (m,v) => m.ItemName = (string)v},
//{"Description", (m,v) => m.Description = (string)v},
return myDict;
}
// Class names will be different, properties and fields will be different..
public sealed class ItemsRow : Row
{
public String ItemName
{
get { return Fields.ItemName[this]; }
set { Fields.ItemName[this] = value; }
}
public String Description
{
get { return Fields.Description[this]; }
set { Fields.Description[this] = value; }
}
public static readonly RowFields Fields = new RowFields().Init();
public ItemsRow()
: base(Fields)
{
}
public class RowFields : RowFieldsBase
{
public StringField ItemName;
public StringField Description;
}
}
Base Class
=================================================================================
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
namespace Serenity.Data
{
[JsonConverter(typeof(JsonRowConverter))]
public abstract partial class Row : IEntityWithJoins,
INotifyPropertyChanged, IEditableObject
#if !COREFX
, IDataErrorInfo
#endif
{
internal RowFieldsBase fields;
internal bool[] assignedFields;
internal Hashtable dictionaryData;
internal bool ignoreConstraints;
internal object[] indexedData;
internal bool tracking;
internal bool trackWithChecks;
protected Row(RowFieldsBase fields)
{
if (fields == null)
throw new ArgumentNullException("fields");
this.fields = fields.InitInstance(this);
TrackAssignments = true;
}
public void CloneInto(Row clone,
bool cloneHandlers)
{
clone.ignoreConstraints = ignoreConstraints;
foreach (var field in GetFields())
field.Copy(this, clone);
clone.tracking = tracking;
if (tracking)
{
if (assignedFields != null)
{
clone.assignedFields = new bool[assignedFields.Length];
Array.Copy(assignedFields, clone.assignedFields, assignedFields.Length);
}
}
else
clone.assignedFields = null;
clone.trackWithChecks = trackWithChecks;
clone.originalValues = originalValues;
if (dictionaryData != null)
clone.dictionaryData = (Hashtable)this.dictionaryData.Clone();
else
clone.dictionaryData = null;
if (indexedData != null)
{
clone.indexedData = new object[indexedData.Length];
for (var i = 0; i < indexedData.Length; i++)
clone.indexedData[i] = indexedData[i];
}
else
clone.indexedData = null;
if (previousValues != null)
clone.previousValues = previousValues.CloneRow();
else
clone.previousValues = null;
if (cloneHandlers)
{
clone.postHandler = this.postHandler;
clone.propertyChanged = this.propertyChanged;
if (this.validationErrors != null)
clone.validationErrors = new Dictionary<string, string>(this.validationErrors);
else
clone.validationErrors = null;
}
}
public Row CloneRow()
{
var clone = CreateNew();
CloneInto(clone, true);
return clone;
}
public virtual Row CreateNew()
{
if (fields.rowFactory == null)
throw new NotImplementedException();
return fields.rowFactory();
}
internal void FieldAssignedValue(Field field)
{
if (assignedFields == null)
assignedFields = new bool[fields.Count];
assignedFields[field.index] = true;
if (validationErrors != null)
RemoveValidationError(field.PropertyName ?? field.Name);
if (propertyChanged != null)
{
if (field.IndexCompare(previousValues, this) != 0)
{
RaisePropertyChanged(field);
field.Copy(this, previousValues);
}
}
}
public Field FindField(string fieldName)
{
return fields.FindField(fieldName);
}
public Field FindFieldByPropertyName(string propertyName)
{
return fields.FindFieldByPropertyName(propertyName);
}
public RowFieldsBase GetFields()
{
return fields;
}
public int FieldCount
{
get { return fields.Count; }
}
public bool IsAnyFieldAssigned
{
get
{
return tracking && assignedFields != null;
}
}
public bool IgnoreConstraints
{
get { return ignoreConstraints; }
set { ignoreConstraints = value; }
}
public string Table
{
get { return fields.TableName; }
}
public bool TrackAssignments
{
get
{
return tracking;
}
set
{
if (tracking != value)
{
if (value)
{
if (propertyChanged != null)
previousValues = this.CloneRow();
tracking = value;
}
else
{
tracking = false;
trackWithChecks = false;
assignedFields = null;
}
}
}
}
public bool TrackWithChecks
{
get
{
return tracking && trackWithChecks;
}
set
{
if (value != TrackWithChecks)
{
if (value && !tracking)
TrackAssignments = true;
trackWithChecks = value;
}
}
}
private Field FindFieldEnsure(string fieldName)
{
var field = FindField(fieldName);
if (ReferenceEquals(null, field))
throw new ArgumentOutOfRangeException("fieldName", String.Format(
"{0} has no field with name '{1}'.", this.GetType().Name, fieldName));
return field;
}
public object this[string fieldName]
{
get
{
var field = FindFieldByPropertyName(fieldName) ??
FindField(fieldName);
if (ReferenceEquals(null, field))
{
if (dictionaryData != null)
return dictionaryData[fieldName];
return null;
}
return field.AsObject(this);
}
set
{
(FindFieldByPropertyName(fieldName) ??
FindFieldEnsure(fieldName)).AsObject(this, value);
}
}
public void SetDictionaryData(object key, object value)
{
if (value == null)
{
if (dictionaryData == null)
return;
dictionaryData[key] = null;
}
else
{
if (dictionaryData == null)
dictionaryData = new Hashtable();
dictionaryData[key] = value;
}
}
public object GetDictionaryData(object key)
{
if (dictionaryData != null)
return dictionaryData[key];
return null;
}
internal void SetIndexedData(int index, object value)
{
if (value == null)
{
if (indexedData == null)
return;
indexedData[index] = null;
}
else
{
if (indexedData == null)
indexedData = new object[this.FieldCount];
indexedData[index] = value;
}
}
internal object GetIndexedData(int index)
{
if (indexedData != null)
return indexedData[index];
return null;
}
public bool IsAssigned(Field field)
{
if (assignedFields == null)
return false;
return assignedFields[field.index];
}
public void ClearAssignment(Field field)
{
if (assignedFields == null)
return;
assignedFields[field.index] = false;
for (var i = 0; i < assignedFields.Length; i++)
if (assignedFields[i])
return;
assignedFields = null;
}
public bool IsAnyFieldChanged
{
get
{
if (originalValues == null)
return false;
for (var i = 0; i < fields.Count; i++)
if (fields[i].IndexCompare(originalValues, this) != 0)
return true;
return false;
}
}
IDictionary<string, Join> IHaveJoins.Joins
{
get { return fields.Joins; }
}
}
}
Sorry I couldn't get back to you yesterday, but a promise is a promise :). And while writing this code I began to doubt about what your headers actually look like. How are you going to determine which property belongs to which header? Unless you have some type of recognition for that which I might be missing from your code.
But the general idea is this:
Of course this is based on the premise that headers are keyvaluepairs of which the key is the identifier for which property to use.
static void Main(string[] args)
{
var values = new Dictionary<string, string>()
{
["Title"] = "Test",
["Amount"] = "5",
["Description"] = "Some description"
};
var target = new TestClass();
var setters = GetPropertySetters(target);
foreach(KeyValuePair<string, string> value in values)
{
if (setters.ContainsKey(value.Key))
setters[value.Key].Invoke(value.Value);
}
Console.WriteLine(JsonConvert.SerializeObject(target));
Console.ReadLine();
}
public static Dictionary<string, Action<string>> GetPropertySetters<T>(T source)
{
var result = new Dictionary<string, Action<string>>(StringComparer.OrdinalIgnoreCase);
foreach (PropertyInfo pi in typeof(T).GetProperties())
result.Add(pi.Name, (string value) => { pi.SetValue(source, Convert.ChangeType(value, pi.PropertyType)); });
return result;
}
public class TestClass
{
public string Title { get; set; }
public int Amount { get; set; }
public string Description { get; set; }
}
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;
}));
});
});
}
I've a WPF application that loads a menu from an XML file, each node as a tag that identifies the user function. Each user has visibility permission that match against the tag defined in the xml file. I wish some help on simplifing that code since I's quite complex and from my point of view poor performing. Consider that the main menu is composed of main items and inside each there're specific areas function. If a user is enabled to at element at list the main menu node is shown otherwise not.
public virtual System.Threading.Tasks.Task<MenuItemNode> RegisterMenu(IDictionary<string,Type> functions)
{
var assembly = Assembly.GetCallingAssembly(); //I should get the module that invoked the base class
string filename = GetFullFileName(assembly, MenuFilename);
return Task.Factory.StartNew<MenuItemNode>(() =>
{
string xmlFileName = string.Format(filename);
var doc = new XmlDocument();
using (Stream stream = assembly.GetManifestResourceStream(xmlFileName))
{
if (stream != null)
{
using (var reader = new StreamReader(stream))
{
doc.LoadXml(reader.ReadToEnd());
}
}
}
MenuItemNode menu = BuildMenu(doc.SelectSingleNode(#"/Node"), "/", functions);
return menu;
});
}
private string GetFullFileName(Assembly assembly,string filename)
{
var resourceFiles = assembly.GetManifestResourceNames();
return resourceFiles.First(x => x.EndsWith(filename));
}
private MenuItemNode BuildMenu(XmlNode parent, string path, IDictionary<string, Type> functions)
{
Argument.IsNotNull(() => parent);
if (functions == null || (functions.Count == 0)) return null;
MenuItemNode menuItem = null;
string subPath = "Node";
string name = string.Empty;
string tag = string.Empty;
int position = 0;
bool forceVisible = false;
string parameters = string.Empty;
string group = string.Empty;
bool showInDialog = false;
if (parent.Attributes != null)
{
if (parent.Attributes["name"] != null)
name = parent.Attributes["name"].Value;
if (parent.Attributes["tag"] != null)
tag = parent.Attributes["tag"].Value;
if (parent.Attributes["position"] != null)
position = System.Convert.ToInt32(parent.Attributes["position"].Value);
if (parent.Attributes["force_visible"] != null)
forceVisible = Convert.ToBoolean(parent.Attributes["force_visible"].Value);
if (parent.Attributes["parameters"] != null)
parameters = parent.Attributes["parameters"].Value;
if (parent.Attributes["group"] != null)
group = parent.Attributes["group"].Value;
if (parent.Attributes["showindialog"] != null)
showInDialog = Convert.ToBoolean(parent.Attributes["showindialog"].Value);
}
//parent item
if (string.IsNullOrEmpty(tag))
{
menuItem = CreateMenuItem(name, position);
menuItem.ForceVisible = forceVisible;
// menuItem.Group = group;
}
else//child item
{
if (functions.ContainsKey(tag))
{
menuItem = CreateMenuItem(name, tag, position);
menuItem.ForceVisible = forceVisible;
//menuItem.GroupName = group;
menuItem.ShowInDialog = showInDialog;
//menuItem.MenuParameter = GetMenuItemParameters(parameters);
#region Multiple-tag
if ((functions == null) || !functions.Any()) return null;
#endregion
}
else
{
//todo: add-logging
}
}
if (parent.HasChildNodes)
{
foreach (XmlNode child in parent.SelectNodes(subPath))
{
MenuItemNode childMenuItem = BuildMenu(child, subPath, functions);
if (childMenuItem == null) continue;
int childPosition = childMenuItem.SortIndex;
//This to prevent out-of-boundaries exception
if (childPosition > menuItem.Children.Count)
childPosition = menuItem.Children.Count;
menuItem.Children.Insert(childPosition, childMenuItem);
}
}
return menuItem;
}
private MenuItemNode CreateMenuItem(string text, int position)
{
var item = new MenuItemNode();
item.Text = text;
item.SortIndex = position;
return item;
}
private MenuItemNode CreateMenuItem(string text, string tag, int? position)
{
MenuItemNode item = CreateMenuItem(text, (!position.HasValue) ? 0 : position.Value);
item.FunctionTag = tag;
item.SortIndex = (!position.HasValue) ? 0 : position.Value;
return item;
}
And here's the MenuItemNode class
[ContentProperty("Children")]
public class MenuItemNode : INotifyPropertyChanged
{
private string text;
private ICommand command;
private Uri imageSource;
private int sortIndex;
private bool forceVisible;
private bool showInDialog;
private bool isChecked;
public bool IsChecked
{
get
{
return this.isChecked;
}
set
{
if (this.isChecked != value)
{
this.isChecked = value;
this.RaisePropertyChanged(() => this.IsChecked);
}
}
}
public bool IsSeparator { get; set; }
public MenuItemNode()
{
Children = new MenuItemNodeCollection();
SortIndex = 50;
SetCommand();
}
public MenuItemNode(String path)
: base()
{
Path = path;
}
public MenuItemNodeCollection Children { get; private set; }
public virtual ICommand Command
{
get
{
return command;
}
set
{
if (command != value)
{
command = value;
RaisePropertyChanged(() => this.Command);
}
}
}
public Uri ImageSource
{
get
{
return imageSource;
}
set
{
if (imageSource != value)
{
imageSource = value;
RaisePropertyChanged(() => this.ImageSource);
}
}
}
public string Text
{
get
{
return text;
}
set
{
if (text != value)
{
text = value;
RaisePropertyChanged(() => this.Text);
}
}
}
private MenuGroupDescription group;
public MenuGroupDescription Group
{
get { return group; }
set
{
if (group != value)
{
group = value;
RaisePropertyChanged(() => this.Group);
}
}
}
public int SortIndex
{
get
{
return sortIndex;
}
set
{
if (sortIndex != value)
{
sortIndex = value;
RaisePropertyChanged(() => this.SortIndex);
}
}
}
public string Path
{
get;
private set;
}
public bool ForceVisible
{
get
{
return this.forceVisible;
}
set
{
if (forceVisible != value)
{
this.forceVisible = value;
RaisePropertyChanged(() => ForceVisible);
}
}
}
public bool ShowInDialog
{
get
{
return this.showInDialog;
}
set
{
if (showInDialog = value)
{
this.showInDialog = value;
RaisePropertyChanged(() => ShowInDialog);
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyExpression.Name));
}
#endregion
protected virtual void SetCommand()
{
this.Command = FunctionMenuCommands.OpenFunctionCommand;
}
public string FunctionTag { get; set; }
}
In specific what I did is to process each child node then if visible I add it to the collection... do you see any possible better solution?
Thanks
Whoever wrote that code clearly didn't know how to write WPF. In WPF, there is a much simpler option... just use the MenuItem.Visibility property to hide (collapse) MenuItems that users don't have access to. Of course, you'd need some data bind-able security bool properties which you could then data bind to the MenuItem.Visibility property of each MenuItem via a BooleanToVisibilityConverter. Here's a simple example:
<MenuItem Header="Some option" Visibility="{Binding User.Security.HasSomeOptionPermission,
Converter={StaticResource BooleanToVisibilityConverter}}" ... />
If a particular user has the SomeOptionPermission, then the MenuItem will be displayed, otherwise it will be hidden.
At the moment I have this Code (Deepth = 2 Categories)
private void Window_Loaded(object sender, RoutedEventArgs e)
{
foreach (Kategorie kategorie in mainViewModel.Kategorien)
{
if (kategorie.Oberkategorie == null)
{
TreeViewItem newChild = new TreeViewItem();
newChild.Header = kategorie.Bezeichnung;
treeView.Items.Add(newChild);
foreach (Kategorie unterkategorie in mainViewModel.Kategorien)
{
if (unterkategorie.Oberkategorie != null)
{
if (unterkategorie.Oberkategorie.Id == kategorie.Id)
{
TreeViewItem subItem = new TreeViewItem();
subItem.Header = unterkategorie.Bezeichnung;
newChild.Items.Add(subItem);
}
}
}
}
}
}
I would like to make a recursive method, where I could have n Categories in undercategories and so on, I tried things like:
foreach (Kategorie kategorie in mainViewModel.Kategorien)
{
FillKategorienTreeView(kategorie);
}
and then:
private void FillKategorienTreeView(Kategorie kategorie)
{
//if (kategorie.Oberkategorie == null)
//{
// TreeViewItem newChild = new TreeViewItem();
// newChild.Header = kategorie.Bezeichnung;
// treeView.Items.Add(newChild);
//}
//else
//{
// if (kategorie.Oberkategorie.Id == kategorie.Id)
// {
// TreeViewItem subItem = new TreeViewItem();
// subItem.Header = kategorie.Bezeichnung;
// newChild.Items.Add(subItem);
// }
//}
}
and other similiar things and it didn't work, I'm not so friendly with recursion but in this case it's indispensable..
There's a Treeview, which has a TopLevel (Maincategory) and can have n under/subcategories.
Hope u can help me
EDIT: The Category Object:
[DataMember]
public int Id
{
get { return _id; }
set
{
if (_id != value)
{
if (ChangeTracker.ChangeTrackingEnabled && ChangeTracker.State != ObjectState.Added)
{
throw new InvalidOperationException("The property 'Id' is part of the object's key and cannot be changed. Changes to key properties can only be made when the object is not being tracked or is in the Added state.");
}
_id = value;
OnPropertyChanged("Id");
}
}
}
private int _id;
[DataMember]
public string Bezeichnung
{
get { return _bezeichnung; }
set
{
if (_bezeichnung != value)
{
_bezeichnung = value;
OnPropertyChanged("Bezeichnung");
}
}
}
private string _bezeichnung;
#endregion
#region Navigation Properties
[DataMember]
public TrackableCollection<Artikel> Artikel
{
get
{
if (_artikel == null)
{
_artikel = new TrackableCollection<Artikel>();
_artikel.CollectionChanged += FixupArtikel;
}
return _artikel;
}
set
{
if (!ReferenceEquals(_artikel, value))
{
if (ChangeTracker.ChangeTrackingEnabled)
{
throw new InvalidOperationException("Cannot set the FixupChangeTrackingCollection when ChangeTracking is enabled");
}
if (_artikel != null)
{
_artikel.CollectionChanged -= FixupArtikel;
}
_artikel = value;
if (_artikel != null)
{
_artikel.CollectionChanged += FixupArtikel;
}
OnNavigationPropertyChanged("Artikel");
}
}
}
private TrackableCollection<Artikel> _artikel;
[DataMember]
public TrackableCollection<Kategorie> Unterkategorie
{
get
{
if (_unterkategorie == null)
{
_unterkategorie = new TrackableCollection<Kategorie>();
_unterkategorie.CollectionChanged += FixupUnterkategorie;
}
return _unterkategorie;
}
set
{
if (!ReferenceEquals(_unterkategorie, value))
{
if (ChangeTracker.ChangeTrackingEnabled)
{
throw new InvalidOperationException("Cannot set the FixupChangeTrackingCollection when ChangeTracking is enabled");
}
if (_unterkategorie != null)
{
_unterkategorie.CollectionChanged -= FixupUnterkategorie;
}
_unterkategorie = value;
if (_unterkategorie != null)
{
_unterkategorie.CollectionChanged += FixupUnterkategorie;
}
OnNavigationPropertyChanged("Unterkategorie");
}
}
}
private TrackableCollection<Kategorie> _unterkategorie;
[DataMember]
public Kategorie Oberkategorie
{
get { return _oberkategorie; }
set
{
if (!ReferenceEquals(_oberkategorie, value))
{
var previousValue = _oberkategorie;
_oberkategorie = value;
FixupOberkategorie(previousValue);
OnNavigationPropertyChanged("Oberkategorie");
}
}
}
private Kategorie _oberkategorie;
This will only work if each category has a list of children or sub categories in the object. If not then you will have to build the list of children for each item.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
foreach (Kategorie kategorie in mainViewModel.Kategorien)
{
LoadTreeviewItem(kategorie, null);
}
}
private void LoadTreeviewItem(Kategorie kategorie, TreeViewItem parentItem)
{
//Stop condition
if(kategorie == null) return;
TreeViewItem newChild = new TreeViewItem();
newChild.Header = kategorie.Bezeichnung;
treeView.Items.Add(newChild);
if(parentItem != null) // Add to parent if it is not null
{
parentItem.Items.Add(newChild);
}
else //Otherwise this is the top level so add to treeview
{
treeView.Items.Add(newChild);
}
foreach (Kategorie subkategorie in kategorie.Unterkategorie)
{
LoadTreeviewItem(subkategorie, parentItem);
}
}