I'm trying to Graph Excel data using ChartJS.
Visual Studio is saying that List<Graphs> does not contain a definition for Answers.
I can't find anything wrong with my code, though. Though, I've only been using VS for the past two days.
Can someone look at my code and maybe find a mistake, or two? Thanks!
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using ReinovaGrafieken.Models;
namespace ReinovaGrafieken.Models
{
public class GraphDataViewModel
{
public List<Graphs> GraphData { get; set; }
}
}
Graphs Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using ReinovaGrafieken.Models;
namespace ReinovaGrafieken.Models
{
public class Graphs
{
public string Names { get; set; }
public string AnswerHeaders { get; set; }
public int Answers { get; set; }
public string Questions { get; set; }
public string AnteOrPost { get; set; }
}
}
And a piece of the code from the View:
#model ReinovaGrafieken.Models.GraphDataViewModel
#{
ViewBag.Title = "Dashboard";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
<h2>Dashboard</h2>
<div id="chart_container">
<canvas id="bar_chart"></canvas>
<script>
var answers = #Html.Raw(Json.Encode(#Model.GraphData.Answers));
var labels = #Html.Raw(Json.Encode(#Model.GraphData.Names));
This is where I got the ideas from, where it does work for that person:
https://www.youtube.com/watch?v=E7Voso411Vs&t=2787s
GraphData is collection of Graph. So Answers is accessible property on Graph and not GraphData.
Like #Stephen Muecke wrote, List<T> does not contain a property named Answers.
You could take element, which you need like this:
#Model.GraphData.First().Answers
(get first element from the list).
Or you can use .Foreach() method
Related
I'm following on some tutorial which creates TodoList and uses multiple layer structure to handle different business logic. When I copy code from the book it shows me an error when I fire dotnet run command in windows cmd. The error I get is displayed bellow so I can specify where lies the problem but don't know how to fix this. What can I do to make this work ? I'm using dotnet 3.0.100 version.
Services\FakeTodoItemService.cs(21,17): error CS0117: 'FakeTodoItemService' does
not contain a definition for 'Title' [C:\dotnetproject\AspNetCoreTodo\AspNetCor
eTodo\AspNetCoreTodo.csproj]Services\FakeTodoItemService.cs(22,17): error CS0117: 'FakeTodoItemService' doesn not contain a definition for 'DueAt' [C:\dotnetproject\AspNetCoreTodo\AspNetCor
eTodo\AspNetCoreTodo.csproj]
And here is a code which I think may be responsible for this error. Basically I have a service that implements interface which uses a model.
FakeTodoItemService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AspNetCoreTodo.Data;
using AspNetCoreTodo.Models;
namespace AspNetCoreTodo.Services
{
public class FakeTodoItemService : ITodoItemService
{
public Task<TodoItem[]> GetIncompleteItemsAsync()
{
var item1 = new TodoItem
{
Title = "Learn ASP.NET Core",
DueAt = DateTimeOffset.Now.AddDays(1)
};
var item2 = new FakeTodoItemService
{
Title = "Build awesome apps",
DueAt = DateTimeOffset.Now.AddDays(2)
};
return Task.FromResult(new[] {item1, item2});
}
}
}
TodoItem.cs
using System;
using System.ComponentModel.DataAnnotations;
namespace AspNetCoreTodo.Models
{
public class TodoItem
{
public Guid Id {get; set;}
public bool IsDone {get; set;}
[Required]
public string Title {get; set;}
public DateTimeOffset? DueAt {get; set;}
}
}
ITodoItemService.cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AspNetCoreTodo.Models;
namespace AspNetCoreTodo.Services
{
public interface ITodoItemService
{
Task<TodoItem[]> GetIncompleteItemsAsync();
}
}
In FakeTodoItemService.GetIncompleteItemsAsync you have this line var item2 = new FakeTodoItemService. FakeTodoItemService should be TodoItem.
I try to implement Metadatatype, in order to seperate Validation attributes from my Acquisitiecode class, into the AcquisitiecodeAnnotations class.
Now when I add attributes (like Required, StringLength and so on) to the Acquisitiecode class, validation works as expected. When I move these attributes to the AcquisitiecodeAnnotations class and bind this class using the MetadataType attribute, I does not work.
Please find the code examples below (I've stripped them down for readability). Also, the project is an ASP.NET Core 3.0 web application. All code, including the examples are also running in.NET Core 3.0 projects.
Snippet 1:
using System;
using System.ComponentModel.DataAnnotations;
namespace Shared.Entities
{
[MetadataType(typeof(AcquisitiecodeAnnotations))]
public partial class Acquisitiecode
{ }
public partial class AcquisitiecodeAnnotations
{
[StringLength(4, ErrorMessage = "The value cannot exceed 4 characters. ")]
public string Acquisitiecode1 { get; set; }
}
}
Snippet 2:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Shared.Entities
{
public partial class Acquisitiecode
{
public Acquisitiecode()
{
Lidmaatschap = new HashSet<Lidmaatschap>();
}
public string Acquisitiecode1 { get; set; }
public virtual Lid Lid { get; set; }
public virtual ICollection<Lidmaatschap> Lidmaatschap { get; set; }
}
}
As of October 2020 the current version of Blazor does not support Metadatatype.
For more information please read this issue.
We are a newbie for Xamarin. We are having an issue in binding the response data from a web service to a ListView.
We debugged and we can see the the web service is successfully responding with the data but it never gets populated.
Any ideas?
It's gotta be a small thing that we are missing. We have managed to display a single entry from the data with other views (in other parts of the project) BUT not in IEnumerable<> or List<>
Here's the code:
View - RoundsPage.xaml :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModels="clr-namespace:AthlosifyMobile.ViewModels"
x:Class="AthlosifyMobile.Views.RoundsPage">
<ContentPage.BindingContext>
<viewModels:RoundsViewModel />
</ContentPage.BindingContext>
<StackLayout>
<Entry Text="{Binding AccessToken}" />
<Button Command="{Binding GetRoundsCommand}" Text="Get all rounds" />
<Label Text="Rounds: "></Label>
<ListView ItemsSource="{Binding Rounds}" HasUnevenRows="true" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="Round 1:"></Label>
<Label Text="{Binding Name}"></Label>
<Label Text="{Binding DailyHandicap}"></Label>
<Label Text="{Binding PlayedUTC}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>`
ViewModel - RoundsViewModel.cs :
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows.Input;
using AthlosifyMobile.Annotations;
using Xamarin.Forms;
using AthlosifyMobile.Services;
using AthlosifyMobile.Models;
namespace AthlosifyMobile.ViewModels
{
public class RoundsViewModel : INotifyPropertyChanged
{
ApiServices _apiServices = new ApiServices();
public event PropertyChangedEventHandler PropertyChanged;
private IEnumerable<Round> _rounds;
public string AccessToken { get; set; }
public IEnumerable<Round> Rounds
{
get
{
return _rounds;
}
set
{
_rounds = value;
OnPropertyChanged();
}
}
public ICommand GetRoundsCommand
{
get
{
return new Command(async() =>
{
Rounds = await _apiServices.GetRoundsAsync(AccessToken);
});
}
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Model - Course.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace AthlosifyMobile.Models
{
public class Round : EntityBase
{
public Guid RoundID { get; set; }
public Guid UserID { get; set; }
public Guid RoundCategoryID { get; set; }
public Guid CourseID { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public int DailyHandicap { get; set; }
public DateTime PlayedUTC { get; set; }
public RoundCategory RoundCategory { get; set; }
public Course Course { get; set; }
public ICollection<RoundHole> RoundHoles { get; set; }
}
public abstract class EntityBase
{
public DateTime CreatedUTC { get; set; }
public DateTime LastModifiedUTC { get; set; }
}
}
Services - apiservices.cs:
using AthlosifyMobile.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace AthlosifyMobile.Services
{
public async Task<IEnumerable<Round>> GetRoundsAsync(string accessToken)
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var json = await client.GetStringAsync("http://localhost:5609/api/Rounds");
var list = JsonConvert.DeserializeObject<IEnumerable<Round>>(json);
return list;
}
}
}
You will need to diagnose whether this is an issue with connecting the View to the ViewModel or whether your Data Service isn't working correctly. Either way, there are a few things you should do to fix this!
Firstly you are using IEnumerable, instead you should be using ObservableCollection<T>. You should always be using ObservableCollection<T> for Binded list views. This is explained in the xamarin docs here (they automatically notify the view when their contents changed & update).
So you should make this change:
public ObservableCollection<Round> Rounds { get; }
Next you should verify that the bindings are correct. I would not recommend your approach of going straight to live data if you aren't familiar with xamarin. Firstly you should try adding some static objects to the view model and trying to bind them!
Disconnect your API code and call a method that creates some of your Round objects. Here is an example method (i use methods like these all the time when designing my ListViews UI).
public RoundsViewModel()
{
Rounds = CreateSampleData();
}
private ObservableCollection<Round> CreateSampleData()
{
ObservableCollection<Round> dummyData = new ObservableCollection<Round>();
dummyData.Add(new Round() { Name="User", handicap=1, PlayedUTC=DateTime.Now });
dummyData.Add(new Round() { Name="User", handicap=1, PlayedUTC=DateTime.Now });
dummyData.Add(new Round() { Name="User", handicap=1, PlayedUTC=DateTime.Now });
return dummyData;
}
At this point you will either see items in your ListView, meaning you have an issue with your API code / Implementation of INotifyPropertyChanged. If you don't see anything then you likely have an issue with binding and will need to verify that your view is actually connected to the View Model.
Mvvm Helpers
Seeing some of this code makes me feel very sorry for you, you definitely should looking into using an MVVM helper such as Prism or MVVMCross. I personally use Prism which provides a ViewModelBase which all ViewModels inherit from. This means all of the INotifyPropertyChanged code is hidden away from you (less boilerplate). It also has a dependancy service which means hooking views up to view models is as simple as registering it in the app.cs.
If you are interested in prism, watch this video with Brian Lagunas to see what Prism can do for you!
Update: There are now a few helpful libraries aside from Prism that will help with the MVVM stuff. Refractored.MVVMHelpers and Xamarin.CommunityToolkit both contain an essential object: ObservableRangeCollection.
ALL code using an ObservableCollection should be replaced with ObservableRangeCollection, it is an essential object and really belongs in a microsoft maintained namespace at this point. It creates a performance benefit for updating larger collections & reduces the need for alot of boilerplate when updating the ObservableCollection
I'm sure I am missing something very obvious, and I've read different threads (like this one, this and also this, just to name the last ones) but I still cannot find the answer...
Here are my classes:
using System;
using Newtonsoft.Json;
namespace WebAPIClient
{
public class XWTournament
{
private string name;
[JsonProperty("name")]
public string Name { get => name; set => name = value; }
}
public class Root
{
public XWTournament xwtournam { get => xwtournam; set => xwtournam = value; }
}
}
And here I try to use them:
msg = "{\"tournament\": {\"Name\": \"Worlds 2014 Flight One\"}}";
Root root = JsonConvert.DeserializeObject<Root>(msg) ;
string pippo = root.xwtournam.Name;
But in this case I am receiving a stack overflow error...
What am I missing? How can I read the variables in the string?
Edit: thanks to the useful answers, I have corrected the code in this way
using System;
using Newtonsoft.Json;
namespace WebAPIClient
{
public class XWTournament
{
//I've deleted the private variable
public string Name { get; set; }
}
public class Root
{
[JsonProperty("tournament")]
public XWTournament xwtournam { get; set; }
}
}
None of your classes have a property named tournament. Your JSON does. What does that suggest?
public class Root
{
public XWTournament tournament { get; set; }
}
You also don't need the infinite recursion in the setter as you wrote it. Try assigning to it: The getter and the setter both just call themselves. That's the cause of the stack overflow exception. You'd get one if you tried to set that property, too.
Suggest me a proper solution for autogenerating DTO elements when loading a proper XML for Deserialization.
This is my DTO
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace GHelper.DTO
{
public class ElementsDTO
{
[XmlRoot("GalLC")]
public class FareBB
{
[xmlElement("Ip")]
public string strIp { get; set; }
[xmlElement("Port")]
public int intPort { get; set; }
[xmlElement("Type")]
public int intPort{ get; set; }
[xmlElement("Email")]
public string strEmail{ get; set; }
}
}
}
Here is my XML
<GalLC>
<Ip>192.168.2.100</Ip>
<Port>5051</Port>
<Type></Type>
<Email></Email>
</GalLC>
The problem is: when i am getting a lengthy XML, I will consume lots of time to create a DTO for it.
Please suggest me something about creating a DTO automatically.
Given that it sounds like you've worked out how to get an XML schema definition (XSD) you could use XSD.exe to generate the classes or there's even online tools for it... And if you want something really custom, you could look into T4 Text Templates.