Unable to bind whole Chart to Frontend - c#

I am looking for a way to bind a whole Chart in my xaml. Not only one Series, but the whole Chart. This is due to my need to add multiple Series dynamically to the Chart.
XAML:
<chart:Chart DataContext="{Binding Path=FocusEnergyChart, UpdateSourceTrigger=PropertyChanged}"/>
C#:
public void DrawChart()
{
myChart = new Chart();
LinearAxis xAxis = new LinearAxis();
xAxis.Orientation = AxisOrientation.X;
xAxis.Title = "Energy";
LinearAxis yAxis = new LinearAxis();
yAxis.Orientation = AxisOrientation.Y;
yAxis.Title = "Focus";
myChart.Axes.Add(xAxis);
myChart.Axes.Add(yAxis);
myChart.Title = "Focus Energy - Chart";
foreach( string aKey in myGraphData.Keys)
{
BubbleSeries aSeries = new BubbleSeries();
aSeries.Title = aKey;
aSeries.ItemsSource = myGraphData[aKey];
aSeries.DependentValuePath = "Focus";
aSeries.IndependentValuePath = "Energy";
aSeries.SizeValuePath = "Size";
aSeries.SetResourceReference(Series.BackgroundProperty, "Background");
aSeries.SetResourceReference(BubbleSeries.LegendItemStyleProperty, "CustomLegendItemStyle");
aSeries.SetResourceReference(BubbleSeries.DataPointStyleProperty, "BubbleToolTipTemplate");
myChart.Series.Add(aSeries);
}
base.OnPropertyChanged("FocusEnergyChart");
}
public Chart FocusEnergyChart
{
get { return myChart; }
}
When i try to run this code it just shows me an empty ChartArea.
I hope someone can help me!
Thanks!

All you do here is add another chart as the DataContext of your chart declared from XAML.
You can use a ContentControl and bind it's content to your chart created from code-behind:
<ContentControl Content="{Binding Path=FocusEnergyChart}" />

Related

Xamarin calculating a stack layout height at run time

I am trying to create a dynamic view, where I get the data from the backend and create views for it on my Xamarin App.
In the XAML view I have a simple stack layout
<StackLayout x:Name="Container">
</StackLayout>
and I am creating views as soon as the date is retrieved as so
Label label = new Label();
label.Text= Text;
label.LineHeight = 1.1;
Container.Children.Add(CreateLabel(label));
The problem is the view doesn't expand to fit all the elements added
calculating the height and setting it as the HeightRequest for stack layout didn't work
any idea or suggestion would be nice.
I made a demo for you by writing the MainPage.xaml.cs file.
public partial class MainPage : ContentPage
{
String Text1 = "This is a text. This is a text.This is a text.This is a text.";
Double LineHeight1 = 1.78;
public MainPage()
{
InitializeComponent();
var layout = new StackLayout { };
var label = new Label { Text = Text1, TextColor = Color.Black, FontSize = 20, LineHeight = LineHeight1, BackgroundColor = Color.Red, LineBreakMode = LineBreakMode.WordWrap };
layout.Children.Add(label);
this.Content = layout;
}
}
You can see that I create a StackLayout and a label and I bind the layout to the content. It works well and you can try it.

Binding Label's visible property in a list with Toggle switch

I have a toggle button and list which contains Label in it.
Toggle(Switch) and List View are declared in Xaml file where list's Data-cell is generated programatically in cs file.
I need to hide/show this label in the list based on the toggle switch
Xaml code:
<Switch IsToggled="{Binding IsToggled, Mode=TwoWay}" Grid.Row = "0" Grid.Column = "1" HorizontalOptions = "Start" Margin = "10,8,8,0"></Switch>
<ListView x:Name="lvItemSigns" HasUnevenRows="True" SeparatorVisibility="Default" SeparatorColor="Gray">
cs file code:
lvItemSigns.ItemTemplate = new DataTemplate(typeof(DataCell));
lvItemSigns.ItemsSource = VM.ItemSignsList;
class DataCell : ViewCell
{
Label label;
public DataCell()
{
// has grid
var label = new Label();
label.TextColor = Color.Black;
label.Margin = 4;
label.Text = "test";
grid.Children.Add(label, 2, 1);
label.SetBinding(Label.IsVisibleProperty, new Binding("BindingContext.IsToggled", BindingMode.TwoWay, new BooleanConverter(), null, null, "cs-file_name"));
grid.Children.Add(stackLayout, 0, 3);
grid.Margin = new Thickness(8,0,0,0);
View = grid;
}
}
In ViewModel:
public bool _IsToggled;
public bool IsToggled
{
get
{
return _IsToggled;
}
set
{
_IsToggled= value;
OnPropertyChanged("_IsToggled");
}
}
public ItemSignsTabViewModel()
{
ItemSignsList = new ObservableCollection<TicketItem>(daItemSign.GetItemSigns(Ticket.MobileID));
}
I'm binding the visible property to Label but still I can see the label all the time (when toggle switch is on or off).
I know I'm doing something wrong. Any help?
Your DataContext for the Switch's binding is different from you DataCell's DataContext.
Both views are not targeting the same objects.
You need to post the code of your viewmodels for both the page, and the DataCell in order to get help.

Need directions on how to make a List with different items, to bind it to a ListView

I need to make a ListView where each row will have an image, then a Text, then another image.
Since to make a GridView I had to bind its DataContext to a List with all the images, and they work (almost) the same way, I think I need to make another List with the images and texts
The format is: "Store Logo. Promotion Text. Credit Card Logo" and all this data comes from an API.
I already have all the pictures saved in different folders ("Stores" and "PaymentMethods") and I get the text like
myTextBlock.text = item.promotion;
Now my questions are:
1) Is it possible to make a list with all this data? How? (or where do I have to look for it)
2) Once I have the list, how, by binding it, can I be sure that it will respect the format I mentioned above?
(Something I tried out, instead of having a ListView, was creating everything at runtime:
public async void getPromos()
{
if (Resp.searchResults.Count > 0)
{
var selected = from promo in Resp.searchResults
where (promo.store_id != null || promo.method_id != null)
select new
{
store = promo.store_id,
medio = promo.method_id,
endDay = promo.to,
promocion = promo.desc
};
foreach (var item in selected)
{
Debug.WriteLine(item.store);
await showPromos(item.store, item.medio, item.endDay, item.promocion);
}
}
}
async Task showPromos(string store, string medio, string endDay, string promocion)
{
Debug.WriteLine(store);
Debug.WriteLine("medio" + medio);
StorageFolder folder1 = await KnownFolders.PicturesLibrary.GetFolderAsync("UnicenterMediosFolder");
StorageFolder folder2 = await KnownFolders.PicturesLibrary.GetFolderAsync("UnicenterStores");
if (store != null)
{
StorageFile file = await folder2.GetFileAsync(store + ".png");
ImageProperties properties = await file.Properties.GetImagePropertiesAsync();
if (properties.Width > 0)
{
var bitmap = new WriteableBitmap((int)properties.Width, (int)properties.Height);
bitmap.SetValue(NameProperty, (string)properties.Title);
Debug.WriteLine(bitmap.PixelWidth);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
bitmap.SetSource(stream);
}
Color customColor = ColorHelper.FromArgb(213, 213, 213, 213);
StackPanel casa = new StackPanel();
casa.Orientation = Orientation.Horizontal;
casa.Background = new SolidColorBrush(customColor);
casa.Height = 70;
Image promoImage = new Image();
promoImage.Source = bitmap;
promoImage.Width = 70;
promoImage.Height = 70;
TextBlock thePromo = new TextBlock();
thePromo.Text = promocion;
thePromo.Foreground = new SolidColorBrush(Colors.Gray);
casa.Children.Add(promoImage);
casa.Children.Add(thePromo);
gridForPromos.Children.Add(casa);
Debug.WriteLine("aaa" + gridForPromos.Children.Count);
}
}
}
and in my xaml:
<ScrollViewer x:Name="myPromoSpace" Grid.Row="2">
<Grid x:Name="gridForPromos"/>
</ScrollViewer>
But doing this, I get each stackpanel on the previous one, instead of having them one under the other)
Can you guys point me in the right direction here, please?
When you add elements to a Grid without setting Grid.Row and having Grid.RowDefinitions, all the childs will be in the same grid cell. You either need to add RowDefinitions and set the row of the child:
gridForPromos.RowDefinitions.Add(new RowDefinition(...))
Grid.SetRow(casa, gridForPromos.RowDefinitions.Count);
or replace your Grid with a StackPanel:
<StackPanel x:Name="gridForPromos" />
But I would prefer to define a DataTemplate for your Items. With this you can define the visual apperance of your items in XAML and simple bind a StackPanel to your items. Here a link that shows you how to do: http://www.wpftutorial.net/datatemplates.html

Cannot Convert Lambda expression to type 'System.Type' because it is not a Delegate Type

I am working in Xamarin.Forms, to try and create a Pop Up window which contains a ListView.
I am trying to use this structure:
var PopUp = new StackLayout
{
BackgroundColor = Color.Black, // for Android and WP
Orientation = StackOrientation.Vertical,
Children =
{
PLZOrt_Label, // my Label on top
SearchBarPLZOrt, // my SearchBar to the ListView
LVPLZOrt, // The Listview (all Cities/Zip-Codes in the Datasource -> List)
}
};
Taken from this guide page 13.
However, when I add a list view ( as detailed here ),
new Func<object> (delegate {
ListView listView = new ListView {
// Source of data items.
ItemsSource = devices,
ItemTemplate = new DataTemplate(() =>
{
// Create views with bindings for displaying each property.
Label nameLabel = new Label();
nameLabel.SetBinding(
Label.TextProperty, "{Binding Name, Converter={StaticResource strConverter}}"
);
Label IDLabel = new Label();
IDLabel.SetBinding(
Label.TextProperty, "{Binding Path=ID, Converter={StaticResource guidConverter}}"
);
return new ViewCell
{
View = new StackLayout
{
})
});
The "ItemTemplate" line throws up a "Cannot Convert Lambda expression to type 'System.Type' because it is not a Delegate Type"
In some other issues like this, it seems the solutions was to add a new action(() => {}) structure, but as this is a Xamarin approved method, I am not sure why I would need to implement this?
Thanks!
EDIT: With the addition of the top func line, I now get an error raised on that line, Error CS1643: Not all code paths return a value in anonymous method of type 'System.Func<object>'
As you can see from the constructors of DataTemplate here, you need to either pass a Func<object> or a Type.
You need to return something inside your statement block in order for it to be converted to a Func<object>. Since you have no return statement, the lambda isn't converted and the compiler thinks you're trying to use the DataTemplate(Type) constructor with wrong parameters. I don't know why the C# compiler chooses this constructor - I would guess that it's the first one it finds.
The example on the documentation page for the ListView page which you linked works because it returns a new ViewCell:
// ...
ItemTemplate = new DataTemplate(() =>
{
// Create views with bindings for displaying each property.
Label nameLabel = new Label();
nameLabel.SetBinding(Label.TextProperty, "Name");
Label birthdayLabel = new Label();
birthdayLabel.SetBinding(Label.TextProperty,
new Binding("Birthday", BindingMode.OneWay,
null, null, "Born {0:d}"));
BoxView boxView = new BoxView();
boxView.SetBinding(BoxView.ColorProperty, "FavoriteColor");
// Return an assembled ViewCell. <<--------------------------------------
return new ViewCell
{
View = new StackLayout
{
Padding = new Thickness(0, 5),
Orientation = StackOrientation.Horizontal,
Children =
{
boxView,
new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Spacing = 0,
Children =
{
nameLabel,
birthdayLabel
}
}
}
}
};
})
// ...
EDIT: This is what I meant by put the lambda inside a new Func<object>(...):
ListView listView = new ListView
{
// Source of data items.
ItemsSource = devices,
ItemTemplate = new DataTemplate(new Func<object>(() =>
{
// Create views with bindings for displaying each property.
Label nameLabel = new Label();
nameLabel.SetBinding(
Label.TextProperty, "{Binding Name, Converter={StaticResource strConverter}}"
);
Label IDLabel = new Label();
IDLabel.SetBinding(
Label.TextProperty, "{Binding Path=ID, Converter={StaticResource guidConverter}}"
);
return new ViewCell
{
View = new StackLayout
};
}));
}

Changing and setting the Legend (LineGraph) Future of DynamicDataDisplay

I'm using this great library https://d3future.codeplex.com/ to plot some 2D graphs.
In the old D3 I used to set the legend this way:
graf = plotter.AddLineGraph(new CompositeDataSource(xSrc, plot),
new Pen(brush, 4),
new PenDescription("myText" ));
But I have no idea how to obtain the same in future D3. Could someone make me see the light?
Exploring the source code I find this but can't understand how to access and change the default string "LineGraph":
public class LineGraph : PointsGraphBase
{
static LineGraph()
{
Type thisType = typeof(LineGraph);
Legend.DescriptionProperty.OverrideMetadata(thisType, new FrameworkPropertyMetadata("LineGraph"));
Legend.LegendItemsBuilderProperty.OverrideMetadata(thisType, new FrameworkPropertyMetadata(new LegendItemsBuilder(DefaultLegendItemsBuilder)));
}
//more stuff
}
v0.4.0 uses the following syntax:
// For access to the Legend class
using Microsoft.Research.DynamicDataDisplay.Charts;
... snip ...
LineGraph lineGraph = new LineGraph(dataSource);
lineGraph.LinePen = new Pen(Brushed.Green, 1.0);
Legend.SetDescription(lineGraph, "The line label");
plotter.Children.Add(lineGraph);
... snip ...
v0.3.0 used the following syntax:
plotter.AddLineGraph(dataSource, pen, marker, new PenDescription("The line label"));
When you add line graph to the plotter (AddLineGraph(...)), one of the parameters is description string.
WGW is Spot On! Thumbs Up from me.
I found that doing it a slightly different way was easier to understand:
<Page
...
xmlns:d3="http://research.microsoft.com/DynamicDataDisplay/1.0"
... >
...
<Grid Name="GridOne" Grid.Column="0" Grid.Row="0" Margin="13" />
</Page>
And the Code Behind:
using Microsoft.Research.DynamicDataDisplay.Charts;
...
ChartPlotter PlotterOne = new ChartPlotter();
// Add a Graph to One:
GridOne.Children.Add(PlotterOne);
LineGraph line = new LineGraph();
line.ProvideVisiblePoints = true;
line.Stroke = Brushes.Blue;
line.StrokeThickness = 1;
line.DataSource = GetDayDataSource();
Legend.SetDescription(line, "Today's Activity");
PlotterOne.Children.Add(line);
Hope this helps.

Categories

Resources