C# UWP - Adding object to ObservableCollection causes XAML generated UnhandledException - c#

I have an ObservableCollection<DiscoveredScooter> DiscoveredScooters = new ObservableCollection<DiscoveredScooter>. The DiscoveredScooter class looks like this:
public class DiscoveredScooter : ViewModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Model { get; set; }
public int RSSI { get; set; }
public DiscoveredScooter(string id, string name, string model, int rssi)
{
Id = id;
Name = name;
Model = model;
RSSI = rssi;
}
public void Update(DeviceInformationUpdate d, string model, int rssi)
{
Id = d.Id;
RSSI = rssi;
Model = model;
RaisePropertyChanged(nameof(Id));
RaisePropertyChanged(nameof(RSSI));
RaisePropertyChanged(nameof(Model));
}
public void UpdateRSSI(int rssi)
{
RSSI = rssi;
RaisePropertyChanged(nameof(RSSI));
}
}
My XAML has a Listview which is bound to this ObservableCollection. I have a BluetoothAdvertismentEvent that gets fired whenever I receive advertisement data. I do some validation and then I do
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
DiscoveredScooters.Add(new DiscoveredScooter(args.BluetoothAddress.ToString(), bleDeviceName, beaconParser.HumanReadableModel, (int)args.RawSignalStrengthInDBm));
});
But this causes a "XAML generated UnhandledException" and it doesn't say any more about the error whatsoever. Here is a screenshot https://gyazo.com/42ee2cae9018c05087335f77db83cb99 Any help is appreciated.

The issue was that I was using .Substring(41) on a property, where the length was way less than that.

Related

How to include a new item in the array of items in an object in MongoDB with C #?

How to include a new item in the array of items in an object in MongoDB with C#?
I tried to use the AddToSet method, but I did not succeed.
I have the following code structure:
1 - Parent object (Revenda):
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Collections.Generic;
namespace api.mstiDFE.Entidade.api.mstiDFE
{
public class Revenda : Notificavel, IEntidade
{
public Revenda(string Id, long Codigo, string CPF, string CNPJ, List<RevendaCliente> Clientes)
{
this.Id = Id;
this.Codigo = Codigo;
this.CPF = CPF;
this.CNPJ = CNPJ;
this.Clientes = Clientes;
}
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; private set; }
[BsonElement("Codigo")]
public long Codigo { get; private set; }
[BsonElement("Nome")]
public string Nome { get; private set; }
[BsonElement("CPF")]
public string CPF { get; private set; }
[BsonElement("CNPJ")]
public string CNPJ { get; private set; }
[BsonElement("Clientes")]
public ICollection<RevendaCliente> Clientes { get; private set; }
}
}
2 - Child object (RevendaCliente):
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Collections.Generic;
namespace api.mstiDFE.Entidade.api.mstiDFE
{
public class RevendaCliente : Notificavel, IEntidade
{
public RevendaCliente(string Codigo, string Nome, string CPF, string CNPJ, ICollection<RevendaClienteToken> Tokens)
{
this.Codigo = Codigo;
this.Nome = Nome;
this.CPF = CPF;
this.CNPJ = CNPJ;
this.Tokens = Tokens;
}
[BsonElement("Codigo")]
public string Codigo { get; private set; }
[BsonElement("Nome")]
public string Nome { get; private set; }
[BsonElement("CPF")]
public string CPF { get; private set; }
[BsonElement("CNPJ")]
public string CNPJ { get; private set; }
[BsonElement("Tokens")]
public ICollection<RevendaClienteToken> Tokens { get; private set; }
}
}
3 - Code used to insert a complete parent object:
public Revenda Add(Revenda revenda)
{
Database.GetCollection<Revenda>("Revendas").InsertOne(revenda);
return revenda;
}
4 - Code used to recover a specific reseller:
public Revenda FindById(string id)
{
return CollRevendas.Find<Revenda>(revenda => revenda.Id == id).FirstOrDefault();
}
Everything works fine.
However, how can I only include a new child object (RevendaCliente) in a parent object (Revenda) already registered in MongoDB?
I am using the following environment:
-Microsoft.AspNetCore.App (2.1.1)
-MongoDB.Driver (2.8.0)
(as I mentioned in my comment) your problem seems pretty simple, as in MongoDB the related objects in hierarchy are part of the same document, so you need to update your object in-memory and update it.
var parentObject=CollRevendas.Find<Revenda>(revenda => revenda.Id == id).FirstOrDefault();
parentObject.Clientes.Add(newChildObject);
//now update the parent object
Code that worked for me: (Resolved with the support of Aarif)
public bool AddRevendaCliente(string revendaId, RevendaCliente requestRevendaClient)
{
try
{
var filter = Builders<Revenda>.Filter.Eq(s => s.Id, revendaId);
// Get a reference to the parent parent "Revenda"
var parentObject = CollRevendas.Find<Revenda>(filter).FirstOrDefault();
parentObject.Clientes.Add(requestRevendaClient);
// Update the parent object "Revenda"
var result = CollRevendas.ReplaceOneAsync(filter, parentObject);
}
catch (Exception ex)
{
throw;
}
return true;
}

Sort MultiLevel Data with Linq

I have a data structure as follows:
public class BranchLevel_1
{
public string Name { get; set; }
public ObservableCollection<BranchLevel_2> Children { get; set; }
public BranchLevel_1(string name, List<BranchLevel_2> children)
{
this.Name = name;
this.Children = new ObservableCollection<BranchLevel_2>(children);
}
}
public class BranchLevel_2
{
public ObservableCollection<BranchLevel_3> Contents { get; set; }
public BranchLevel_2(List<string> contents)
{
this.Contents = new ObservableCollection<BranchLevel_3>();
for (int i = 0; i < contents.Count; i++)
{
this.Contents.Add(new BranchLevel_3(contents[i]));
}
}
}
public class BranchLevel_3
{
public string Content { get; set; }
public BranchLevel_3(string text)
{
this.Content = text;
}
}
Sorting data on the first level is easy and I can obtain in easily by:
Level1_Data.OrderBy(item => item.Name).ToList()
However, I am stuck with sorting on the second level. BranchLevel_2 class is just a container for items stored in BranchLevel_3 classes. Therefore I would like to sort Level2 with data stored in BranchLevel_2.Contents1.Content value. This syntax for me seems to be correct and I cannot locate the problem...
Level1_Data.Select(item_Level1 => item_Level1.Children.OrderBy(item_Level2 => item_Level2.Contents[1].Content)).ToList();
Any hints?
Here is the rusult (indicated in yellow is supposed to be sorted alphabetically)
Why not just sort the contents before adding them to the ObservableCollection
public class BranchLevel_2
{
public ObservableCollection<BranchLevel_3> Contents { get; set; }
public BranchLevel_2(List<string> contents)
{
this.Contents = new ObservableCollection<BranchLevel_3>();
foreach (var content in contents.OrderBy(c => c))
{
this.Contents.Add(new BranchLevel_3(content));
}
}
}
Here is a solution that solved the problem, thanks to suggestion from #bhmahler
public class BranchLevel_1
{
public string Name { get; set; }
public ObservableCollection<BranchLevel_2> Children { get; set; }
public BranchLevel_1(string name, List<BranchLevel_2> children)
{
this.Name = name;
//this line needs to be added before creating ObservableCollection
children.OrderBy(item_level2 => item_level2.Contents[1].Content).ToList();
this.Children = new ObservableCollection<BranchLevel_2>(children);
}
}

Passing json object data from a ListView SelectedItem

I need some help with passing the ListView Tapped Id (which I get from a json).
I populate the listView with an API call to a server:
private async void searchButton_Click(object sender, RoutedEventArgs e)
{
var textFrom = odTextBox.Text;
var textTo = doTextBox.Text;
var searchResult = await PrevoziApi.SearchRidesAsync(textFrom, textTo, datePicker.Date.UtcDateTime);
var array = searchResult.CarshareList
.OrderBy(cs => cs.Time)
.Select(cs => cs.Contact + " " + cs.Time)
.ToArray();
listView.ItemsSource = array;
}
Now, when I click on an item of listView, I want to navigate to another page(CarShareDetailedPage) and make another call to the API, to get more detailed data about that item. So I need to pass the selectedItem id from one page to other. How do I do that ?
I'm navigating to another page like this:
private void listView_Tapped(object sender, TappedRoutedEventArgs e)
{
Frame.Navigate(typeof(CarShareDetailedPage), listView.SelectedIndex);
}
The OnNagiatedMethod on that page is:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var value = e.ToString();
carShareTextBox.Text = value;
}
And my json class is:
public class CarshareList
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("from_id")]
public string FromId { get; set; }
[JsonProperty("from_country")]
public string FromCountry { get; set; }
[JsonProperty("from_country_name")]
public string FromCountryName { get; set; }
[JsonProperty("to_id")]
public string ToId { get; set; }
[JsonProperty("to")]
public string To { get; set; }
[JsonProperty("to_country")]
public string ToCountry { get; set; }
[JsonProperty("to_country_name")]
public string ToCountryName { get; set; }
[JsonProperty("time")]
public string Time { get; set; }
[JsonProperty("date_iso8601")]
public DateTime DateIso8601 { get; set; }
[JsonProperty("added")]
public DateTime Added { get; set; }
[JsonProperty("price")]
public double? Price { get; set; }
[JsonProperty("num_people")]
public double NumPeople { get; set; }
[JsonProperty("author")]
public string Author { get; set; }
[JsonProperty("is_author")]
public string IsAuthor { get; set; }
[JsonProperty("comment")]
public string Comment { get; set; }
[JsonProperty("contact")]
public string Contact { get; set; }
[JsonProperty("date")]
public string Date { get; set; }
[JsonProperty("full")]
public string Full { get; set; }
[JsonProperty("insured")]
public string Insured { get; set; }
[JsonProperty("share_type")]
public string ShareType { get; set; }
[JsonProperty("confirmed_contact")]
public string ConfirmedContact { get; set; }
[JsonProperty("bookmark")]
public object Bookmark { get; set; }
[JsonProperty("from")]
public string From { get; set; }
}
public class CarshareResponse
{
[JsonProperty("search_type")]
public string SearchType { get; set; }
[JsonProperty("carshare_list")]
public IList<CarshareList> CarshareList { get; set; }
}
Let me say this is the first time ever I'm doing any work with Apis and json.
Thanks for your help!
EDIT: I added the code for the API below, so this now should be all the code I have.
public class PrevoziApi
{ public static async Task<CarshareResponse> SearchRidesAsync(
string fromCity,
string toCity,
DateTime date,
string type = "shares",
CancellationToken token = default(CancellationToken))
{
using (var client = new RestClient("https://prevoz.org/api/"))
{
var request = new RestRequest("search/" + type + "/", HttpMethod.Get);
request.AddQueryParameter("f", fromCity);
request.AddQueryParameter("fc", "SI");
request.AddQueryParameter("t", toCity);
request.AddQueryParameter("tc", "SI");
request.AddQueryParameter("d", date.ToString("yyyy-MM-dd"));
request.AddQueryParameter("exact", "true");
return
(await client.Execute<CarshareResponse>(request, token)).Data;
}
}
}
So with this, you are ordering by the time but displaying a string only that says "[Contact] [Time]". This in-and-of-itself does not hold any relation to the JSON that was returned from your search method. What you'll want to do is instead of making it an array, instead making a List<> object that can store some additional "background" data about that request to send off.
This will require a bit more effort though on your end. You will want to create a class
public class CarItemView {
public string DisplayText {get; set;}
public int ID {get; set;}
}
and fill it with whatever data you want to pass along. Then in your filtering you would do:
List<CarItemView> array = searchResult.CarshareList
.OrderBy(cs => cs.Time)
.Select(cs => new { DisplayText = cs.Contact + " " + cs.Time, ID = cs.Id}).ToList();
You will then, in your XAML, have to add a template to your listview for display. (Note, this is a real rough outline for a XAML Template)
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding DisplayText}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
NOW when you get your selected item changed event fired, you can handle it and get the ID.
private void listView_Tapped(object sender, TappedRoutedEventArgs e)
{
var obj = (CarItemView) listView.SelectedItem; // convert item to our new class
Frame.Navigate(typeof(CarShareDetailedPage), obj.Id.ToString()); // send ID as string
}
Then for the receiving page:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var value = e.ToString();
carShareTextBox.Text = value; // will show the ID number
var caritemret = /* write a new restful function to return based on ID */
}
UPDATE: This answer was updated from original to reflect the use of an array instead of a list<> object
I hope this helps!
This works:
private async void searchButton_Click(object sender, RoutedEventArgs e)
{
var textFrom = odTextBox.Text;
var textTo = doTextBox.Text;
var searchResult = await PrevoziApi.SearchRidesAsync(textFrom, textTo, datePicker.Date.UtcDateTime);
List<CarItemView> array = searchResult.CarshareList
.OrderBy(cs => cs.Time)
.Select(cs => new CarItemView { DisplayText = cs.Contact + " " + cs.Time, Id = cs.Id })
.ToList();
listView.ItemsSource = array;
}
private void listView_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
var obj = (CarItemView)listView.SelectedItem; // convert item to our new class
Frame.Navigate(typeof(CarShareDetailedPage), obj.Id); // send ID as string
}
And on navigated to method on the destination page:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var value = e.Parameter.ToString();
carShareTextBox.Text = value; // will show the ID number
/* write a new restful function to return based on ID */
}
Thanks #daniel, it was mostly as you suggested, with a few errors, but with the help of some guys at the c# chat channel I managed. Thanks to all.

Creating and returning copy of object in class method

I have a class called movie. Movie has a movieYear string property and movieYearInt int property. I want a class method where I can send the movie object and get an object back that has taken the movieYear string property and copied its value to movieYearInt. Later on I will be converting more properties of the object.
this is the movie class
public class movie
{
public string movieName { get; set; }
public string movieYear { get; set; }
public int movieYearInt { get; set; }
public movie convertFilm(movie m)
{
m.movieYearInt = int.Parse(m.movieYear);
return m;
}
}
and this is how I thought of retrieving the object in my form
movie m = new movie();
m.movieYear = cmbMovieYear.ToString();
movie newMovie = m.convertFilm(m);
The error i get is: input string was not in a correct format
what am I doing wrong?
edit-
This is the movieYear combobox
List<int> allYears = new List<int>();
allYears.AddRange(Enumerable.Range(1900, 113));
cmbMovieYear.DataSource = allYears;
edit-
m.movieYear = cmbMovieYear.SelectedItem.ToString();
This was the solution.
Instead of returning a converted object, have you considered modifying the getter for your movieYearInt property to something like this?
public int movieYearInt
{
get
{
// add some validation, and consider using System.Int32.TryParse
return System.Int32.Parse(movieYear);
}
}
public class movie: ICloneable
{
public string movieName { get; set; }
public string movieYear { get; set; }
public int movieYearInt { get { return int.Parse(movieYear) set {movieYear = value.ToString()}}
public object Clone()
{
return new movie() {movieName = this.movieName, movieYear = this.movieYear};
}
}
var m = new movie();
m.movieYear = "2001";
var newMovie = (movie) m.Clone();

List Updating a value after Insert

i have a issue, I want to Update a value to element which is getting added in a list.
With generic example:-
I have a Model Object:-
public class Model
{
public int ModelProperty1 { get; set; }
public int ModelProperty2 { get; set; }
public int ModelPropertyStatus { get; set; }
}
I have a DTO Object:-
public class DTO
{
public int DTOProperty1 { get; set; }
public int DTOProperty2 { get; set; }
public int DTOPropertyStatus { get; set; }
}
Now, in my Controller i have a List which adds Model object:-
List<Model> _listOfModel = new List<Model>();
Secondly, i have created a mapping method which maps my Model & DTO
private Model MapDTOToModel(DTO dto)
{
return new Model
{
ModelProperty1 = dto.DTOProperty1,
ModelProperty2 = dto.DTOProperty2
};
}
Coming to my Issue:-
I want something like this to work:-
//I want a piece of code that Updates my ModelPropertyStatus after it gets inserted to //List
_listOfModel.Add(new Model() { ModelPropertyStatus = 1 });
//Here is the piece of code i want to convert:-
Model model = new Model();
model.ModelPropertyStatus = 1;
_listOfModel.Add(MapDTOToModel(model));
To be specific(Updated)
I want something like this:-
_listOfModel.Add(MapDTOToModel() { ModelPropertyStatus = 1 });
Any Suggestions??
You are looking for an ObservableCollection:
Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
Here's an example:
public class Model
{
public int ModelProperty1 { get; set; }
public int ModelProperty2 { get; set; }
public int ModelPropertyStatus { get; set; }
}
void Main()
{
ObservableCollection<Model> _listOfModel = new ObservableCollection<Model>();
_listOfModel.CollectionChanged += (s, o) =>
{
foreach (var m in o.NewItems)
((Model)m).ModelPropertyStatus = 1;
};
var model = new Model();
Console.WriteLine("Before add: " + model.ModelPropertyStatus.ToString());
_listOfModel.Add(model);
Console.WriteLine("After add: " + model.ModelPropertyStatus.ToString());
}
output:
Before add: 0
After add: 1
As you can see, using the CollectionChanged event, the property gets updatet during the insert.

Categories