TypeInitializationException in Initialize Component Xamarin - c#

namespace FBLALibraryApp2
{
public partial class GenrePage : ContentPage
{
public GenrePage()
{
InitializeComponent();
listView.ItemsSource = DataStorage.GenreList;
}
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void listView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
listView.SelectedItem = null;
}
async private void listView_ItemTapped(object sender, ItemTappedEventArgs e)
{
if (e.Item is GenreGroup)
await Navigation.PushAsync(new GenreView((GenreGroup)e.Item));
}
}
}
Here is the code for a page that I have made in Xamarin. It is a simple page that displays a list of GenreGroup's. It has worked fine in the past, but recently, when I changed my code initializing the list, the application would run to a blank screen. So, I paused debugging and saw it was stuck at, initially, listView.ItemSource = DataStorage.GenreList;. Upon hitting continue, the application would throw a TypeInitializationException. I was worried that perhaps the most recent version of my code was not being built (this has happened to me before with Fast Deployment enabled), so I added a Debug.log("x"); before the troublesome line to ensure that the most recent code was being run. Upon doing this, the application began freezing on InitializeComponent() and throwing the same exception. I am stumped here as to what to do. Here is the code for where I declare the list:
public static class DataStorage
{
public static List<Book> AllBookList = new List<Book> { new Book { Title = "Harry Potter", Author = "J.K. Rowling", Summary="lorem ipsum dolorum sdjfa;dklfja;dkfj;akdfja;dfjkaf", Genre= new string[] { "Fantasy", "Adventure" }, pubYear="2017" }, new Book { Title = "The Hunger Games", Author = "Suzanne Collins", Summary = "lorem ipsum dolorum sdjfa;dklfja;dkfj;akdfja;dfjkaf", Genre = new string[] { "Sci-Fi" }, pubYear = "2017" }, new Book { Title = "Thief in the Night", Author = "Jack Nimble", Summary = "lorem ipsum dolorum sdjfa;dklfja;dkfj;akdfja;dfjkaf", Genre = new string[] { "Mystery"}, pubYear = "2017" }, new Book { Title = "Hardy Bros.", Author = "Johnny Heather", Summary = "lorem ipsum dolorum sdjfa;dklfja;dkfj;akdfja;dfjkaf", Genre = new string[] { "Mystery", "Comedy" }, pubYear = "2017" } };
public static List<GenreGroup> GenreList = new List<GenreGroup> { new GenreGroup("Mystery", "jd;akfjd;"), new GenreGroup("Fantasy", "dja;fdjkl") };
public static GenreGroup Mystery = new GenreGroup("Mystery","djfsldfjldjF");
public static GenreGroup Fantasy = new GenreGroup("Fantasy", "djfsldfjldjF");
static DataStorage()
{
foreach (Book book in AllBookList)
{
for (int x = 0; x < book.Genre.Length; x++)
{
if (book.Genre[x] == "Mystery")
{
Mystery.Add(book);
}
else if (book.Genre[x] == "Fantasy")
{
Fantasy.Add(book);
}
}
}
GenreList = new List<GenreGroup> { Mystery, Fantasy };
}
}
I suspect the issue is somewhere in this code, as this is what I changed. Note: I understand that my code right now is a little strange and I define GenreList explicitly, and then redefine it later, but I was trying to ensure it wasn't null for whatever reason. Thanks for any help
Update: upon placing Debug.WriteLine BEFORE InitializeComponent, it now freezes on Debug.WriteLIne and throws the same, TypeInitializationEXception
Update: Here is the code for GenreGroup and Book
public class GenreGroup : List<Book>
{
public string Title { get; set; }
public string Description { get; set; }
public GenreGroup(string title, string description)
{
Title = title;
Description = description;
}
}
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
public string Summary { get; set; }
public string[] subjectHeadings { get; set; }
public string[] Genre { get; set; }
public string pubYear { get; set; }
}

You' re missing initializations here:
public static GenreGroup Mystery; // Init this
public static GenreGroup Fantasy; // And this
Edit: I just ran your code and it's fine. Just clean your project and rebuild it. VS has plenty of bugs. Cheers.

listView.ItemsSource = DataStorage.GenreList;
This line will call static DataStorage(), in this static constructor, Mystery and Fantasy should be initialized before you call it. So the solution should be this:
1) Add public GenreGroup() { } in your GenreGroup class;
2) Init Mystery and Fantasy in DataStorage class:
public static GenreGroup Mystery = new GenreGroup();
public static GenreGroup Fantasy = new GenreGroup();

Related

Trying to make a bookshelf console application but having some trouble with lists. (C# Beginner)

I am trying to make a bookshelf application but I am having trouble with using lists. What I am hoping for is after the user specifies how many books they would like to add, the for-loop should hopefully repeat the method in the specified amount.
After the first run through of the method, the more titles added will add onto the list.
class Shelf
{
public void Program()
{
Book book = new Book();
int bookAmount;
Console.WriteLine("How many books are you adding.");
bookAmount = int.Parse(Console.ReadLine());
for(int x = 0; x <= bookAmount; x++)
{
AddBook(book);
}
}
public void AddBook(Book book)
{
List<string> bookTitles = new List<string>();
string bookTitle;
Console.WriteLine("Enter title.");
bookTitle = Console.ReadLine();
bookTitles.Add(bookTitle);
bookTitles = book.Title; // 'Cannot implicitly convert type 'string' to 'System.Collections.Generic.List<string>'
}
}
class Book
{
private string title;
public string Title
{
get { return title; }
set { title = value; }
}
}
Any critique is welcome. Thank you in advance.
What you would want to do would be something like this:
public class Book
{
public string ISBN { get; set; }
public string Title {get; set; }
public string Author {get; set; }
}
The book will represent our data model. Now you would do this:
List<Book> library = new List<Book>();
int quantity;
while(quantity < 7)
{
library.Add("12345", "C#", "Someone");
}
What the code is doing, we create a List<Book> which will hold our data model. Then you would have a loop that iterates based on value the user inputs. Then you would simply call the library (List) and add after it ask the user for input.
Obviously I'm not attempting to get user input or validation, but is using the example of how to use a List.
Following can be helpful:
class Shelf
{
List<Book> books = new ArrayList<Book>();
public void Program()
{
int numberOfBooks;
Console.WriteLine("How many books are you adding.");
numberOfBooks = int.Parse(Console.ReadLine());
for(int x = 0; x <= numberOfBooks; x++)
{
AddBook();
}
}
public void AddBook()
{
string bookTitle;
Console.WriteLine("Enter title.");
bookTitle = Console.ReadLine();
books.Add(new Book(bookTitle));
}
}
class Book
{
private string title;
public Book(string _title)
{
title = _title;
}
public string Title
{
get { return title; }
set { title = value; }
}
}
Keep in mind to:
Assign meaningful names to variables
Use input arguments to methods when it is needed
Pay more attention to Global and Local variables and when they should be used
I think that you must change your code like below code:
1- you must create book in addbook but you crate class in main program function
2- you can not convert string to list
3- your colcetion must contain a book
class Shelf
{
public void Program()
{
int bookAmount;
Console.WriteLine("How many books are you adding.");
bookAmount = int.Parse(Console.ReadLine());
//book is deleted
for(int x = 0; x <= bookAmount; x++)
{
AddBook();//parameter was deleted and aff in function
}
}
List<Book> bookTitles = new List<Book>(); //collection create generally in class like fields
public void AddBook()
{
Book book = new Book();
string bookTitle;
Console.WriteLine("Enter title.");
Book.Title = Console.ReadLine();
bookTitles.Add(book); //add book to colection
}
}
class Book
{
private string title;
public string Title
{
get { return title; }
set { title = value; }
}
}

C# multi level object and list access

I have no idea what should this question be titled nor keyword to search.
Scenario:
I have a model as below
public class Message { public List<Page> Pages { get; set; }
public class Page { public List<Line> Lines { get; set; }
public class Line { public string Text {get; set; }
When I wanted to insert a Line with Text = "Test" at Page 1, I would need to do the following.
var Message = new Message();
var line = new Line { Text = "Test" };
var page = new Page();
page.Lines.Add(line);
Message.Pages.Add(page);
Question: are there any easier way to achieve this? Eg.
Message.Pages[0].Lines[0].Text = "Test";
Thanks.
Edit: Assumed all properties are properly instantiated in constructors.
var msg = new Message {
Pages = new List<Page> {
new Page {
Lines = new List<Line> { new Line { Text = "Test" } }
}
}
};
Note: if the lists are initialized in their respective constructors, you can remove the new List<> bits:
var msg = new Message {
Pages = {
new Page {
Lines = { new Line { Text = "Test" } }
}
}
};
You could also add an implicit conversion operator from string to Line, in which case:
var msg = new Message {
Pages = {
new Page {
Lines = { "Test" }
}
}
};
Edit: fully working example, including operator and ctor initialization, and multiple pages (see comments):
using System.Collections.Generic;
public class Message {
public List<Page> Pages { get; private set; }
public Message() { Pages = new List<Page>(); }
}
public class Page {
public List<Line> Lines { get; private set; }
public Page() { Lines = new List<Line>(); }
}
public class Line {
public string Text { get; private set; }
public static implicit operator Line(string value) {
return new Line { Text = value };
}
}
static class Program {
static void Main() {
var msg = new Message {
Pages = {
new Page {
Lines = { "Test" }
},
new Page {
Lines = {
"On another page",
"With two lines"
},
}
}
};
}
}
You can create helper methods in your classes, which will provide handy API for building messages and pages. First is Message class - new Add method accepts page to add, and returns message instance. That will allow to use fluent API for adding pages (example at the bottom):
public class Message
{
public Message()
{
Pages = new List<Page>();
}
public List<Page> Pages { get; private set; }
public Message Add(Page page)
{
Pages.Add(page);
return this;
}
}
And page class. I added static creation method, which builds page with any number of lines you pass to this method:
public class Page
{
public Page()
{
Lines = new List<Line>();
}
public List<Line> Lines { get; private set; }
public static Page WithLines(params string[] texts)
{
var page = new Page();
foreach(var text in texts)
page.Lines.Add(new Line { Text = text });
return page;
}
}
Then adding page with lines will look like
message.Add(Page.WithLines("Text1", "Text2"))
.Add(Page.WithLines("Text3"));
What Marc and Sergey said. Also you can consider a simplified builder. I replaced the properties with fields to make the example smaller:
public class Message { public List<Page> Pages = new List<Page>(); }
public class Page { public List<Line> Lines = new List<Line>(); }
public class Line { public string Text; }
Then your builder would look something like this:
public class Typewriter
{
Message message = new Message();
Page currentPage;
public Typewriter NewPage()
{
currentPage = new Page();
message.Pages.Add(currentPage);
return this;
}
public Typewriter AddLine(string text)
{
currentPage.Lines.Add(new Line() { Text = text });
return this;
}
}
Then you can do:
var typewriter = new Typewriter();
typewriter.NewPage().AddLine("First line on first page")
.AddLine("Next line on first page")
.NewPage().AddLine("Next page etc");

Exception when Asynchoon loading of datagridview bindinglist

When I try to load a datagridview asyncroon I recieve an InvalidOperationException with the message: "Operation is not valid due to the current state of the object."
This happens when I add an item to the BindingList and invocation is requierd. Without threading no exception is thrown. Any help is much appreciated.
These are the methods I use to add items to the DataGridview:
public static class ExtensionMethods
{
public static void LoadAsync<T>(this DataGridView gv, IEnumerable<T> enumerable)
{
gv.DataSource = new BindingList<T>();
new Thread(() => gv.LoadItems(enumerable)) { IsBackground = true, Name = "AsyncLoad" }.Start();
}
private static void LoadItems<T>(this DataGridView gv, IEnumerable<T> enumerable)
{
foreach (T item in enumerable)
gv.AddItemToDataSourche(item);
}
private static void AddItemToDataSourche<T>(this DataGridView gv, T item)
{
if (gv.InvokeRequired)
gv.Invoke(new Action(() => gv.AddItemToDataSourche(item)));
else
((BindingList<T>)gv.DataSource).Add(item); //This is where it goes wrong.
}
}
This is how I instantiate the DataGridView:
public partial class Form1 : Form
{
private DataGridView _gv = new DataGridView();
private readonly IEnumerable<Person> _persons = new List<Person>
{
new Person {ID = 1, FirstName = "Test 1", LastName = "Someone"},
new Person {ID = 2, FirstName = "Test 2", LastName = "Someone"},
new Person {ID = 3, FirstName = "Test 3", LastName = "Someone"}
};
public Form1()
{
InitializeComponent();
Controls.Add(_gv);
_gv.LoadAsync(_persons);
}
}
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
I don't think the DataGridView control is in a ready state yet for that operation, so it won't work in the constructor, and the Load method seems too early, too, so try the OnShown override method instead:
protected override void OnShown(EventArgs e) {
base.OnShown(e);
_gv.LoadAsync(_persons);
}

Changing a class's property from another class

I have a class with properties:
public class TaskConfiguration
{
public string Task_Name
{
get; set;
}
public string task_id
{
get; set;
}
}
And somewhere in the code I have a method to set the properties of the class early on upon program execution:
public class TaskManagingProcess
{
public void InsertTaskProperties()
{
TaskConfiguration tc = new TaskConfiguration();
tc.Task_Name = "Sample Task";
tc.task_id = "1";
}
}
Later in execution, in another class, I want to modify the properties of the TaskConfiguration class, but I'm not sure how. If I use the following, it will not work because it creates a new instance of the TaskConfiguration class.
TaskManagingProcess tmp = new TaskManagingProcess;
tmp.InsertTaskProperties();
So how can I do this?
You want to pass the object:
public void InsertTaskProperties(TaskConfiguration config) {
config.Task_Name = "Sample Task";
config.task_id = "1";
}
Then:
TaskManagingProcess tmp = new TaskManagingProcess();
TaskConfiguration config = new TaskConfiguration();
tmp.InsertTaskProperties(config);
(I am making an awfully large assumption about your code.. but this should give you the basic idea)
It looks to me like TaskManagingProcess is a proxy class that's why I would recommend something like:
public class TaskConfiguration
{
public string Task_Name
{
get;
set;
}
public string task_id
{
get;
set;
}
}
public class TaskManagingProcess
{
private TaskConfiguration taskConfiguration;
public TaskManagingProcess(TaskConfiguration taskConfiguration)
{
this.taskConfiguration = taskConfiguration;
}
public void InsertTaskProperties(string taskId, string name)
{
taskConfiguration.task_id = taskId;
taskConfiguration.Task_Name = name;
}
}
So at the end you could do this (see below) and easily add code to handle the access at your TaskConfiguration object:
TaskConfiguration taskConfiguration = new TaskConfiguration() { task_id = "1", Task_Name = "Sample Task" };
TaskManagingProcess taskManaginProcess = new TaskManagingProcess(taskConfiguration);
taskManaginProcess.InsertTaskProperties("2", "Sample Task 2");

MongoDb c# update array in document

I have the following code:
_eventInstanceRepository.GetInnerCollection().Update(
Query.EQ("_id", listingEventModel.Id),
Update.PushWrapped<string[]>("ArtistIds", ids.ToArray()));
Which is designed to update the following document:
public class ListingEvent
{
public ObjectId Id { get; set; }
public string[] ArtistIds { get; set; }
}
ids is a List
Any ideas why this isn't updating the docs?
[UPDATE]
Also tried this!
foreach (var id in ids)
{
_eventInstanceRepository.GetInnerCollection().Update(
Query.EQ("_id", listingEventModel.Id),
Update.Push("ArtistIds", id));
}
No luck...
[UPDATE]
Going back to RavenDb - at least for now. I don't see how MongoDb is a viable option the whole time there are no real sources discussing (slightly more complex than flat structure) document updates on the internet and the examples I can find simply do not work.
[UPDATE]
Here is the repository code:
public class Repository<T> : IRepository<T>
{
private readonly MongoCollection<T> _docs;
public Repository(MongoCollection<T> docs)
{
_docs = docs;
}
public IList<T> GetAll()
{
return _docs.FindAll().Select<T, T>(x => x.As<T>()).ToList();
}
//HACK!
public MongoCollection<T> GetInnerCollection(){
return _docs;
}
public void Save(T doc)
{
_docs.Save(doc);
}
public void Save(IEnumerable<T> docsToSave)
{
foreach (var doc in docsToSave) Save(doc);
}
public void Dispose()
{
throw new NotImplementedException();
}
public void Delete(string id)
{
var query = Query.EQ("_id", id);
_docs.Remove(query);
}
}
Working sample code for appending a list of strings to an existing list of strings using a strongly-typed Push:
class Event
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public List<string> Participants { get; set; }
}
class Program
{
static void Main(string[] args)
{
MongoClient client = new MongoClient("mongodb://localhost/test");
var db = client.GetServer().GetDatabase("test");
var collection = db.GetCollection("events");
var event0 = new Event { Name = "Birthday Party",
Participants = new List<string> { "Jane Fonda" } };
collection.Insert(event0);
collection.Update(Query.EQ("_id", event0.Id),
Update<Event>.PushAll(p => p.Participants,
new List<string> { "John Doe", "Michael Rogers" }));
}
}

Categories

Resources