Reputation: 159
I need to display a PieChart
, I'm currently using Modern UI (Metro) Charts. I did copy the code in the documentation and the problem is that i'm always having the border and the title in the screen but no chart.
XAML
<UserControl x:Class="Projet.Recources0.Statistique.Ad_Aj"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:chart="clr-namespace:De.TorstenMandelkow.MetroChart;assembly=De.TorstenMandelkow.MetroChart"
mc:Ignorable="d" d:DesignWidth="1000" Height="670">
<UserControl.Resources>
<Style x:Key="MinimalChartStyle" TargetType="{x:Type chart:ChartBase}">
<Setter Property="Width" Value="500"/>
<Setter Property="Height" Value="500"/>
</Style>
</UserControl.Resources>
<Grid >
<chart:PieChart
Style="{StaticResource MinimalChartStyle}"
ChartTitle="Minimal Pie Chart"
ChartSubTitle="Chart with fixed width and height"
SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}" >
<chart:PieChart.Series>
<chart:ChartSeries
SeriesTitle="Errors"
DisplayMember="Category"
ValueMember="Number"
ItemsSource="{Binding Path=Errors}" />
</chart:PieChart.Series>
</chart:PieChart>
</Grid>
CS
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Projet.Recources0.Statistique
{
/// <summary>
/// Interaction logic for Ad_Aj.xaml
/// </summary>
public partial class Ad_Aj : UserControl
{
public ObservableCollection<TestClass> Errors { get; private set; }
public Ad_Aj()
{
Errors = new ObservableCollection<TestClass>();
Errors.Add(new TestClass() { Category = "Globalization", Number = 75 });
Errors.Add(new TestClass() { Category = "Features", Number = 2 });
Errors.Add(new TestClass() { Category = "ContentTypes", Number = 12 });
Errors.Add(new TestClass() { Category = "Correctness", Number = 83});
Errors.Add(new TestClass() { Category = "Best Practices", Number = 29 });
}
private object selectedItem = null;
public object SelectedItem
{
get
{
return selectedItem;
}
set
{
// selected item has changed
selectedItem = value;
}
}
}
// class which represent a data point in the chart
public class TestClass
{
public string Category { get; set; }
public int Number { get; set; }
}
}
Upvotes: 5
Views: 953
Reputation: 13188
Create a ViewModel
to hold data for your chart and assign it to your DataContext
as shown below:
XAML:
<Window x:Class="WpfApplication222.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:chart="clr-namespace:De.TorstenMandelkow.MetroChart;assembly=De.TorstenMandelkow.MetroChart"
xmlns:local="clr-namespace:WpfApplication222"
mc:Ignorable="d"
Title="Window2" Height="350" Width="525">
<Window.DataContext>
<local:PieChartViewModel/>
</Window.DataContext>
<Grid>
<chart:PieChart
ChartTitle="Minimal Pie Chart"
ChartSubTitle="Chart with fixed width and height"
SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}" >
<chart:PieChart.Series>
<chart:ChartSeries
SeriesTitle="Errors"
DisplayMember="Category"
ValueMember="Number"
ItemsSource="{Binding Path=Errors}" />
</chart:PieChart.Series>
</chart:PieChart>
</Grid>
ViewModel:
public class PieChartViewModel
{
public ObservableCollection<TestClass> Errors { get; private set; }
public PieChartViewModel()
{
Errors = new ObservableCollection<TestClass>();
Errors.Add(new TestClass() { Category = "Globalization", Number = 75 });
Errors.Add(new TestClass() { Category = "Features", Number = 2 });
Errors.Add(new TestClass() { Category = "ContentTypes", Number = 12 });
Errors.Add(new TestClass() { Category = "Correctness", Number = 83 });
Errors.Add(new TestClass() { Category = "Best Practices", Number = 29 });
}
}
EDIT: Rather than having your ViewModel
created in XAML as before, you can also do it dynamically as follows:
XAML:
Window x:Class="WpfApplication222.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:chart="clr-namespace:De.TorstenMandelkow.MetroChart;assembly=De.TorstenMandelkow.MetroChart"
xmlns:local="clr-namespace:WpfApplication222"
mc:Ignorable="d"
Title="Window2" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<chart:PieChart
ChartTitle="Minimal Pie Chart"
ChartSubTitle="Chart with fixed width and height"
SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}" >
<chart:PieChart.Series>
<chart:ChartSeries
SeriesTitle="Errors"
DisplayMember="Category"
ValueMember="Number"
ItemsSource="{Binding Path=Errors}" />
</chart:PieChart.Series>
</chart:PieChart>
</Grid>
CS:
public partial class Window2 : Window
{
PieChartViewModel viewModel;
public Window2()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
viewModel = new PieChartViewModel();
viewModel.Errors.Add(new TestClass() { Category = "Globalization", Number = 75 });
viewModel.Errors.Add(new TestClass() { Category = "Features", Number = 2 });
viewModel.Errors.Add(new TestClass() { Category = "ContentTypes", Number = 12 });
viewModel.Errors.Add(new TestClass() { Category = "Correctness", Number = 83 });
viewModel.Errors.Add(new TestClass() { Category = "Best Practices", Number = 29 });
DataContext = viewModel;
}
}
ViewModel:
public class PieChartViewModel
{
public ObservableCollection<TestClass> Errors { get; private set; }
public PieChartViewModel()
{
Errors = new ObservableCollection<TestClass>();
}
}
Upvotes: 1
Reputation: 2594
So you're off to the right track! You're only missing one line of code!
public partial class Ad_Aj : UserControl
{
public ObservableCollection<TestClass> Errors { get; private set; }
public Ad_Aj()
{
/*
* ----------------------------
* This is line you're missing.
* ----------------------------
*/
DataContext = this;
/*
* ----------------------------
*/
Errors = new ObservableCollection<TestClass>();
Errors.Add(new TestClass() { Category = "Globalization", Number = 75 });
Errors.Add(new TestClass() { Category = "Features", Number = 2 });
Errors.Add(new TestClass() { Category = "ContentTypes", Number = 12 });
Errors.Add(new TestClass() { Category = "Correctness", Number = 83});
Errors.Add(new TestClass() { Category = "Best Practices", Number = 29 });
}
}
This is MVVM, but it's not true MVVM. True MVVM has a separate ViewModel class. What you're are doing here is using the Code-Behind of your View as your ViewModel. It works, and no one will fight you on that. However, if you're trying to do true MVVM, then you'll need to separate out your classes.
jstreet has a great answer/example of how to set your DataContext (aka the "binding") to the ViewModel in XAML.
<Window.DataContext>
<local:PieChartViewModel />
</Window.DataContext>
However, take note that he's using a separate ViewModel
class. The code you provided in your question does not do this, so I'm not sure how to do it the same way. Also, it's worth mentioning that if your ViewModel
class uses constructor dependency injection or has parameters, that you're going to have to use some magic to get this to work. If that's the case, it's easier to just set it in the constructor.
Upvotes: 1
Reputation: 1229
I am not an expert with the control but I am guessing that your ItemsSource
binding is failing. The Errors
collection is on the user control as a property and your binding on the ItemsSource
is by default going to go off of the DataContext
which I am thinking is null in your case. To get the the control directly through a binding you would likely get it to work with the RelativeSource
markup extension by doing something like (assuming that you map "local" to the namespace where Ad_Aj is located):
ItemsSource = "{Binding RelativeSource={RelativeSource AncestorType=local:Ad_Aj, Mode=FindAncestor}, Path=Errors}"
I think though that you would want to put your Errors
information in a view model and then set that to the data context and use the bindings as you have them since the Errors
information is really data and separate from the UI.
Upvotes: 0