Hi,
i need an absolute minified implementation for a DataChart with Livedata.
That what i have done:
XAML:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mvvm="http://prismlibrary.com/" xmlns:ig="http://schemas.infragistics.com/xaml" x:Name="UserControlChartCard" x:Class="TorqueLink.Presentation.Views.ChartCard" mvvm:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" Height="300" Width="500"> <Grid x:Name="LayoutRoot" Margin="0" Background="White"> <ig:XamDataChart x:Name="SignalChart" Margin="10" DataContext="{Binding ChartValues}"> <ig:XamDataChart.Series> <ig:LineSeries ItemsSource="{Binding DataContext, ElementName=SignalChart}" ValueMemberPath="SignalData"/> </ig:XamDataChart.Series> <ig:XamDataChart.Axes> <ig:CategoryDateTimeXAxis ItemsSource="{Binding DataContext, ElementName=SignalChart}" DateTimeMemberPath="SignalDateTime" /> </ig:XamDataChart.Axes> </ig:XamDataChart> </Grid></UserControl>
ViewModel (is injected to the UserControl by PRISM):
public class ViewModelChart : ViewModelBase { public class Signal : INotifyPropertyChanged { private double _signalData; private DateTime _signalDateTime;
public double SignalData { get { return _signalData; } set { _signalData = value; OnPropertyChanged(); } }
public DateTime SignalDateTime { get { return _signalDateTime; } set { _signalDateTime = SignalDateTime; OnPropertyChanged(); } }
public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); }
protected virtual void OnPropertyChanged(PropertyChangedEventArgs propertyChangedEventArgs) { RaisePropertyChanged()?.Invoke(propertyChangedEventArgs); }
protected Action<PropertyChangedEventArgs> RaisePropertyChanged() { return args => PropertyChanged?.Invoke(this, args); } }
[NotNull] public ObservableCollection<Signal> ChartValues { get; } = new ObservableCollection<Signal>();
public delegate void SetDataDeviceObjectDelegate(DataDeviceObject dataDeviceObject);
[NotNull] private readonly IDeviceDataManager _deviceDataManager;
public ViewModelChart([NotNull] IDeviceDataManager deviceDataManager) { if (deviceDataManager == null) throw new ArgumentNullException(nameof(deviceDataManager)); _deviceDataManager = deviceDataManager;
//TODO: Use EventAggregator ChartAction = StartSignalChecker; }
public void StartSignalChecker() {
// ### here im starting the signal. it is using the SetDataDeviceObject delegate
}
public void SetDataDeviceObject(IDataDeviceObject dataDeviceObject) { if (dataDeviceObject == null || dataDeviceObject.Data == 0) return;
Signal signal = new Signal(); ChartValues.Add(signal); OnPropertyChanged("ChartValues"); signal.SignalDateTime = DateTime.Now; signal.SignalData = dataDeviceObject.Signal; } }
...............
Well, nothing happend. what is necessary and missing?
Hi Stefan,
From what I can see the only thing that stands out is that you don't have a Y axis defined, nor do you bind the LineSeries to an X and Y axis. Please take a look at the code snippets present in the following documentation:http://help.infragistics.com/doc/WPF/2016.1/CLR4.0/?page=DataChart_Category_Line_Series.html
There are 4 properties which are essential to the LineSeries in order to work properly. These properties are ItemsSource, ValueMemberPath, XAxis and YAxis. If one of these properties is missing, nothing will work. Now maybe you set these in code behind somewhere, but I don't see those present in the current code snippet provided. If you have not created a NumericYAxis and added it to the XamDataChart.Axes collection, please do so. Also, give the CategoryDateTimeXAxis a Name so that you can bind to it in the LineSeries.
<ig:XamDataChart.Axes> <ig:CategoryDateTimeXAxis x:Name="xAxis" ItemsSource="{Binding DataContext, ElementName=SignalChart}" DateTimeMemberPath="SignalDateTime" /> <ig:NumericYAxis x:Name="yAxis"/></ig:XamDataChart.Axes><ig:XamDataChart.Series> <ig:LineSeries ItemsSource="{Binding DataContext, ElementName=SignalChart}" ValueMemberPath="SignalData" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}"/></ig:XamDataChart.Series>
Other than this, everything else looks fine. The DataContext for the whole chart has been set to your ObservableCollection of ChartValues so all the CategoryDateTimeXAxis and LineSeries need to do is bind to the chart's DataContext. ObservableCollection will take care of notifying the chart when new Signal objects are added and if you need to update the SignalData or SignalDateTime properties, you have implemented INotifyPropertyChanged for them already.
As a side note, one recommendation I have not related to the main issue is where you create a new Signal object and add it to the chart. Immediately after you have added this you are setting the SignalDateTime and SignalData properties. I recommend setting these properties first and then adding them to the collection. When you add to the collection this immediately fires a collection changed notification and the chart responds to it. After that the properties are updated which triggers two property changed notifications which the chart responds to. You can avoid the two property notifications by updating them first and then adding to the collection. This way the chart only ever sees the one collection changed notification.
Thanks for the great support!
I am now "one step further"...
I changed my source like this:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mvvm="http://prismlibrary.com/" xmlns:ig="http://schemas.infragistics.com/xaml" x:Name="UserControlChartCard" x:Class="TorqueLink.Presentation.Views.ChartCard" mvvm:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" Height="300" Width="500"> <Grid x:Name="LayoutRoot" Margin="0" Background="White"> <ig:XamDataChart x:Name="SignalChart" Margin="10" DataContext="{Binding ChartValues}" HorizontalZoomable="True" VerticalZoomable="True"> <ig:XamDataChart.Series> <ig:LineSeries ItemsSource="{Binding DataContext, ElementName=SignalChart}" ValueMemberPath="SignalData" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}"/> </ig:XamDataChart.Series> <ig:XamDataChart.Axes> <ig:CategoryDateTimeXAxis x:Name="xAxis" ItemsSource="{Binding DataContext, ElementName=SignalChart}" DateTimeMemberPath="SignalDateTime" /> <ig:NumericYAxis x:Name="yAxis"/> </ig:XamDataChart.Axes> </ig:XamDataChart> </Grid></UserControl>
ViewModel:
public class ViewModelChart : ViewModelBase { public delegate void SetDataDeviceObjectDelegate(DataDeviceObject dataDeviceObject); public static Dispatcher CurrentDispatcher; public static ItemAdderDelegate SignalItemAdderDelegate; public delegate void ItemAdderDelegate(Signal item);
public ViewModelChart([NotNull] IDeviceDataManager deviceDataManager) { if (deviceDataManager == null) throw new ArgumentNullException(nameof(deviceDataManager)); _deviceDataManager = deviceDataManager; CurrentDispatcher = Dispatcher.CurrentDispatcher; SignalItemAdderDelegate = ItemAdder;
public void StartSignalChecker() { if (_deviceDataManager.RegisteredDevices.Count <= 0) return;
IDeviceCommunicator deviceCommunicator = _deviceDataManager.GetCommunicator(); if (deviceCommunicator.ConnectionState != DeviceConnectionState.Connected) deviceCommunicator.Connect(); string deviceName = deviceCommunicator.DeviceName; SetDataDeviceObjectDelegate delegateDeviceObject = SetDataDeviceObject; _deviceDataManager.CreateGetDataDeviceObjectThread(delegateDeviceObject, deviceName, 400); }
Signal signal = new Signal {SignalDateTime = DateTime.Now, SignalData = dataDeviceObject.Signal}; CurrentDispatcher.Invoke(DispatcherPriority.Background, SignalItemAdderDelegate, signal); } private void ItemAdder(Signal item) { ChartValues.Add(item); }
public class Signal : INotifyPropertyChanged { private decimal _signalData; private DateTime _signalDateTime;
public decimal SignalData { get { return _signalData; } set { _signalData = value; OnPropertyChanged(); } }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); }
protected Action<PropertyChangedEventArgs> RaisePropertyChanged() { return args => PropertyChanged?.Invoke(this, args); } } }
i have nothing in code behind.
Thats what i seen now:
Seems i still do anything wrong? :(
Great! Let me know if you have any further questions.
ofc yes :D
thx very much!! it works now ... *happy*
Your SignalDateTime property setter has a typo. It is setting _signalDateTime to SignalDateTime instead of "value". Change it to say "_signalDateTime = value;".