I am building xamarin forms app, I am using jamesmontemagno settings plugin and I'm adding a property which list of a class. But the thing is I'm not able to add or insert to the list, every time I use method Add or Insert it jump into the get not the set and I can't understand why.
here is my code and thanks for the help in advance:
//adding an item to the list
private void order(Sales_Order_Items sale)
{
orderlist.Add(sale);
Settings.Usercartlist.Add(sale);
}
I can only set it by using this code
Settings.Usercarlist=orderlist;
the property in the settings file
public static List<Sales_Order_Items> Usercartlist
{
set
{
string listValue = JsonConvert.SerializeObject(value);
AppSettings.AddOrUpdateValue(myIntListKey, listValue);
}
get
{
string value = AppSettings.GetValueOrDefault(myIntListKey, string.Empty);
List<Sales_Order_Items> myList;
if (string.IsNullOrEmpty(value))
myList = new List<Sales_Order_Items>();
else
myList = JsonConvert.DeserializeObject<List<Sales_Order_Items>>(value);
return myList;
}
}
When adding an item, the actual object reference does not change. Only the value changes. This is not picked up by the getter or setter.
The only way to update after each item is to add the line you already have: Settings.Usercarlist=orderlist; after each operation.
I am using like the following way you can try that
Ex.
private static UserDetails _currentUser = null;
public static UserDetails CurrentUser
{
get
{
if (_currentUser == null)
{
string data = AppSettings.GetValueOrDefault(nameof(CurrentUser), string.Empty);
if (data != null)
_currentUser = JsonConvert.DeserializeObject<LoginResponse>(data);
}
return _currentUser;
}
set
{
string data = JsonConvert.SerializeObject(value);
AppSettings.AddOrUpdateValue(nameof(CurrentUser), data);
_currentUser = value;
}
}
Related
I'm getting stuck into MVVM in WPF and I have setup an ObservableCollection and an ICollectionView. The ICollectionView is set as the ItemsSource of a DataGrid, and the model is a type of Job.
I've setup getters and setter for both of the collections however when I am setting a Filter on the ICollectionView instead of the Job being filtered by the SearchString they're just replicated over and over again, leading me to believe that they way I have the collections setup is totally wrong.
Here is how the two collections are get/set:
public ObservableCollection<Job> AllJobs
{
get
{
foreach (var job in _allJobsList)
_allJobs.Add(job);
return _allJobs;
}
set
{
if (_allJobs == value) return;
OnPropertyChanged("AllJobs");
}
}
public ICollectionView AllJobsView
{
get
{
_allJobsView = CollectionViewSource.GetDefaultView(AllJobs);
return _allJobsView;
}
set
{
if (_allJobsView == value)
{
return;
}
_allJobsView = value;
OnPropertyChanged("AllJobsView");
}
}
Now I have a stringcalled SearchString that is bound to a TextBox.Text. When the text changes I do the following:
public string SearchString
{
get => _searchString;
set
{
if (_searchString == value) return;
_searchString = value;
FilterJobs();
OnPropertyChanged("SearchString");
}
}
private void FilterJobs()
{
AllJobsView.Filter = x =>
{
var viewJob = x as Job;
return viewJob != null && viewJob.Number.Contains(_searchString);
};
}
Now when the page first loads, there are the correct Jobs loaded into the DataGrid. However, as soon as the user types the Jobs are duplicated if the Job.Number does contain the SearchString. How am I able to setup the collections so that I can appropriately set a filter?
The problem is in the getter of your ObservableCollection. Every time you "get" the collection, you are adding every item to the collection all over again.
Your code:
get
{
foreach (var job in _allJobsList)
_allJobs.Add(job);
return _allJobs;
}
Instead, it should be:
get
{
return _allJobs;
}
The setter of your ObservableCollection is also missing the "setter" (private field = value) code:
set
{
if (value != _allJobs)
{
_allJobs = value;
OnPropertyChanged("AllJobs");
}
}
Your Property AllJobs would then be:
private ObservableCollection<Job> _allJobs;
public ObservableCollection<Job> AllJobs
{
get
{
return _allJobs;
}
set
{
if (value != _allJobs)
{
_allJobs = value;
OnPropertyChanged("AllJobs");
}
}
}
The initialization of your collection should be someplace else (and not in the getter of your property), like in the constructor of the ViewModel or/and in a method that a command calls after the user asks for a refresh of the collection.
For example, if your VieModel is called MyViewModel and your List<Job> is called _allJobsList, you can initialize your collection like so:
public MyViewModel()
{
//fill the _allJobsList first, getting from a database for example: _allJobsList = GetJobs();
//and then create an observable collection from that list
AllJobs = new ObservableCollection<Job>(_allJobsList);
}
I see a lot of similar questions but none with a direct answer. I have a List<ClientEntry>. I want to access properties in ClientEntry. My code looks like this:
class ClientEntry
{
private string _clientName;
private string _clientEmail;
public void ClientEntry(string name, string email)
{
this._clientName = name;
this._clientEmail = email;
}
public string ClientName
{
get
{
return _clientName;
}
set
{
_clientName = value;
}
}
public string ClientEmail
{
get
{
return _clientEmail;
}
set
{
RegexUtilities Validator = new RegexUtilities();
if (Validator.IsValidEmail(value))
{
_clientEmail = value;
}
}
}
}
Later:
private List<ClientEntry> clientList;
I then add a bunch of ClientEntry's to the List.
How can I access the ClientName and ClientEmail properties for items in clientList? Also, how can I check for the existance of a certain ClientName or ClientEmail property within the List? Is this even possible with a list of objects? I know a dict would probably serve better, but I wanted to see if this could be done with a List and a class with properties.
You can use Linq to look for values inside of a list using Any()
Eg.
bool emailExists = clientList.Any(x=>x.ClientEmail == <email>);
To access values, you can use a index accessor if you know it, loop the collection, or use Where() to search it:
var email = clientList[index].ClientEmail
or
foreach (var client in clientList)
{
var email = client.ClientEmail
}
or
var email = clientList.Where(x=>x.ClientName == <clientName>).FirstOrDefault();
you can explore your list as below
foreach (ClientEntry client in clientList)
{
//client.ClientName
//client.ClientEmail
}
to find a particular record you can search it as
clientList.Where(p=> p.ClientEmail == "email#domain.com").FirstOrDefault();
To access a specific of item in the list, you input the index / using foreach
string name = clientList[index].ClientName;
foreach(var client in clientList)
{
name = client.ClientName; // access the item one by one
}
To check the existence of certain value of a property, use linq
bool isExist = clientList.Any(i => i.ClientName == "John");
Use Extension Methods !
Something like this, you can write unit test against the extension class easily and also it's straightforward to read.
public static class ClientEntriesExtension
{
public static bool ExistEmail(this IEnumerable<ClientEntry> entries, string targetEmail)
{
return entries.Any(x=>x.ClientEmail == targetEmail);
}
}
bool exist = clientList.ExistEmail(targetEmail)
EDIT 2
I have got some help over the past few days on a problem that I am trying to work through. After receiving helpful support from several users, I have come across an error that I have been trying to fix over the weekend and still not succeeded.
I created a Dictionary, where I pass a string Country and also a ICollection of Places for that Country.
Dictionary<string, NewCountryClass> NTCD = new Dictionary<string, NewCountryClass>();
public void AddCountryCollection()
{
newCountryClass = new NewCountryClass(newCountry);
Collections.Add(newCountryClass);
NTCD.Add(newCountryClass.Country, newCountryClass);
}
public void AddPlace()
{
string Country = selectedItem.Country;
RenameQuestion(placeName);
NTCD[Country].Place.Add(placeName);
}
Here is my newCountryClass where I stored the Country and Places in that Country.
private ICollection<string> _places;
public ICollection<string> Places
{
get
{
return _places;
}
set
{
if (value == _places)
return;
_places = value;
RaisePropertyChanged(() => Places);
}
}
This is where the places could be added, but I create an instance of my class at the adding Country stage, and therefore can't pass a place at that time. (EDIT - I have moved the initialising of the collection into the constructor instead of in the Places property, as advised).
public NewCountryClass(string country)
{
_places = new ObservableCollection<string>();
if (country != null)
{
_country = country;
}
}
Therefore, I attempted to create a renamePlace() method:
public void RenamePlace(string place)
{
_places.Add(place);
}
However, _places still seems to be null even with this attempt. Any further ideas or anything I am doing wrong?
You need to learn how to debug a program. Basically, you try to instantiate your NewCountryClass here:
public void AddCountryCollection()
{ // <<< Put breakpoint here <<<
newCountryClass = new NewCountryClass(newCountry, placeName);
Collections.Add(newCountryClass);
NTCD.Add(newCountryClass.Country, newCountryClass);
}
If the placeName input parameter is null in the constructor, then it is also null here... you need to add a breakpoint here and find out why the value is null and ensure that it has a value by this stage in your program.
Would you not be better off initialising the _places collection in the constructor instead of the property get accessor?
public NewCountryClass(string country)
{
_places = new ObservableCollection<string>();
if (country != null)
{
_country = country;
}
}
I'm putting together a custom control flow SSIS task for the first time in C#. On my task UI editor I have a property grid and in one of the options I would like to be able to populate a drop down list of any task variables available as well as give the user the option of creating a new one. I've been researching for a few days and I have found some good examples on the forum but I'm a little lost now. My code as follows compiles and the editor displays a drop down list but its blank. After stepping through it, it appears to be down to this line:
taskHostProperty = context.Instance.GetType().GetProperty("TransferTask", typeof(TaskHost));The "TransferTask" being the name of my control flow task. I'm wondering if this is correct?
My full code for this is below.
//Property Grid Property
[Category("General"),
Description("Specifies the local Path for this task"),
Browsable(true),
ReadOnly(false),
DesignOnly(false),
TypeConverter(typeof(VariableConverter)),
DisplayName("Local Path")]
public string LocalPath
{
get
{
return this.stLocalPath;
}
set
{
dtsVariableService = serviceProvider.GetService(typeof(IDtsVariableService)) as IDtsVariableService;
dtsVariableService.PromptAndCreateVariable(parentWindow, dtsContainer,"Local Path","User",typeof(string));
this.stLocalPath = value;
}
}
//Variable Converter
internal class VariableConverter : TypeConverter
{
StandardValuesCollection svc = new StandardValuesCollection(new ArrayList());
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
TaskHost taskHost = null;
PropertyInfo taskHostProperty = null;
List<string> values = new List<string>();
values.Add(NEW_VARIABLE);
if (context == null)
{
return svc;
}
if (context.Instance == null)
{
return svc;
}
taskHostProperty = context.Instance.GetType().GetProperty("TransferTask", typeof(TaskHost));
if (taskHostProperty == null)
{
return svc;
}
taskHost = taskHostProperty.GetValue(context.Instance, null) as TaskHost;
foreach(Variable v in taskHost.Variables)
{
if (!v.SystemVariable && v.DataType == TypeCode.String)
{
values.Add(v.QualifiedName);
}
}
values.Sort();
return new StandardValuesCollection(values);
}
In the end I gave up trying to add the variables to a property grid and just created my own form. I used the following code to populate a combobox and after allowing the user to add a new SSIS variable. I refreshed the datasource. I would still like to know how to do this properly but I just didnt have the time to sit and work it out.
I used the following to first get the SSIS variables I needed, I'm able to add a new SSIS variable and I'm able to select the newly created one. I'm sure there is a better way of doing this but this works for now.
public ObservableCollection<string> FillVariableList()
{
ObservableCollection<string> variables = new ObservableCollection<string>();
variables.Add(string.Empty);
variables.Add(New_Variable);
foreach (Variable v in thetaskHost.Variables)
{
if (!v.SystemVariable && v.DataType == TypeCode.String && !variables.Contains(v.Name))
{
variables.Add(v.Name);
}
}
return variables;
}
And I used the following to allow the user to add a new SSIS variable or select an existing SSIS variable and to refresh the SSIS variable combobox.
private void cmbxVariables_SelectionChangeCommitted(object sender, EventArgs e)
{
if (cmbxVariables.Text == New_Variable)
{
try
{
DtsContainer dtsContainer = null;
dtsVariableServie = serviceProvider.GetService(typeof(IDtsVariableService)) as IDtsVariableService;
Variable var = dtsVariableServie.PromptAndCreateVariable(null, dtsContainer, "VariableName", "User", typeof(string));
if (!var.IsNull())
{
cmbxVariables.DataSource = null;
cmbxVariables.DataSource = FillVariableList();
}
}
catch (Exception exe)
{
MessageBox.Show(exe.ToString());
}
}
else
{
foreach (Variable v in thetaskHost.Variables)
{
if (v.Name == cmbxVariables.Text)
{
//Do something with the variable selected
break;
}
}
}
}
I am abit new in C# and i am trying to insert an object to a CheckedListBox,
so this inserted item will have a title inside the checked list (my object contains a string field inside it which I want to be displayed in the CheckedListBox).
for example this is my class:
public class InfoLayer
{
private string LayerName;
private List<GeoInfo> GeoInfos;
public InfoLayer()
{
LayerName = "New Empty Layer";
GeoInfos = new List<GeoInfo>();
}
public InfoLayer(string LayerName)
{
this.LayerName = LayerName;
GeoInfos = new List<GeoInfo>();
}
public InfoLayer(string LayerName,List<GeoInfo> GeoInfosToClone):this(LayerName)
{
foreach (GeoInfo item in GeoInfosToClone)
{
GeoInfos.Add((GeoInfo)((ICloneable)item).Clone());
}
}
public GeoInfo SearchElement(long id)
{
foreach (GeoInfo info in GeoInfos) // foreach loop running on the list
{
if (info.INFOID == id)
return info; // return the item if we found it
}
return null;
}
public GeoInfo SearchElement(string name)
{
foreach (GeoInfo info in GeoInfos)
{
if (info.INFONAME.CompareTo(name)==0)
return info;
}
return null;
}
public override string ToString()
{
string toReturn = "";
for (int i = 0; i < GeoInfos.Count; i++) // for loop running on the list
{
toReturn += String.Format("{0}\n",GeoInfos[i].ToString()); // piping another geoinfo
}
return toReturn;
}
public string LAYERNAME{get{return LayerName;}}
my class also contains a tostring overrider inside her (not what i want to display)
thanks in advance for your help.
Override ToString() in your class, the class that the object is an instance of.
Edit:
You don't want to display the contents of ToString(). You want to display the LayerName, don't you? Perhaps you should display the values with Databinding instead. Then you can set DisplayMember to your new LAYERNAME property.
I believe this is what you are trying to achieve:
checkedListBox1.Items.Add(yourObject.stringField);
((MyObjectType)checkedListBox1.Items(index)).Name = "whatever"
You will have to know the index of the object you want to change.
You'll just have to override the ToString method in your class so that it returns this Name property value.
public overrides string ToString() {
return Name;
}
It will then display its name when added to your CheckedListbox.