I wanna add to my tool a statistics window that will contain stacked bars chart.
I used for a similar application Modern UI (Metro) charts to create a single graph and it worked fine.
This Time, I need to show an unknown number of StackedBarChart and I'm having problems doing so.
I'd like your thoughts for a solution or a work-around
this is what my code for a single chart looks like (which works fine):
<chart:StackedBarChart Width="400" Height="400" ChartTitle="Statistics" ChartSubTitle="A single stacked bar">
<chart:StackedBarChart.Series>
<chart:ChartSeries
SeriesTitle="Y axis name"
DisplayMember="Name"
ValueMember="Number"
ItemsSource="{Binding SomeObservableCollectionOfNamesAndNumbers}"/>
</chart:StackedBarChart.Series>
</chart:StackedBarChart>
and what i want to do is something like this (using itemsSource):
<chart:StackedBarChart Width="400" Height="400" ChartTitle="Statistics" ChartSubTitle="Multiple stacked bars">
<chart:StackedBarChart.Series ItemsSource="{SomeObservableCollectionOfSomeObservableCollectionOfNamesAndNumbers}">
<chart:ChartSeries
SeriesTitle="{binding SomeObservableCollectionOfNamesAndNumbers.Name}"
DisplayMember="Name"
ValueMember="Number"
ItemsSource="{Binding SomeObservableCollectionOfNamesAndNumbers}"/>
</chart:StackedBarChart.Series>
</chart:StackedBarChart>
but unfortunately it is not possible, can you think of any other way?
you have to bind Series to your Observable Collection like this:
chart:StackedColumnChart ChartTitle="Statistics" ChartSubTitle="Multiple stacked bars" Series="{Binding Bars}">
</chart:StackedColumnChart>
You have to define your series in the Observable Collection (Bars in this case) in your Code Behind/ViewModel
ObservableCollection<TestClass> blocks = new ObservableCollection<TestClass>();
ChartSeries chartSerie = new ChartSeries();
chartSerie.SeriesTitle = "Some Title"
chartSerie.DisplayMember = "Category";
chartSerie.ValueMember = "Number";
Bars.Add(chartSerie);
chartSerie.ItemsSource = blocks;
blocks = new ObservableCollection<TestClass>();
Blocks are holding the single stacks and a ChartSerie is one whole Bar.
The TestClass holds your values and looks like this:
public class TestClass
{
public string Category { get; set; }
public int Number { get; set; }
}
Feel free to ask, if you need any further information.
Related
I have a app that retrieves comments from a website. I can programmatically add them to a StackPanel, calulating their indentation for comment replies but I'd like to learn how to bind a list of comments to a ListView and have it display correctly there.
My Comment Class looks like this:
class Comment
{
public List<Comment> Replies { get; set; }
public string Body { get; }
public int Level { get; set; }
public Comment(string BodyText)
{
Body = BodyText;
}
public Comment(string BodyText, List<Comment> replies, int level)
{
Body = BodyText;
Replies = replies;
Level = level;
}
}
So each Comment can have a List<> of comments (replies) to it and the Level variable indicates the depth of the comment.
What would be the process to set up a ListView so that I can bind a list of comments to it and those comments replies to those and so on? Or is there a better way to do this?
Thank you.
This is how I currently have it implemented which is visually correct but I'd like to use data binding rather than doing it through code.
Create a ListView, bind it's ItemsSource property to the list of top level comments. Use an ItemTemplate that contains the comment and another ListView in a vertical StackPanel. That inner ListView needs to get the same ItemTemplate it is in. I'm not sure if {StaticResource} will handle that, but it should.
If you use ObservableCollections this will actually be dynamic.
I recommend you to use the third party package WinRTXamlToolkit. Which contains a TreeView control that can meet your hierarchy requirements well. You can just bind the comments collection to the TreeView control code behind. Code example as follows:
Xaml Code
<controls:TreeView Width="400" MaxHeight="400" x:Name="Treeviewcomment">
<controls:TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Body}"/>
<data:DataTemplateExtensions.Hierarchy>
<data:HierarchicalDataTemplate ItemsSource="{Binding Replies}" />
</data:DataTemplateExtensions.Hierarchy>
</DataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
Binding code
this.InitializeComponent();
ObservableCollection<Comment> comments = new ObservableCollection<Comment>
{
new Comment ("By the way,I have noticed that ..."),
new Comment("Has this been metioned anywhere before..",
new List<Comment>
{
new Comment("Delta upgrade..."),
new Comment("When only stuff that...",
new List<Comment> {
new Comment("That's blloby...")},
3)},
2),
new Comment("Just had to turn off..")
};
And the result:
Special nuget package for uwp: WinRT XAML Toolkit. And I also upload the above code example to GitHub.
Okay, i feel slightly dumb for askin this but, I have a listview with a templated class MyClass or whatever, whenever i "myListView.Add(new MyClass())" the winrt platform adds a new UIElement there and binds the proper properties into their proper uielements properly, now, I want to be able to iterate through these logical items (myListView.Items or myListView.SelectedItems) and get their corresponding UIElement for animation, is that possible?
like for example
class PhoneBookEntry {
public String Name { get;set }
public String Phone { get;set }
public PhoneBookEntry(String name, String phone) {
Name = name; Phone = phone;
}
};
myListView.Add(new PhoneBookEntry("Schwarzeneger", "123412341234");
myListView.Add(new PhoneBookEntry("Stallone", "432143214321");
myListView.Add(new PhoneBookEntry("Statham", "567856785678");
myListView.Add(new PhoneBookEntry("Norris", "666666666666");
And in XAML (just an example so i can explain what I mean)
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Phone}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
So, my point and objective here is to
foreach(PhoneBookEntry pbe in myListView.Items) // or SelectedItems
{
UIElement el; // How can I get the UIElement associated to this PhoneBookEntry pbe?
if(el.Projection == null)
el.Projection = new PlaneProjection;
PlaneProjection pp = el.Projection as PlaneProjection;
// Animation code goes here.
if(myListView.SelectedItems.Contains(pbe)
//something for selected
else
//something for not selected
}
I just need a way to get an UIElement which is being used to represent this logical data class PhoneBookEntry in the templated listview.
Also, this necessity comes with a very big problem I'm having where, selected items doesn't differ visually on Windows Phone -_- any ideas?
You can also use the ListView.ContainerFromItem or ListView.ContainerFromIndex methods which will return the container UI element for a given item in the list view (of course, only if the container is generated)
Ok I may look like a fool answering my own question but i've figured a way out.
First things first: ListViews only create UIElements for determinate items in the list (the ones cached and the ones being shown). So if you do add 2000 items to myListView.Items, the effective ammount of UIElements representing these items will be 56 or close number.
Because, the ItemListView simulates the UIElements even if they're not there, just to give size and position to the scrollbar (hence why scrolling down on very large lists cause some lag, WinRT is unloading UIElements and loading new ones)
From that, I figured out I could simply iterate through the current list of loaded UIElements through
// For each of the cached elements
foreach(LIstViewItem lvi in myListView.ItemsPanelRoot.Children)
{
// Inside here I can get the base object used to fill the data template using:
PhoneBookEntry pbe = lvi.Content as PhoneBookEntry;
if(pbe.Name == "Norris")
BeAfraid();
// Or check if this ListViewItem is or not selected:
bool isLviSelected = lvi.IsSelected;
// Or, like I wanted to, get an UIElement to animate projection
UIElement el = lvi as UIElement;
if(el.Projection == null)
el.Projection = new PlaneProjection();
PlaneProjection pp = el.Projection as PlaneProjection;
// Now I can use pp to rotate, move and whatever with this UIElement.
}
So, this is it. Right beneath my nose...
In my program I would like to implement a DynamicResource from code-behind. Right now I am binding the Content of a Label to a string property in my Data Model...
<Label Content="{Binding DataModel.StringValue}" ... />
Following this question, I have implemented the string in my Data Model like so:
private string _stringValue = (string)Application.Current.Resources["nameOfResource"];
public string StringValue
{
get { return _cartsInSystem; }
set
{
_cartsInSystem = value;
NotifyPropertyChange(() => CartsInSystem);
}
}
I would like to make it so that every time the user changes the Resource Dictionary, this string value updates with the new value.
I am trying to achieve the same effect as something like this:
<Label Content="{DynamicResource nameOfResource}" ... />
Please let me know what I am doing wrong, and how I might correctly implement something like this.
UPDATE 1: As requested by #HighCore, this is an example of my code where I only have access to string values from code-Behind (or C# class)
(This is part of a ViewModel of a TreeView in my MainWindow)
//The "DisplayNames" for these nodes are created here and not accessible through xaml.
//This is because the xaml window has access to this code through it's itemsSource
private HierarchicalVM CreateCartsNode()
{
return new HierarchicalVM()
{
DisplayName = "Carts",
Children =
{
new CartConnection() { ConnectionDataModel = new CartConnectionModel(), DisplayName = "Cart Connection" },
new HierarchicalVM() {
DisplayName = "Cart Types",
Children = {
CreateCartType( new CartConfigModel() { DisplayName = "Default" }, new CartIO_Model() ),
},
Commands = { new Command(OpenAddCart) {DisplayName = "Add..."} }
}
}
};
}
This is the xaml of the above TreeView:
<!-- Tree view items & Functions -->
<TreeView ItemsSource="{Binding DataTree.Data}" ... />
Update 2: I have another perfect example of my problem...
I have a comboBox that has it's itemsSource bound to an ObservableCollection in my Data Model. Like so:
private ObservableCollection<string> _objCollection;
private string _notUsed = "Not Used";
private string _stop = "Stop";
private string _slow = "Slow";
public DataModel()
{
ObjCollection = new ObservableCollection<string>() { _notUsed, _stop, _slow };
}
public ObservableCollection<string> ObjCollection {...}
xaml:
<ComboBox ItemsSource="{Binding DataModel.ObjCollection}" ... />
If I want to make it so that the items in this comboBox change when the resource dictionary is changed, it looks like I'll need to handle it in C# rather than xaml.
After OP's UPDATE 2 and having a chat with him for a different question, I understood he was trying achieve localisation for his application. He would change Resource Dictionaries (for different languages) on the fly, and he wanted his C# code re-read/load values from Application.Current.Resources.
APPROACH ONE
After you changing the Resource Dictionary, You could use something like EventAggregator/Mediator to let other parts of the application (including ViewModels) know about Resource Dictionary change, and they respond to it by re-loading/reading resources/values from Application.Current.Resources
APPROACH TWO
OP doesn't want to introduce any new dependencies like EventAggregator/Mediator. So, I suggested this second approach. I know, it is not pretty, but here it goes..
You could have a global static event instead of EventAggregator/Mediaotr to let other parts of the application know that you swapped resource dictionary, and they will re-load/read values.
Read this answer about potential problems with static events and their subscriptions.
I've started to learn about GridView (XAML) for Windows 8 Store apps. I've used the ItemsPage example to try and have a look at the code.
My aim is use it as a horizontal menu, on the click event it will simply open another xaml page.
I've edited the SampleDataSource.cs file and filled up with the wanted content, i thought that there would be an easier, cleaner way of doing this. This Menu won't be dynamic and won't change so i'm looking for a way to statically add the menu items.
I can do the following to add a simple text entry;
<x:String>Item 1</x:String>
But i have i'm not sure how to bind to certain parts, such as the image and title elements
Right, i think i'm understanding this a little bit more. The following code would try and bind to itemsViewSource
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Items}"
d:Source="{Binding AllGroups, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"/>
So would i need to create a new list, such as;
List<String> itemsList = new List<string>();
itemsList.Add("Item 1");
itemsList.Add("Item 2");
Only issue is that each item (line) would need a Title and Image text field and how to bind those to the correct items.
If your ItemsControl (GridView) needs to display more than one bound item for each list item - you need to bind its Source to a list of something more than a string unless you want to parse the strings. In your case you would have something like
List<TitleAndImageText> itemsList = new List<TitleAndImageText>();
itemsList.Add(new TitleAndImageText { Title = "Title 1", ImageText = "Image Text 1");
itemsList.Add(new TitleAndImageText { Title = "Title 2", ImageText = "Image Text 2");
Then in your ItemTemplate/DataTemplate you would have two TextBlocks - that bind to the properties of your item view model like this: Text="{Binding Title}", Text="{Binding ImageText}".
Of course you need to define your TitleAndImageText, e.g.
public class TitleAndImageText
{
public string Title { get; set; }
public string ImageText { get; set; }
}
I avoided to ask this question, but the ListBox's selected index can no be set. I have read the other threads and applied the settings, but it doesn't work.
<ListBox ItemsSource="{Binding}"
HorizontalAlignment="Right"
Name="lstReading" Height="Auto"
SelectedIndex="{Binding BookmarkSelectedIndex}">
In the something.xaml.cs, I am settings
lstReading.DataContext = IQText;
Where, IQText is an IEnumerable<dictIQ> and includes the BookmarkSelectedIndex as data element. Other data elements from IQText can be used but the listindex can't be set. Could someone please let me know why?
Are you have BookmarkSelectedIndex inside of dictIQ class? So, you have one BookmarkSelectedIndex per item, not per collection!
You can create separate property BookmarkSelectedIndex outside of dictIQ or create class that inherited from ObservalbeCollection<dictIQ> and have additional property BookmarkSelectedIndex:
public class CollectionWithIndex: ObservalbeCollection<dictIQ>
{
public int BookmarkSelectedIndex { get; set; }
}
I hope you choose best solution suitable for you
use this code for select item at runtime...
List<Audio> lst = Audio.GetAudioFiles();
Audio aufile = new Audio { FileDisplayName = "Select Audio File" };
lst.Insert(0, aufile);
lstPickAudio.ItemsSource = lst;
string FileDisplayName="your condition"
lstPickAudio.SelectedItem = lst.Where(p => p.FileName == FileDisplayName).First();