Hi,
I am trying to implement a RadCartesianChart3D, but am missing the SeriesProvider Property to be able to bind view models and dynamically create series.. The Telerik package reference is Telerik.UI.for.WPF.NetCore.Xaml (2021.2.615). Was this property not implemented at that time? If so, how do I overcome this?
Example of what Id like to implement:
<telerik:RadCartesianChart3D x:Name="chart">
<!--...-->
<telerik:RadCartesianChart3D.SeriesProvider>
<telerik:ChartSeriesProvider3D Source="{Binding SeriesData}">
<telerik:XyzSeries3DDescriptor XValuePath="Year" YValuePath="Industry" ZValuePath="Revenue" ItemsSourcePath="Data">
<telerik:XyzSeries3DDescriptor.Style>
<Style TargetType="telerik:BarSeries3D" BasedOn="{StaticResource BarSeries3DStyle}" />
</telerik:XyzSeries3DDescriptor.Style>
</telerik:XyzSeries3DDescriptor>
</telerik:ChartSeriesProvider3D>
</telerik:RadCartesianChart3D.SeriesProvider>
</telerik:RadCartesianChart3D>
Edit: This feature seems to have been implemented in WPF R2 2022 and I do not have the option to upgrade the Telerik package. Is there a workaround for this?
Thanks in advance,
Chris
In my WPF application using c#, I need a count of DataPoints of a series of particular RadCartesianChart using c# (code behind). How can I achieve it?
I have used the following line:
int a = ((Telerik.Windows.Controls.ChartView.CategoricalSeries)new System.Collections.Generic.Mscorlib_CollectionDebugView<CartesianSeries>(((Telerik.Windows.Controls.RadCartesianChart)my SelectedChart).Series).Items[0]).DataPoints.Count;
But it gives the following error:
Error CS0122 'Mscorlib_CollectionDebugView<T>' is inaccessible due to its protection level
Hi,
I'm working with ChartView3D and Telerik UI for a project. I am using the XAML tags for the graph. I can build and compile the graph. During runtime, when I change the view angles of the graph and rotate, zoom it frequently the axes gets updated with the graph by a small delay. Sometime the axes get stuck. I have attached the screenshot for reference.
The code below is used to create the 3D graph,
<telerik:RadCartesianChart3D x:Name="E3DChart" Visibility="Collapsed">
<telerik:RadCartesianChart3D.XAxis>
<telerik:CategoricalAxis3D Title="Position">
<telerik:CategoricalAxis3D.TitleTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="White" Padding="3" FontSize="20" />
</DataTemplate>
</telerik:CategoricalAxis3D.TitleTemplate>
<telerik:CategoricalAxis3D.LabelStyle>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#FFD4D4D4" />
</Style>
</telerik:CategoricalAxis3D.LabelStyle>
</telerik:CategoricalAxis3D>
</telerik:RadCartesianChart3D.XAxis>
<telerik:RadCartesianChart3D.YAxis>
<telerik:CategoricalAxis3D Title="Tube">
<telerik:CategoricalAxis3D.TitleTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="White" Padding="3" FontSize="20"/>
</DataTemplate>
</telerik:CategoricalAxis3D.TitleTemplate>
<telerik:CategoricalAxis3D.LabelStyle>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#FFD4D4D4" />
</Style>
</telerik:CategoricalAxis3D.LabelStyle>
</telerik:CategoricalAxis3D>
</telerik:RadCartesianChart3D.YAxis>
<telerik:RadCartesianChart3D.ZAxis>
<telerik:LinearAxis3D Title="Count">
<telerik:LinearAxis3D.TitleTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="White" Padding="3" FontSize="20"/>
</DataTemplate>
</telerik:LinearAxis3D.TitleTemplate>
<telerik:LinearAxis3D.LabelStyle>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#FFD4D4D4" />
</Style>
</telerik:LinearAxis3D.LabelStyle>
</telerik:LinearAxis3D>
</telerik:RadCartesianChart3D.ZAxis>
<telerik:RadCartesianChart3D.Behaviors>
<telerik:Chart3DCameraBehavior Distance="2500"
FirstAngle="225"
SecondAngle="85"/>
<telerik:Chart3DTooltipBehavior ShowDuration="10000"/>
</telerik:RadCartesianChart3D.Behaviors>
<telerik:RadCartesianChart3D.Grid>
<telerik:CartesianChart3DGrid GridLineThickness="3"/>
</telerik:RadCartesianChart3D.Grid>
</telerik:RadCartesianChart3D>
I was surprised to find that assigning a foreground color to a LinearAxis3D does not automatically make the axis line, title or labels take on that color. That was the behavior I would expect. But it does not.
Ok, no problem, I figured I would get around it by defining a style resource for LinearAxis3D that individually binds the color to its logical children to the parent LinearAxis3D. So I did that and it works just fine for the text title and labels. But it does not work for the axis line
Are a LinearAxis3D object's axis lines not logical children of that axis? And if not, is there any way to generically find the LinearAxis3D object for (binding purposes) from within the style?
To illustrate, here's a the Z axis on my chart. (I've nested the style here for simplicity but in my app it needs to be a separate static resource for re-use.)
<
tk:RadCartesianChart3D.ZAxis
>
<
tk:LinearAxis3D
x:Name
=
"ZAxis"
LabelFormat
=
"0.00"
SmartLabelsMode
=
"SmartStep"
Minimum
=
"{Binding ZAxisMin}"
Maximum
=
"{Binding ZAxisMax}"
Foreground
=
"Yellow"
>
<
tk:LinearAxis3D.Style
>
<
Style
TargetType
=
"{x:Type tk:LinearAxis3D}"
>
<
Setter
Property
=
"LabelStyle"
>
<
Setter.Value
>
<
Style
TargetType
=
"{x:Type TextBlock}"
>
<
Setter
Property
=
"Foreground"
Value
=
"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:LinearAxis3D}}, Path=Foreground}"
/>
</
Style
>
</
Setter.Value
>
</
Setter
>
<
Setter
Property
=
"LineStyle"
>
<
Setter.Value
>
<
Style
TargetType
=
"{x:Type Path}"
>
<
Setter
Property
=
"Stroke"
Value
=
"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:LinearAxis3D}}, Path=Foreground}"
/>
<
Setter
Property
=
"StrokeThickness"
Value
=
"2"
/>
</
Style
>
</
Setter.Value
>
</
Setter
>
</
Style
>
</
tk:LinearAxis3D.Style
>
</
tk:LinearAxis3D
>
</
tk:RadCartesianChart3D.ZAxis
>
Since I assigned "Yellow" to the LinearAxis3D.Foreground, my label text blocks manage to find the parent LinearAxis3D and bind to this property to show the correct label color. But the axis lines never show up. That binding never finds the LinearAxis3D and so never gets any color.
If I change this setter to just use a hard coded color then it setter works fine. But obviously, that's not going to work for me.
Surprisingly, when I tried -- just as a test -- to bind by ElementName to "ZAxis", that didn't work either. It's not an option for me if I want this Style to be a StaticResource but still I was surprised it did not work.
So do I have any other option here? Is the Path object used to draw the axis line a logical child of the LinearAxis3D? And if not, is there any way to achieve what I want? Or do I need to just individually nest the line style for each axis?
I've got a RadCartesianChart3D chart that looks and works great. (You fine folks have helped me out with it quite a bit on some recent threads here). I use the Chart3DCameraBehavior upon it to zoom and rotate. Although that is great, I now have a customer request for my user to be able to have their mouse moves (or touch moves) pan the chart instead of rotating it. How may I do this?
I was thinking that I could make this into some sort of mode, but the Chart3DCameraBehavior does not seem to have any facility for panning at all that I can. Is there another behavior that might do this for me?
I would not be averse to writing my own code to adjust some sort of TranslateTransform when in some specific "mode", but the problem is that if I were to do that to the whole chart, the axes would pan with the surface and that wouldn't help me at all.
-Joe
When I create a PointSeries chart, the point's color is determined at moment the chart is showing. But I want the point's color changed with the datasource's some content after the chart was shown.
So I make a new PlotInfo class shown as below, and I set DefaultVisualMaterialSelector bind to PlotInfo's ColorFlag, with a Converter.
Finally, the project doesn't work, the point's color didn't change when I modify the ColorFlag.
So does ChartView3D support this kind of abbility? And how can I get what I want?
public
class
PlotInfo : INotifyPropertyChanged
{
public
event
PropertyChangedEventHandler PropertyChanged;
public
double
XValue {
get
;
set
; }
public
double
YValue {
get
;
set
; }
public
string
ZValue {
get
;
set
; }
private
string
m_sColorFlag;
public
string
ColorFlag
{
get
{
return
m_sColorFlag;}
set
{
m_sColorFlag = value;
if
(
this
.PropertyChanged !=
null
)
{
PropertyChanged.Invoke(
this
,
new
PropertyChangedEventArgs(
"ColorFlag"
));
}
}
}
}
MainWindow.xaml
<
Window
x:Class
=
"VariableMaterial.MainWindow"
xmlns:telerik
=
"http://schemas.telerik.com/2008/xaml/presentation"
xmlns:local
=
"clr-namespace:VariableMaterial"
mc:Ignorable
=
"d"
Title
=
"MainWindow"
Height
=
"350"
Width
=
"525"
>
<
Window.Resources
>
<
local:ColorConvert
x:Key
=
"myColorConvert"
/>
</
Window.Resources
>
<
Grid
>
<
Grid.RowDefinitions
>
<
RowDefinition
Height
=
"30"
/>
<
RowDefinition
/>
</
Grid.RowDefinitions
>
<
ToolBar
Grid.Row
=
"0"
Height
=
"auto"
>
<
Button
Content
=
"SetColorFlag=A"
Click
=
"ButtonA_Click"
Margin
=
"10,0,0,0"
/>
<
Button
Content
=
"SetColorFlag=B"
Click
=
"ButtonB_Click"
Margin
=
"10,0,0,0"
/>
</
ToolBar
>
<
telerik:RadCartesianChart3D
Grid.Row
=
"1"
>
<
telerik:RadCartesianChart3D.XAxis
>
<
telerik:LinearAxis3D
/>
</
telerik:RadCartesianChart3D.XAxis
>
<
telerik:RadCartesianChart3D.YAxis
>
<
telerik:LinearAxis3D
/>
</
telerik:RadCartesianChart3D.YAxis
>
<
telerik:RadCartesianChart3D.ZAxis
>
<
telerik:CategoricalAxis3D
/>
</
telerik:RadCartesianChart3D.ZAxis
>
<
telerik:RadCartesianChart3D.Series
>
<
telerik:PointSeries3D
PointSize
=
"100"
DefaultVisualMaterialSelector
=
"{Binding ColorFlag, Converter={StaticResource myColorConvert}}"
XValueBinding
=
"XValue"
YValueBinding
=
"YValue"
ZValueBinding
=
"ZValue"
ItemsSource
=
"{Binding}"
/>
</
telerik:RadCartesianChart3D.Series
>
<
telerik:RadCartesianChart3D.Grid
>
<
telerik:CartesianChart3DGrid
/>
</
telerik:RadCartesianChart3D.Grid
>
<
telerik:RadCartesianChart3D.Behaviors
>
<
telerik:Chart3DCameraBehavior
/>
</
telerik:RadCartesianChart3D.Behaviors
>
</
telerik:RadCartesianChart3D
>
</
Grid
>
</
Window
>
MainWindow.xaml.cs
using
System;
using
System.Collections.Generic;
using
System.Collections.ObjectModel;
using
System.Globalization;
using
System.Windows;
using
System.Windows.Data;
using
System.Windows.Media;
using
System.Windows.Media.Media3D;
namespace
VariableMaterial
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public
partial
class
MainWindow : Window
{
public
ObservableCollection<PlotInfo> source =
new
ObservableCollection<PlotInfo>();
public
MainWindow()
{
InitializeComponent();
PlotInfo info1 =
new
PlotInfo()
{
XValue = 1,
YValue = 1,
ZValue =
"A"
,
ColorFlag =
"A"
,
};
PlotInfo info2 =
new
PlotInfo()
{
XValue = 2,
YValue = 2,
ZValue =
"B"
,
ColorFlag =
"B"
,
};
source.Add(info1);
source.Add(info2);
this
.DataContext = source;
}
private
void
ButtonA_Click(
object
sender, RoutedEventArgs e)
{
source[0].ColorFlag =
"B"
;
}
private
void
ButtonB_Click(
object
sender, RoutedEventArgs e)
{
source[1].ColorFlag =
"A"
;
}
}
public
class
ColorConvert : IValueConverter
{
private
Dictionary<Color, Material> colorToMaterialDict =
new
Dictionary<Color, Material>();
public
object
Convert(
object
value, Type targetType,
object
parameter, CultureInfo culture)
{
string
colorFlag = (
string
)value;
Color color;
if
(colorFlag ==
"A"
)
{
color = (Color)ColorConverter.ConvertFromString(
"#007ACC"
);
}
else
{
color = (Color)ColorConverter.ConvertFromString(
"#68217A"
);
}
Material material;
if
(!
this
.colorToMaterialDict.TryGetValue(color,
out
material))
{
material =
new
DiffuseMaterial(
new
SolidColorBrush(color));
colorToMaterialDict[color] = material;
}
return
material;
}
public
object
ConvertBack(
object
value, Type targetType,
object
parameter, CultureInfo culture)
{
throw
new
NotImplementedException();
}
}
}
I'm using RadCartesianChart3d to show a surface. I've written some background code to intelligently choose the Maximum and Minimum values for my Z axis to be on nice even numbers which exceed the boundaries of the data. I then bind the LinearAxis3D for Z to these values.
The chart honors my Minimum value. Unfortunately, it sometimes ignores my Maximum value and chooses its own.
To be sure I wasn't wasting your time, before I posted this report, I tried to reproduce the problem using the sample application that Martin Ivanov attached in a reply in this other forum thread from just 2 weeks ago. It's the attachment "WpfApp17"
https://www.telerik.com/forums/dynamic-colorizer-for-surfaceseries3d
What I did was change the Z axis in the sample to use some arbitrary Minimum and Maximum values:
<
telerik:RadCartesianChart3D.ZAxis
>
<
telerik:LinearAxis3D
Minimum
=
"-800"
Maximum
=
"900"
/>
</
telerik:RadCartesianChart3D.ZAxis
>
At first, I could not reproduce the problem. But then I tried updating the sample to use the very latest version of UI for WPF that I have on my machine. It is R2 2019 SP1 which was literally released today, June 19, 2019.
Once I changed the assembly references to use the this new version of UI for WPF, the problem did occur. When I run the sample app with the changes above, my maximum axis value only shows 700, not 900.
(I realize the data does not go that high but I still want the chart to show the maximum I give to it.)
That's not all. It gets even stranger. If you then change the Maximum value from 900 to 1200, suddenly, it *is* honored.
The forum software does not seem to want to let me attach my modified version of the sample to this thread, even though it's a ZIP file and it's only 350k so you'll need to make the changes on your own version to reproduce this.
I've got a RadCartesianChart3D that uses a SurfaceSeries3D to show a colorized surface I've attached a sample image to show how it looks now ("Current_Surface.png")
This all works very well and looks great. It produces the image I referred to above.
Here is the XAML I use.
<
tk:RadCartesianChart3D.Series
>
<
tk:SurfaceSeries3D
ItemsSource
=
"{Binding Points}"
XValueBinding
=
"X"
YValueBinding
=
"Y"
ZValueBinding
=
"Z"
x:Name
=
"Series"
>
<
tk:SurfaceSeries3D.Colorizer
>
<
tk:SurfaceSeries3DValueGradientColorizer
x:Name
=
"Colorizer"
IsAbsolute
=
"False"
/>
</
tk:SurfaceSeries3D.Colorizer
>
</
tk:SurfaceSeries3D
>
</
tk:RadCartesianChart3D.Series
>
And here is how my XAML builds the GradientStops
// "Colors" is an array of 64 custom colors.
// Return an evenly distributed array of them for gradient stops.
var step = 1.0 / Colors.Length;
var stops = Colors.Select((color, index) => new GradientStop(color, index * step));
return new GradientStopCollection(stops);
But now I have a new requirement. I need to add a RadSlider that allows the user to dynamically change the colors instantaneously. The slider sets "cut-off" values distribution of the colors, limiting the range to a subset of 1.0. The visual effect is to highlight certain values. Basically I am emulating something that is already done a different application of ours (that app uses OpenGL).
To illustrate, I have also attached an image ("Desired_Surface.png") of this alternate application (the one that already has this slider) and the same surface showing. You can see the the user has adjusted the bottom slider upwards and this has totally compressed the color distribution. (You can even see the compressed distribution in the slider itself, though I don't need that).
My problem is that I cannot see how to emulate this with SurfaceSeries3D without using Deferred Dragging . The user needs to see the colors change immediately as he/she adjusted either of the sliders indicators; But the only way I can see to implement this is far too slow for anything but deferred dragging.
First I tried binding the Colorizer's GradientStop property. As you no doubt already know, that is not allowed by WPF
<
tk:SurfaceSeries3D.Colorizer
>
<
tk:SurfaceSeries3DValueGradientColorizer
IsAbsolute
=
"False"
GradientStops
=
"{Binding GradientStops}"
/>
Then I tried declaring all 64 gradient stops directly in XAML and binding each one's GradientStop.Offset to a backing view-model property but that is also not allowed (because Gradient stops must be Freezable and always sorted)
<
tk:SurfaceSeries3D.Colorizer
>
<
tk:SurfaceSeries3DValueGradientColorizer
IsAbsolute
=
"False"
>
<
tk:SurfaceSeries3DValueGradientColorizer.GradientStops
>
<
GradientStopCollection
>
<
GradientStop
Color
=
"sc# 1.0, 0.0, 0.0, 0.5625"
Offset
=
"{Binding Offset_0}"
/>
<
GradientStop
Color
=
"sc# 1.0, 0.0, 0.0, 0.6250"
Offset
=
"{Binding Offset_1}"
/>
So the only way I could get this working was to completely rebuild the entire Colorizer every single time the user adjusts the slider. I construct 64 new Gradient stops with the new Offset values and put them into a new GradientStop collection. Unfortunately, this is far, far too laggy and slow. It's too much work to do for a slider drag. So I am left with using deferred dragging. But that's not what my boss wants.
Is there any other approach I might take to speed up the adjustment of the colors?