Binding Data to UWP WinRT_XamlToolKit_Chart - c#

I am trying to load a chart from a DataTemplate in a UWP program using the WinRT_XamlToolkit_Chart library. I am Binding the Chart Title and Data using the {Binding Property} syntax, but it is not loading the property as a data member of the chart object. I have included both my XAML
<Charting:Chart HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="600"
Height="400"
DataContext="{Binding}"
Title="{Binding Title}">
<Charting:LineSeries Title="{Binding Title}"
Margin="0"
IndependentValuePath="Name"
DependentValuePath="Amount"
IsSelectionEnabled="True"
ItemsSource="{Binding Data}"
/>
</Charting:Chart>
c# Object
public class DataChartNode : ExperimentNode
{
public DataChartNode(String title, String type)
{
Type = type;
Title = title;
Category = "Data Analysis";
}
public DataChartNode(String type)
{
Type = type;
Category = "Data Analysis";
Name = type;
Title = "Hello";
Length = 0;
Data = new List<DataPoint>();
}
public DataChartNode() { }
public string Type { set; get; }
public string Title { set; get; }
public int Length { set; get; }
public List<DataPoint> Data { set; get; }
}

Since you didn't provide the DataPoint class and didn't show how you build the data source that you bind to the Chart control, I wrote a simple demo that created the data source code behind which can work well with your XAML code snippet you can reference.
XAML Code (Same with you)
<Charting:Chart
Title="{Binding Title}"
Width="600"
Height="400"
HorizontalAlignment="Center"
VerticalAlignment="Center"
DataContext="{Binding}">
<Charting:LineSeries
Title="Title"
Margin="0"
DependentValuePath="Amount"
IndependentValuePath="Name"
IsSelectionEnabled="True"
ItemsSource="{Binding Data}" />
</Charting:Chart>
Code behind
public sealed partial class MainPage : Page
{
private Random _random = new Random();
public MainPage()
{
this.InitializeComponent();
var data = new List<DataPoint>();
for (int i = 0; i < 3; i++)
{
data.Add(new DataPoint { Name = "Name" + i, Amount = _random.Next(10, 100) });
}
DataChartNode charnode = new DataChartNode()
{
Title = "Hello",
Data = data
};
this.DataContext = charnode;
}
}
public class DataChartNode
{
public string Type { set; get; }
public string Title { set; get; }
public int Length { set; get; }
public List<DataPoint> Data { set; get; }
}
public class DataPoint
{
public string Name { get; set; }
public int Amount { get; set; }
}
Please check your code behind to find if anything wrong with it.

Related

Why aren't my line showing up on my ItemsControl?

I'm attaching an ObservableCollection to it filled with a class I created. The ObservableCollection begins empty but is filled once the file is loaded. I've checked and it's properly loading the CanvasStart and CanvasEnd values. As far as I was aware the ItemsControl should be updating itself when the points are added to the ObservableCollection. See below:
my CanvasLine class:
public class CanvasLine
{
public Point DxfStart { get; set; }
public Point DxfEnd { get; set; }
public Point CanvasStart { get; set; }
public Point CanvasEnd { get; set; }
public string Layer { get; set; }
public List<double> Extents { get; set; }
public double Scale { get; set; }
public double CanvasWidth { get; set; }
public double CanvasHeight { get; set; }
public CanvasLine(Point dxfStart, Point dxfEnd, string layer)
{
DxfStart= dxfStart;
DxfEnd= dxfEnd;
Layer = layer;
}
public void GetCanvasLines(List<double> extents, double canvasWidth, double canvasHeight)
{
Extents = extents;
CanvasWidth = canvasWidth;
CanvasHeight = canvasHeight;
CanvasStart = DXFToCanvas.DXFCoordToCanvas(DxfStart, Extents, CanvasWidth, CanvasHeight);
CanvasEnd = DXFToCanvas.DXFCoordToCanvas(DxfEnd, Extents, CanvasWidth, CanvasHeight);
}
public partial class MainPage : Page
{
private List<double> extents;
private double scale;
private ObservableCollection<CanvasLine> canvasLines = new ObservableCollection<CanvasLine>();
public List<double> Extents
{
get { return extents; }
set
{
extents = value;
}
}
public double Scale
{
get { return scale; }
set { scale = value; }
}
public ObservableCollection<CanvasLine> CanvasLines
{
get { return canvasLines; }
set
{
canvasLines = value;
}
}
public MainPage()
{
InitializeComponent();
DataContext = this;
}
public void LoadCanvasDXF()
{
extents = LoadDXF.LoadExtents(Globals.CAD_FILE_PATH);
scale = LoadDXF.GetScale(extents, MainPageCanvas.Height, MainPageCanvas.Width);
foreach (CanvasLine canvasLine in Globals.LINE_LIST)
{
canvasLine.GetCanvasLines(Extents, MainPageCanvas.Width, MainPageCanvas.Height);
CanvasLines.Add(canvasLine);
}
}
}
XAML for the ItemsControl:
<ItemsControl ItemsSource="{Binding CanvasLines}" x:Name="MainPageCanvas" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Width="600" Height="300">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White" Width="600" Height="300"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Line X1="{Binding CanvasStart.X}" Y1="{Binding CanvasStart.Y}"
X2="{Binding CanvasStart.X}" Y2="{Binding CanvasStart.Y}"
Stroke="Black" StrokeThickness="3"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Here is an example of a few of the lines start and end:
CanvasStart: 428.88814432501835, 266.5502781209483 CanvasEnd: 349.5791140550308, 266.5502781209483
CanvasStart: 349.5791140550308, 268.2016894748275 CanvasEnd: 428.88814432501835, 268.2016894748275
CanvasStart: 272.29306269353776, 268.2016894748275 CanvasEnd: 341.6523395564147, 268.2016894748275
CanvasStart: 341.6523395564147, 266.5502781209483 CanvasEnd: 272.29306269353776, 266.5502781209483
I tried binding the collection to my ItemsControl but it isn't working.

ViewModel binding to a hierarchical TreeView to the selected value

I am trying to implement a countries list as per this link. Basically it has a id:country with 3 levels of data.
I have the tree view displaying as required using this class:
using System.Collections.ObjectModel;
namespace ckd.Library
{
/// <summary>
/// implementation of the hierarchical data from the ABS SACC 2016
/// #link https://www.abs.gov.au/statistics/classifications/standard-australian-classification-countries-sacc/latest-release
/// </summary>
public static class Sacc2016
{
public static ObservableCollection<MajorGroup> Countries { get; set; }
static Sacc2016()
{
Countries = new ObservableCollection<MajorGroup>();
var majorGroup1 = new MajorGroup(1, "OCEANIA AND ANTARCTICA");
var minorGroup11 = new MinorGroup(11, "Australia (includes External Territories)");
var minorGroup12 = new MinorGroup(12, "New Zealand");
var minorGroup13 = new MinorGroup(13, "Melanesia");
minorGroup11.Countries.Add(new Country(1101, "Australia"));
minorGroup11.Countries.Add(new Country(1102, "Norfolk Island"));
minorGroup11.Countries.Add(new Country(1199, "Australian External Territories, nec"));
minorGroup12.Countries.Add(new Country(1201, "New Zealand"));
minorGroup13.Countries.Add(new Country(1301, "New Caledonia"));
Countries.Add(majorGroup1);
}
}
public class MajorGroup
{
public MajorGroup(int id, string name)
{
Id = id;
Name = name;
MinorGroups = new ObservableCollection<MinorGroup>();
}
public int Id { get; set; }
public string Name { get; set; }
public ObservableCollection<MinorGroup> MinorGroups { get; set; }
}
public class MinorGroup
{
public MinorGroup(int id, string name)
{
Id = id;
Name = name;
Countries = new ObservableCollection<Country>();
}
public int Id { get; set; }
public string Name { get; set; }
public ObservableCollection<Country> Countries { get; set; }
}
public class Country
{
public Country(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
}
}
My ViewModel implements INotifyPropertyChanged and in part is:
private int? _CountryOfBirth;
public int? CountryOfBirth
{
get => _CountryOfBirth;
set => SetProperty(ref _CountryOfBirth, value);
}
public ObservableCollection<MajorGroup> CountriesObservableCollection { get; private set; }
void ViewModelConstructor(){
...
CountriesObservableCollection = Sacc2016.Countries;
...
}
Finally, the xaml section is:
<TreeView x:Name="CountriesTreeView" HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch"
ItemsSource="{Binding CountriesObservableCollection}"
SelectedValue="{Binding CountryOfBirth, Mode=OneWayToSource }"
SelectedValuePath="Id"
>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding MinorGroups}" DataType="{x:Type library:MajorGroup}">
<Label Content="{Binding Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Countries}" DataType="{x:Type library:MinorGroup}">
<Label Content="{Binding Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="{x:Type library:Country}">
<Label Content="{Binding Name}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
this xaml gives the error: View.xaml(260, 23): [MC3065] 'SelectedValue' property is read-only and cannot be set from markup. Line 260 Position 23.
removing the selectedValue shows:
so my question is, how can I link the Id field (from MajorGroup, MinorGroup and Country) to the CountryOfBirth property in my viewmodel?
There exist many solutions. One simple MVVM ready solution is to handle the TreeView.SelectedItemChanged event to set a local dependency property which you can bind to the view model class:
MainWindow.xaml.cs
partial class MainWindow : Window
{
public static readonly DependencyProperty SelectedTreeItemProperty = DependencyProperty.Register(
"SelectedTreeItem",
typeof(object),
typeof(MainWindow),
new PropertyMetadata(default));
public object SelectedTreeItem
{
get => (object)GetValue(SelectedTreeItemProperty);
set => SetValue(SelectedTreeItemProperty, value);
}
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var treeView = sender as TreeView;
this.SelectedTreeItem = treeView.SelectedItem;
}
}
MainWindow.xaml
<Window>
<Window.Resources>
<Style TargetType="local:MainWindow">
<Setter Property="SelectedTreeItem"
Value="{Binding SelectedDataModel, Mode=OneWayToSource}" />
</Style>
</Window.Resources>
<TreeView SelectedItemChanged="TreeView_SelectedItemChanged" />
</Window>
MainViewModel.cs
class MainViewModel : INotifyPropertyChanged
{
public object SelectedDataModel { get; set; }
}
Alternatively, you can also move the logic from the MainWindow.xaml.cs to an attached behavior.

Bind UserControl Property to ViewModel

I have an UserContol Combination of Country Code Combobox and A number Textbox.
In my Window, I have 2 UserControl (Primary Phone Number and Secondary Phone Number)
Here is my Model
public class ContactNumber
{
public Country Country { get; set; }
public string Number { get; set; }
}
public class Country
{
public int id { get; set; }
public string name { get; set; }
public string code { get; set; }
public string phone_code { get; set; }
public int is_active { get; set; }
public List<Country> country { get; set; }
}
Here is My UserControl XAML
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="250"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!--ComboBox for Country-->
<ComboBox Grid.Column="0" Style="{StaticResource ComboBoxMerged}" x:Name="cmbCountry"></ComboBox>
<TextBlock Text="|" FontSize="{StaticResource fontSize30}" Foreground="{StaticResource LightSilverBrush}"
HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="1" Margin="0,-5,0,0">
</TextBlock>
<!--TextBox for Number-->
<TextBox Style="{StaticResource TextBoxWithDropDown}"
Text="{Binding ContactNumber.Number,ElementName=ContactWindow,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
x:Name="txtContactNumber" TextChanged="txtContactNumber_TextChanged" Width="240" Grid.Column="2">
</TextBox>
</Grid>
Here is my Control Code Behind
public ContactNumber ContactNumber
{
get { return (ContactNumber)GetValue(ContactNumberProperty); }
set
{
SetValue(ContactNumberProperty, value);
}
}
// Using a DependencyProperty as the backing store for ContactNumber. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ContactNumberProperty =
DependencyProperty.Register("ContactNumber", typeof(ContactNumber), typeof(ContactNumberWithCountryCode),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
SetText));
private static void SetText(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ContactNumberWithCountryCode contactNumberWithCountryCode=d as ContactNumberWithCountryCode;
if (contactNumberWithCountryCode!=null)
{
contactNumberWithCountryCode.txtContactNumber.Text = (e.NewValue as ContactNumber).Number.ToString();
}
}
public ContactNumberWithCountryCode()
{
InitializeComponent();
}
private void txtContactNumber_TextChanged(object sender, TextChangedEventArgs e)
{
ContactNumber.Number = txtContactNumber.Text;
}
This is my Main Window XAMl
<usercontrols:ContactNumberWithCountryCode ContactNumber="{Binding PrimaryContactNumber,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" x:Name="PracticePhoneNumber" Margin="0,15,0,0" ></usercontrols:ContactNumberWithCountryCode>
<usercontrols:ContactNumberWithCountryCode ContactNumber="{Binding SecondryContactNumber,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" x:Name="SecondaryPracticePhoneNumber" Margin="0,15,0,0" ></usercontrols:ContactNumberWithCountryCode>
Here is my View Model Code
private ContactNumber primaryContactNumber;
public ContactNumber PrimaryContactNumber
{
get { return primaryContactNumber; }
set
{
primaryContactNumber = value;
OnPropertyChanged("PrimaryContactNumber");
}
}
private ContactNumber secondryContactNumber;
public ContactNumber SecondryContactNumber
{
get { return secondryContactNumber; }
set
{
secondryContactNumber = value;
OnPropertyChanged("SecondryContactNumber");
}
}
My goal is to fill ViewModel Property on Text Or Combobox Value Change.
Thanks in Advance.

Datagrid image TemplateColumn source binding wpf

i'm using a Datagrid to display users information, every thing is working fine for text columns ,except the column I want to display user image,
here is the Datagrid in xaml
<DataGrid Name="UserListDataGrid" Margin="10,50,10,10"
AutoGenerateColumns="False"
EnableRowVirtualization="False"
ItemsSource="{Binding convUsrList}"
CellStyle="{StaticResource Body_Content_DataGrid_Centering}"
RowDetailsVisibilityMode="VisibleWhenSelected"
CanUserSortColumns="False"
CanUserAddRows="False"
CanUserResizeRows="False"
CanUserReorderColumns="False"
IsReadOnly="True"
Width="900"
Opacity="0"
Foreground="Black"
GridLinesVisibility="None"
HeadersVisibility="All"
HorizontalContentAlignment="Center"
Background="Gray"
BorderBrush="Transparent"
ScrollViewer.HorizontalScrollBarVisibility="Auto" >
<DataGrid.Columns>
<DataGridTemplateColumn >
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<Image Source="{Binding PhotoSource}" Width="60" Height="60" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataContext[10],RelativeSource={RelativeSource AncestorType=DataGrid}}" Width="60"/>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding FirstName}" >
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataContext[4],RelativeSource={RelativeSource AncestorType=DataGrid}}" Width="60"/>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>....
I get the user photo from my DB in base64 string format, convert to BitmapImage using this function
public static BitmapImage getImage(string image)
{
byte[] b = Convert.FromBase64String(image);
MemoryStream mst = new MemoryStream(b, 0, b.Length);
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.StreamSource = mst;
bmp.EndInit();
return bmp;
}
and finally create a list of user (which is a class presenting user information such as firstname (string) //lastname(string)// ...//PhotoSource (BitmapImage) ) and feed it to data grid as follows
UserListDataGrid.ItemsSource = convUsrList;
as I said everything is showing on the Datagrid except user image would you please help me ?
this is the user class:
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public bool IsActive { get; set; }
public int UserTypeId { get; set; }
public int ShopId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
public string CellNumber { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public bool Gender { get; set; }
public string Photo { get; set; }
public string SecurityAnswer { get; set; }
public int SecurityQuestionId { get; set; }
public long LastSecurityCheck { get; set; }
public DateTime? DeletedAt { get; set; }
public DateTime? ExpireDate { get; set; }
}
public class UserDatagrid:User
{
public BitmapImage PhotoSource;
}
and here is how convUsrList is declared:
public void loadUserTable()
{
UserManagement um = new UserManagement(db);
List<User> userlist = um.getUserlist(um.GetUsers());
if (db.IsRTL)
UserListDataGrid.FlowDirection = FlowDirection.RightToLeft;
else
UserListDataGrid.FlowDirection = FlowDirection.LeftToRight;
string s = "";
dataBase.AppNotifyDic.TryGetValue("userTbl", out s);
string[] contbl = s.Split('-');
UserListDataGrid.DataContext = new List<string>() { contbl[0], contbl[1], contbl[2], contbl[3], contbl[4], contbl[5], contbl[6], contbl[7], contbl[8], contbl[9], contbl[10], contbl[11], contbl[12], contbl[13], contbl[14], contbl[15], contbl[16] };
List<UserDatagrid> convUsrList = new List<UserDatagrid>();
for (int i=0;i<userlist.Count;i++)
{
convUsrList.Add(tools.convertUserForDataGrid(userlist[i]));
}
UserListDataGrid.ItemsSource = convUsrList;
}
and the convertUserForDataGrid is as follow:
public static UserDatagrid convertUserForDataGrid(User origUser)
{
UserDatagrid convUser = new UserDatagrid();
convUser.Id = origUser.Id;
convUser.UserName = origUser.UserName;
convUser.Password = origUser.Password;
convUser.IsActive = origUser.IsActive;
convUser.UserTypeId = origUser.UserTypeId;
convUser.ShopId = origUser.ShopId;
convUser.FirstName = origUser.FirstName;
convUser.LastName = origUser.LastName;
convUser.PhoneNumber = origUser.PhoneNumber;
convUser.CellNumber = origUser.CellNumber;
convUser.Address = origUser.Address;
convUser.Email = origUser.Email;
convUser.Gender = origUser.Gender;
convUser.Photo = origUser.Photo;
convUser.SecurityAnswer = origUser.SecurityAnswer;
convUser.SecurityQuestionId = origUser.SecurityQuestionId;
convUser.LastSecurityCheck = origUser.LastSecurityCheck;
convUser.DeletedAt = origUser.DeletedAt;
convUser.ExpireDate = origUser.ExpireDate;
convUser.PhotoSource = (string.IsNullOrEmpty(origUser.Photo)) ? (convUser.Gender)? setImagesource("male.png"): setImagesource("Female.png") : getImage(origUser.Photo);
return convUser;
}
Because binding system uses Reflection to find the
Property in DataContext(i.e your VM)
Hope this will help.
credits:link1

Populate WPF listbox based on selection of another listbox

I have a listbox that is bound to an observablecollection. The observable collection contains a list of objects, each with it's own observablecollection. What i want is to click an item in the first listbox and have it's list of things displayed in the second listbox. Can I do this in pure WPF?
Just bind the ItemsSource of the second listbox to the SelectedItem of the first list box.
Edit: here is some code.
public partial class MainWindow : Window
{
public MainWindow()
{
TestItems = new ObservableCollection<Test>();
InitializeComponent();
for (int i = 0; i < 5; i++)
TestItems.Add(InitTest(i));
}
public ObservableCollection<Test> TestItems { get; set; }
private Test InitTest(int index)
{
Test test = new Test();
test.Name = "Test" + index.ToString();
test.Test2Items = new ObservableCollection<Test2>();
for (int i = 0; i <= index; i++)
{
Test2 test2 = new Test2();
test2.Label = test.Name + "_label" + i.ToString();
test.Test2Items.Add(test2);
}
return test;
}
}
public class Test
{
public string Name { get; set; }
public ObservableCollection<Test2> Test2Items { get; set; }
public override string ToString()
{
return Name;
}
}
public class Test2
{
public string Label { get; set; }
public override string ToString()
{
return Label;
}
}
Xaml
<Window x:Class="WpfApplication1.MainWindow"
x:Name="MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF Example" Height="300" Width="400">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox x:Name="ListBox1" Grid.Column="0" ItemsSource="{Binding TestItems, ElementName=MyWindow}" />
<ListBox Grid.Column="1" ItemsSource="{Binding SelectedItem.Test2Items, ElementName=ListBox1}" />
</Grid>
</Window>
Your view models could look something like this: (I am using my BindableBase here)
class MainViewModel : Bindablebase {
public ObservableCollection<ItemViewModel> Items { get; private set; }
private ItemViewModel _selectedItem;
public ItemViewModel SelectedItem {
get { return _selectedItem; }
set { SetProperty(ref _selectedItem, value, "SelectedItem"); }
}
}
class ItemViewModel : BindableBase {
public ItemViewModel (string name) {
Name = name;
Items = new ObservableCollection<string>();
}
public string Name { get; private set; }
public ObservableCollection<string> Values { get; private set; }
private string _selectedValue;
public string SelectedValue {
get { return _selectedValue; }
set { SetProperty(ref _selectedValue, value, "SelectedValue"); }
}
}
And then your view would have:
<ComboBox ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"
DisplayMemberPath="Name"/>
<!--
Note that the DataContext here could be ommitted
and the bindings would be like {Binding SelectedItem.Values}
-->
<ComboBox DataContext="{Binding SelectedItem}"
ItemsSource="{Binding Values}"
SelectedItem="{Binding SelectedValue}"/>

Categories

Resources