Lining up multiple RadCartesianChart with DateTimeContinuousAxis - c#

I want all of my charts to line up using the DateTimeContinuousAxis. I have several values logged with a time stamp. I parse the file and store the values per time stamp. Now how can I create several charts that will line up as if it were to look like a timing diagram using Telerik RadChartView? Mind you, this all will need to be done pragmatically aside from any styles that are set.
Here are some things to consider:
when the VerticalAxis label has 4 characters (-900), vs. 2 characters (10), the vertical axis of all the charts aren't lined up
when I Hide the HorizontalAxis.Visibility it gets rid of the axis like I would like, but then the LineSeries extends all the way to the right of the grid, so they don't line up with the bottom-most chart's HorizontalAxis
Here is a screenshot of what I'm talking about (and actually I have the vertical axis label thing partially fixed in this screenshot, see the answer on how I did it):

First thing is first, you have add each of your charts to the grid. Here is what my XAML looks like for that:
<Grid Name="layout" />
Next I initialize and setup a couple (not all are shown) components inside of my loop--that iterates through the collection or values that I want to chart--that I will be adding to the Grid/Chart
LineSeries lineSeries = new LineSeries();
lineSeries.VerticalAxis = new LinearAxis()
{ //set additional properties here
LabelStyle = Resources["AdjustedLabelVerticalAxis"] as Style
};
lineSeries.ItemsSource = collection.Values;
lineSeries.CategoryBinding = new PropertyNameDataPointBinding() { PropertyName = "Date" };
lineSeries.ValueBinding = new PropertyNameDataPointBinding() { PropertyName = "Value" };
RadCartesianChart chart = new RadCartesianChart();
chart.HorizontalAxis = new DateTimeContinuousAxis() { LabelFormat = "HH:mm:ss" };
chart.Series.Add(lineSeries);
Then I "hack" my HorizontalAxis to disappear:
chart.HorizontalAxis.MajorTickStyle = Resources["HideTicksHorizontalAxis"] as Style;
chart.HorizontalAxis.LabelStyle = Resources["HideShiftHorizontalAxisLabel"] as Style;
chart.HorizontalAxis.LineThickness = 0;
Now we need to programmatically add the chart to the grid at the end of the loop, so each chart is in their own row, which helps for auto-resizing.
layout.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(chart.MinHeight, GridUnitType.Star) });
Next we set what row in the Grid we want to put the chart, and add it:
Grid.SetRow(chart, i); //where i is the loop counter
layout.Children.Add(chart);
When the loop is done, we have all our charts in the collection to the grid, with no horizontal axes labeling. We need an DateTimeContinousAxis, so lets get crafty.
We first need to add the very last row, because we are going to create another chart and populate the same data, but then hide and adjust everything.
So outside of my loop I did:
layout.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(30) }); //add last row
DateTimeContinuousAxis graph = new DateTimeContinuousAxis();
graph.MinHeight = 12;
graph.Maximum = collection.Values[collection.Values.Count - 1].Date; //max/min DateTime values
graph.Minimum = collection.Values[0].Date;
graph.LabelInterval = 2;
graph.MaximumTicks = 3;
graph.LabelFormat = "hh:mm:ss";
graph.MajorStepUnit = Telerik.Charting.TimeInterval.Second;
graph.LineThickness = 1;
Then go on to create a minimalist LinearAxis, LineSeries, and RadCartesianChart
LinearAxis axis = new LinearAxis();
LineSeries ls = new LineSeries();
RadCartesianChart blankChart = new RadCartesianChart();
ls.ItemsSource = collection.Values; //Set up for binding
ls.CategoryBinding = new PropertyNameDataPointBinding() { PropertyName = "Date" };
ls.ValueBinding = new PropertyNameDataPointBinding() { PropertyName = "Value" };
ls.Visibility = System.Windows.Visibility.Hidden; //hide the line from being plotted
axis.LabelStyle = Resources["TextBlockStyle2"] as Style;
axis.Opacity = 0; //make it invisible
axis.MinHeight = 0; //make it able to resize to 0 if ever needed
blankChart.MinHeight = 0;
blankChart.HorizontalAxis = graph;
blankChart.VerticalAxis = axis;
blankChart.Series.Add(ls);
Grid.SetRow(blankChart, collection.Count);
layout.Children.Add(blankChart);
There you have it, the last Grid in your window will contain just a visible DateTimeContinuous axis that will line up with your other charts. This is quite the hack, so its not the prettiest or revised. Below is the Styles that can be used in your XAML as well as the final result.
<Style x:Key="AdjustedLabelVerticalAxis" TargetType="{x:Type TextBlock}">
<Setter Property="Width" Value="30"/>
<Setter Property="Margin" Value="0,0,2,0"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="TextAlignment" Value="Right"/>
</Style>
<Style x:Key="HideShiftHorizontalAxisLabel" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="4,-15,4,0"/>
<Setter Property="Foreground" Value="Transparent"/>
</Style>
<Style x:Key="HideTicksHorizontalAxis" TargetType="{x:Type Rectangle}">
<Setter Property="Visibility" Value="Hidden"/>
</Style>
Any questions, please ask.

Related

Why is the Style not getting applied from code? [duplicate]

This question already has answers here:
How do you change Background for a Button MouseOver in WPF?
(6 answers)
Closed 12 months ago.
I'm trying to create a button from code and make the hover color change, for some reason the setters, etc are not getting applied. I'm pretty sure I'm either missing a step or it's something else but nothing changes, not even the color while not hovering. I'm not trying to make the button in XAML but create it in code and I know how to do it in XAML.
System.Windows.Controls.Button createPlaylist = new System.Windows.Controls.Button()
{
Height = 100,
Width = 100,
Margin = new Thickness(0,50,0,0)
};
// STYLE END //
var dt = new DataTemplate();
Style style = new Style(typeof(System.Windows.Controls.Button), createPlaylist.Style);
Trigger t = new Trigger();
t.Property = IsMouseOverProperty;
t.Value = true;
Setter setter = new Setter();
setter.Property = BackgroundProperty;
setter.Value = Brushes.Blue;
t.Setters.Add(setter);
Trigger s = new Trigger();
s.Property = IsMouseOverProperty;
s.Value = false;
Setter set = new Setter();
set.Property = BackgroundProperty;
set.Value = Brushes.Red;
s.Setters.Add(setter);
style.Triggers.Add(t);
createPlaylist.Style = style;
You have to manage the Background color of the Border within the Template of the Button, instead of just changing the Background property of the Button itself.
i.e. do the equivalent of this XAML:
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
Something like this on code behind:
Style buttonStyle = new Style();
FrameworkElementFactory contentBorder = new FrameworkElementFactory(typeof(Border));
contentBorder.AppendChild(new FrameworkElementFactory(typeof(ContentPresenter)));
contentBorder.SetBinding(Border.BackgroundProperty, new Binding { RelativeSource = RelativeSource.TemplatedParent, Path = new PropertyPath(nameof(Background)) });
ControlTemplate templateButton = new ControlTemplate(typeof(Button)) { VisualTree = contentBorder };
buttonStyle.Setters.Add(new Setter { Property = Button.TemplateProperty, Value = templateButton });
Trigger styleTrigger = new Trigger { Property = Button.IsMouseOverProperty, Value = true };
styleTrigger.Setters.Add(new Setter { Property = Button.BackgroundProperty, Value = Brushes.Blue });
buttonStyle.Triggers.Add(styleTrigger);
createPlaylist.Style = buttonStyle;

Changing specific wpf datagrid row color using c#

I have a requirement to change color of specific data grid row at run time
I am setting row background color inside Loading Row event of data grid
private void MessagesDataGrid_LoadingRow(objects , DataGridRowEventArgs e)
{
var v = e.Row.Item.ToString();
int i = e.Row.GetIndex();
if (IoStatusViewModel.HighlightSelected == true )
{
e.Row.Focusable = true;
e.Row.Background = Brushes.Red;
if (v.Contains("MCP :"))
{
DisplayLogs = IoStatusViewModel.ChangeMcpLog(v);
e.Row.Item = DisplayLogs;
}
}
else
{
if (v.Contains("MCP :"))
{
DisplayLogs = IoStatusViewModel.ChangeMcpLog(v);
e.Row.Item = DisplayLogs;
}
}
}
This code is working fine as data grid loads but after some times the color of each rows in data grid starts changing and as time passes whole grid becomes red
I would do it within the class object you are binding against in conjunction with a style for the grid. First, your data being presented in the grid. How/where is that coming from. Is it some sort of List<> or ObservableCollect<> of items. Example
var yourBoundProperty = new List<SomeClass>();
… populate however you do.
public class SomeClass
{
public string SomeProp {get; set;}
public string YourMCPField {get; set;}
// make a SPECIAL FIELD... could be boolean, number setting, whatever flag
// but in this case, I just have boolean
public bool FieldContainsMCP { get { return YourMCPFieldContains( "MCP :"); }}
}
Now, in your Xaml… assuming in a Window declaration.
<Window … >
<Window.Resources>
<Style TargetType="{x:Type DataGridCell}" x:Key="MyColorTriggers">
<Style.Triggers>
<DataTrigger Binding="{Binding FieldContainsMCP}" Value="True">
<Setter Property="Background" Value="Red" />
<Setter Property="ExampleAnyOtherProperty" Value="someOtherValue" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<DataGrid … other settings you have
CellStyle="{StaticResource MyColorTriggers}" >
.. rest of your data column declarations
</DataGrid>
</Window>
This way the actual data source is the flag basis which is applied to the CellStyle triggering regardless of where you may be scrolling through records.

Create "table style" ListView in UWP and XAML (C#)

I'm wondering if there is any way I can create a "table like" ListView in a UWP Windows 10 app? I need some sort of table where I can allow a user to browse and select files and then put the selected files into a list, sort of like a details view that you see in Windows explorer with column headers and rows that I can insert programmatically like:
string[] item = { "D:\\Music\\MyAudioFile.mp3", "MP3", "12MB" }
listview1.Items.Add(item);
Anyone have any ideas what I can use for this?
Thanks
Thanks Lindexi, that pointed me in the right direction... Here is the code I got working...
C# backend code:
// Create a new StackPanel to insert as a ListViewItem
StackPanel myStack = new StackPanel();
myStack.HorizontalAlignment = HorizontalAlignment.Stretch;
myStack.VerticalAlignment = VerticalAlignment.Stretch;
myStack.Orientation = Orientation.Horizontal;
// Create new StackPanel "Child" elements with alignment and width
ListViewItem lv1 = new ListViewItem();
lv1.Content = "Test Content";
lv1.Width = 400;
lv1.HorizontalAlignment = HorizontalAlignment.Stretch;
lv1.VerticalAlignment = VerticalAlignment.Stretch;
// Create new StackPanel "Child" elements with alignment and width
ListViewItem lv2 = new ListViewItem();
lv2.Content = "Test Content";
lv2.Width = 100;
lv2.HorizontalAlignment = HorizontalAlignment.Stretch;
lv2.VerticalAlignment = VerticalAlignment.Stretch;
// Create new StackPanel "Child" elements with alignment and width
ListViewItem lv3 = new ListViewItem();
lv3.Content = "Test Content";
lv3.Width = 100;
lv3.HorizontalAlignment = HorizontalAlignment.Stretch;
lv3.VerticalAlignment = VerticalAlignment.Stretch;
// Create new StackPanel "Child" elements with alignment and width
ListViewItem lv4 = new ListViewItem();
lv4.Content = "Test Content";
lv4.Width = 100;
lv4.HorizontalAlignment = HorizontalAlignment.Stretch;
lv4.VerticalAlignment = VerticalAlignment.Stretch;
// Create new StackPanel "Child" elements with alignment and width
ListViewItem lv5 = new ListViewItem();
lv5.Content = "Test Content";
lv5.Width = 250;
lv5.HorizontalAlignment = HorizontalAlignment.Stretch;
lv5.VerticalAlignment = VerticalAlignment.Stretch;
// Create new StackPanel "Child" elements with alignment and width
ListViewItem lv6 = new ListViewItem();
lv6.Content = "Test Content";
lv6.Width = 250;
lv6.HorizontalAlignment = HorizontalAlignment.Stretch;
lv6.VerticalAlignment = VerticalAlignment.Stretch;
// Add "Child" elements for the new StackPanel
myStack.Children.Add(lv1);
myStack.Children.Add(lv2);
myStack.Children.Add(lv3);
myStack.Children.Add(lv4);
myStack.Children.Add(lv5);
myStack.Children.Add(lv6);
// Add the new StackPanel as a ListViewItem control
MusicQueue.Items.Insert(1, myStack);
XAML Code:
<ListView Name="MusicQueue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListViewItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Horizontal">
<ListViewHeaderItem Width="400">Filename</ListViewHeaderItem>
<ListViewHeaderItem Width="100">Format</ListViewHeaderItem>
<ListViewHeaderItem Width="100">Size</ListViewHeaderItem>
<ListViewHeaderItem Width="100">Duration</ListViewHeaderItem>
<ListViewHeaderItem Width="250">Artist</ListViewHeaderItem>
<ListViewHeaderItem Width="250">Title</ListViewHeaderItem>
</StackPanel>
</ListViewItem>
</ListView>
Of course this is probably not going to be the most efficient way to manually add an item to a ListView stacked horizontally, but it works which is most important :)
If anyone does know a quicker way to do this with less code please let me know :)
Thanks guys
You can use dataGrid in UWP.
But you also can use DataTemplate in ListView, and you can use blow code to solve the width is too small.
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
The lib you can use is :https://github.com/MyToolkit/MyToolkit/wiki/DataGrid
And https://liftcodeplay.com/2015/10/24/datagrid-alternatives-in-uwp/
If you can spend money, you can use https://www.syncfusion.com/products/uwp/sfdatagrid

Hiding expander when all content is collapsed

I have A WPF Datagrid that has a Collection View Source with 3 levels of grouping on it.
I have styled the datagrid to use 3 expanders such that it looks like this:
Level 1 Expander
<content>
Level 2 Expander
<content>
Level 3 Expander
<content>
Level 2 and Level 1 are just title of the groups
I have a second control that allows the user to show and hide level 3 items which works by binding the Level 3 expander to a Boolean "IsVisible" property in the object behind.
<!-- Style for groups under the top level. this is the style for how a sample is displayed -->
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<!-- The parent control that determines whether or not an item needs to be displayed. This holds all of the sub controls displayed for a sample -->
<Expander Margin="2"
Background="{Binding Path=Name,
Converter={StaticResource SampleTypeToColourConverter}}"
IsExpanded="True"
Visibility="{Binding Path=Items[0].IsVisibleInMainScreen,
Converter={StaticResource BoolToVisibilityConverter}}">
This approach works fantasically well.
HOWEVER
If the user deselects all items in a level 3 expander, the Level 2 expander header still displays meaning that valuable real estate is used up showing the header of a group with no visible data.
What I would like is a way to bind the visibility of the level 2 expander to its child controls and say "If all children are visible then show the expander, otherwise collapse it"
Is this possible?
I found a rather simple and clean way, yet not perfect, to achieve your goal. This should do the trick if hou don't have too much groups.
I've just added this trigger to the GroupItem ControlTemplate :
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=IP, Path=ActualHeight}" Value="0">
<Setter Property="Visibility" Value="Hidden"/>
<Setter Property="Height" Value="1"/>
</DataTrigger>
</ControlTemplate.Triggers>
When the ItemsPresenter (IP) ActualSize drops to zero, it Will almost collapse the header.
Why almost ?
When the control gets initialized and before the binding occurs, the ItemPresenter ActualHeight is 0 and when Visibility is set to Collapsed, the ItemPresenter doesn't get rendered at all.
Using Visibility.Hidden allows the ItemsPresenter to go to the render phase and be mesured.
I succedeed to drop Height to .4 px but I suspect this to be device dependant.
Assuming that you are using an MVVM sort of style, you could bind instead to a property of your group object that returns false if all of the children are invisible:
public bool AreChildrenVisible { get { return _children.Any(x=>x.IsVisibleInMainScreen); } }
Alternatively, pass the collection of Items through a Converter class to return Visibility depending on the aggregate status of all the subItems in the group.
This isn't a direct answer as you would have to implement it specifically for your needs but previously I have used a an override of the Grid Control to create dynamic grid allocation of members, if there are no visible members it then hides the parent group box.
public class DynamicLayoutGrid : Grid
{
protected override void OnInitialized(EventArgs e)
{
//Hook up the loaded event (this is used because it fires after the visibility binding has occurred)
this.Loaded += new RoutedEventHandler(DynamicLayoutGrid_Loaded);
base.OnInitialized(e);
}
void DynamicLayoutGrid_Loaded(object sender, RoutedEventArgs e)
{
int numberOfColumns = ColumnDefinitions.Count;
int columnSpan = 0;
int rowNum = 0;
int columnNum = 0;
int visibleCount = 0;
foreach (UIElement child in Children)
{
//We only want to layout visible items in the grid
if (child.Visibility != Visibility.Visible)
{
continue;
}
else
{
visibleCount++;
}
//Get the column span of the element if it is not in column 0 as we might need to take this into account
columnSpan = Grid.GetColumnSpan(child);
//set the Grid row of the element
Grid.SetRow(child, rowNum);
//set the grid column of the element (and shift it along if the previous element on this row had a rowspan greater than 0
Grid.SetColumn(child, columnNum);
//If there isn't any columnspan then just move to the next column normally
if (columnSpan == 0)
{
columnSpan = 1;
}
//Move to the next available column
columnNum += columnSpan;
//Move to the next row and start the columns again
if (columnNum >= numberOfColumns)
{
rowNum++;
columnNum = 0;
}
}
if (visibleCount == 0)
{
if (this.Parent.GetType() == typeof(GroupBox))
{
(this.Parent as GroupBox).Visibility = Visibility.Collapsed;
}
}
}
}
Use IMultiValueConverter implementation to convert items to visibility.
If all items IsVisibleInMainScreen property return true the converter will return visible else hidden.
Use the converter in the same place U used to convert the first item in original example

My pushpins in bingmaps for WP7 are all black. Why?

I am trying to work with WP7 and Bingmaps.
I have this code
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<my:Map Height="389" HorizontalAlignment="Left" Margin="28,28,0,0" Name="map1" VerticalAlignment="Top" Width="409" />
</Grid>
and
public MapInfo()
{
InitializeComponent();
GeoCoordinate lHamburg = new GeoCoordinate(53.550556, 9.993333);
//map1.Radius = 5000;
map1.ZoomLevel = 10.0;
map1.Center = lHamburg;
map1.CredentialsProvider = new ApplicationIdCredentialsProvider(APPLICATION_ID);
//Add a pin to the map
Pushpin pushpin = new Pushpin();
Location location = new Location();
location.Latitude = 53.550556;
location.Longitude = 9.993333;
pushpin.Location = location;
map1.Children.Add(pushpin);
}
But my pushpin is black, without any style.
Did I forget something?
Thanks,
Oscar
Edit: it looks like that they ARE black. I would have to set some style to it or something like that. Anyone could give me some hints of how to add a simple style? Very simple, maybe only change the color, or make it round like google maps or something like that.
Thanks,
Oscar
You can use a style for example:
<Style TargetType="my:Pushpin">
<Setter Property="Background"
Value="White" />
</Style>
or directly set color while creating them:
//Add a pin to the map
Pushpin pushpin = new Pushpin();
Location location = new Location();
location.Latitude = 53.550556;
location.Longitude = 9.993333;
pushpin.Location = location;
pushpin.Background = new SolidColorBrush(Colors.Red);
map1.Children.Add(pushpin);
[NOTE: I used background property here. You may need to set different property/properties to change it's appearance to needed state.]
The following MSDN exercise will provide you with all the information that you need: Exercise 2: Handling and Customizing Pushpins. Scroll down to item 5 which is where the customizations of pushpins begins.

Categories

Resources