Series data binding in LightningChart - wpf

I see there's 3 WPF APIs available in LightningChart. Bindable/semi-bindable and non-bindable. What's exactly difference of them?
How to bind a collection of data points to make a line chart?

Bindable chart API: DependencyProperties, ObservableCollection-based lists and data inputs. Bind everything. Configure in XAML. Good performance when compared to competitors but not as good as semi-bindable or non-bindable. The performance difference shows especially when using hundreds of series and millions of data points.
Semi-bindable chart API: DependencyProperties, ObservableCollections in lists. Data input is array-based and must be done in code-behind. So you can bind UI settings and chart objects, but just feed the data in code. Very good performance.
Non-bindable chart API: No DependencyProperties, no ObservableCollections in any lists or data inputs. Regular properties and usage in code-behind. Best performance and multithreading features. Over billion points can be monitored in real-time monitoring as our demo application shows.
With Bindable chart API you can configure chart and bind like this
<Window x:Class="BindingExamplePointLineSeries.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lcub="http://schemas.arction.com/bindablecharting/ultimate/"
x:Name="thisTest"
Title="MainWindow" Height="350" Width="525">
<Grid>
<lcub:LightningChartUltimate>
<lcub:LightningChartUltimate.ViewXY>
<lcub:ViewXY>
<lcub:ViewXY.YAxes>
<lcub:AxisY/>
</lcub:ViewXY.YAxes>
<lcub:ViewXY.XAxes>
<lcub:AxisX/>
</lcub:ViewXY.XAxes>
<lcub:ViewXY.PointLineSeries>
<lcub:PointLineSeries Points="{Binding ElementName=thisTest, Path = Points}" PointsVisible="True"/>
</lcub:ViewXY.PointLineSeries>
</lcub:ViewXY>
</lcub:LightningChartUltimate.ViewXY>
</lcub:LightningChartUltimate>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Random rand = new Random();
SeriesPointCollection points0 = new SeriesPointCollection();
for (int i = 0; i < 10; i++)
{
SeriesPoint p = new SeriesPoint();
p.X = i;
p.Y = rand.NextDouble() * 10.0;
points0.Add(p);
}
Points = points0;
}
public static readonly DependencyProperty PointsProperty =
DependencyProperty.Register(
"Points",
typeof(SeriesPointCollection),
typeof(MainWindow)
);
public SeriesPointCollection Points
{
get { return GetValue(PointsProperty) as SeriesPointCollection; }
set { SetValue(PointsProperty, value as Object); }
}
}
and then you get the chart with your data bound:

Related

WPF/MVVM windowsservice without viewmodel reset

I'm want to remove from my view model's creating of view's
I wrote WinodwsService class to creating a new window:
public class WindowService : IWindowService
{
public void ShowWindow(object viewModel)
{
//var win = new DXWindowCloasable(viewModel);
var win = new DXWindow();
win.Content = viewModel;
win.DataContext = viewModel;
win.ShowDialog();
}
}
In view model I call method:
var vm = new PolaPrzewoznikowViewModel(konf);
IWindowService wnf = new WindowService(); // this is only for test
wnf.ShowWindow(vm);
In UserControl I have defined view model type:
<UserControl.DataContext>
<local:PolaPrzewoznikowViewModel />
</UserControl.DataContext>
When I have this, I can drill down (CTRL + B) on commands, and user an code completition when I'm projecting a View - this is very helpful.
But... when I use
win.ShowDialog(); the new view model is created. And displayed view has view model without parameters (default constructor).
How can I use window service and keep defined UserControl.DataContext in view?
instead of initializing DataContext in xaml
<UserControl.DataContext>
<local:PolaPrzewoznikowViewModel />
</UserControl.DataContext>
I suggest to use DesignInstance:
<UserControl d:DataContext="{d:DesignInstance Type=local:PolaPrzewoznikowViewModel,
IsDesignTimeCreatable=True}" ...>
It will give IntelliSense and designer enough information in design-time, but a new instance won't be created in run-time (there will only DataContext from WindowService)
Why are you setting both the content and the datacontext of the window?
Regarding intellisense you should do as ASh suggests, the data context by its nature will be available to all view descendants.
If you don't want to implement the window service yourself you can always use my framework https://github.com/FantasticFiasco/mvvm-dialogs.

How can I bind Pushpin location in WPF using MVVM?

I'm developing a Desktop application that uses Bing maps and MVVM.
In the application, a user adds a Pushpin in the map by double clicking on it, the Pushpin location gets saved in an Event class and the Event class is sent through a WCF Service.
I would like to get the Latitude and Longitude from the Pushpin using data binding, however the compiler complains about DependencyProperty when I try to do that.
I managed to set the Latitude and Longitude in the ViewModel from the View, however I don't know if it's valid in MVVM. I have seen examples using MapsItemControls but I don't understand them.
ViewModel
private Event evt;
public Event Evt
{
get
{
return this.evt;
}
set
{
this.evt = value;
OnPropertyChanged("Event");
}
}
Map xaml
<m:Map Grid.RowSpan="5" Grid.Column="3" Margin="3"
Name="operatorMap"
CredentialsProvider="Map_key"
Center="19.4000,-99.1333"
ZoomLevel="5"
MouseDoubleClick="SetPushpinLocation" />
CodeBehind
private MaintenanceFormViewModel viewModel = new MaintenanceFormViewModel();
private Pushpin pin = null;
public MainWindow()
{
InitializeComponent();
this.Loaded += (s, e) =>
{
this.DataContext = this.viewModel;
};
}
private void SetPushpinLocation(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
Point mousePosition = e.GetPosition((UIElement)sender);
Location pinLocation = operatorMap.ViewportPointToLocation(mousePosition);
if (pin == null)
{
pin = new Pushpin();
operatorMap.Children.Add(pin);
}
pin.Location = pinLocation;
this.viewModel.Evt.Latitude = pinLocation.Latitude;
this.viewModel.Evt.Longitude = pinLocation.Longitude;
}
Bing Maps uses the attached property MapLayer.Position for positioning elements on the map.
Given a view model with a property of type Location
public class ViewModel : INotifyPropertyChanged
{
private Location location;
public Location Location
{
get { return location; }
set
{
location = value;
OnPropertyChanged("Location");
}
}
...
}
you can bind the position of a Pushpin like this:
<bm:Pushpin bm:MapLayer.Position="{Binding Location}"/>
Note that in the Windows Store App version of the Bing Maps SDK there seems to be a bug when you try to setup a binding in XAML. It says (still with Bing Maps SDK version 1.313.825.0)
Failed to assign to property 'Bing.Maps.MapLayer.Position'
You can however create a binding in code behind:
pushpin.SetBinding(MapLayer.PositionProperty,
new Binding { Path = new PropertyPath("Location") });
Personally, I'd add an attached property to the Bing map which would allow you to bind the lat/long to properties to your ViewModel. This would follow the MVVM pattern.
Google "attached property wpf" for a tutorial on attached properties, there are some good ones out there.
This is not to say that using code behind is bad: usually I get it working with code behind first, then port it into an attached property to adhere to the MVVM pattern, and for reusability and maintainability.
You mentioned an error related to dependecy properties. These are completely different to attached properties.
You add a dependency property to a user control that you write yourself.
You add an attached property to another 3rd party control you cannot alter or do not have the source code for. The rule of thumb is this: if you start with any code behind in a user control, you can shift it into an attached property to keep in line with the MVVM pattern.
Yes, attached properties are a bit of a learning curve, but persevere: this is one technique you will have to master before you can become an MVVM expert.

Design-Time setup of a ViewModel

I'm using Visual Studio 2013's designer to create my User Control in WPF, and I'm using a MVVM approach.
I'm trying to find the best way to have "Design-Time" setup of my viewmodel so that I immediatly see the effect in the designer of changing a value of a property for instance. I've used different designs and techniques to support this, but nothing is exactly what I want. I'm wondering if someone has better ideas...
Situation (simplified):
So I have a "Device" which I want a UserControl to show states and operations. From top to bottom:
I have a IDeviceModel which has a field bool IsConnected {get;} (and proper notification of state changes)
I have a FakeDeviceModel which implements IDeviceModel, and thus enables me to not rely on a real device for design-time and testing
A DeviceViewModel, which contains a IDeviceModel, and encapsulate the model's properties. (yes it has proper INotifyPropertyChanged notifications in it)
My UserControl which will have a DataContext of type DeviceViewModel, and would have a custom-styled CheckBox which is IsChecked={Binding IsConnected, Mode=OneWay
My Goal: I want to preview on design time how does the Model's IsConnected state affect my UserControl (So it could affect other things than just IsChecked)
Framework:
I use the idea of the MVVM Light ViewModelLocator, returning non-static fields (so new instances of ViewModels). At runtime, the real datacontext will be given by the one instanciating this UserControl
d:DataContext="{Binding DeviceViewModelDesignTime, Source={StaticResource ViewModelLocator}}"
public class ViewModelLocator
{
private static MainWindowViewModel _mainWindowViewModel;
public MainWindowViewModel MainWindowViewModelMainInstance
{
get
{
if (_mainWindowViewModel == null)
{
_mainWindowViewModel = new MainWindowViewModel();
}
return _mainWindowViewModel;
}
}
public DeviceViewModel DeviceViewModelDesignTime
{
get
{
//Custom initialization of the dependencies here
//Could be to create a FakeDeviceModel and assign to constructor
var deviceViewModel = new DeviceViewModel();
//Custom setup of the ViewModel possible here
//Could be: deviceViewModel.Model = new FakeDeviceModel();
return deviceViewModel;
}
}
Solutions I tried:
Compile-Time solution
Simply code the setup of the ViewModel in the ViewModelLocator.
var deviceViewModel = new DeviceViewModel(fakeDeviceModel);
var fakeDeviceModel = new FakeDeviceModel();
fakeDeviceModel.IsConnected = true;
deviceViewModel.AddDevice(fakeDeviceModel);
Pros: Simple
Cons: That's longer iterations of always going to change the value in code, recompile, go back to designer view, wait for result
Instance in resources and kept static in ViewModelLocator
So I create an instance in XAML and I try to push it in the current ViewModel used by the designer. Not the cleanest way, but worked for a while in simple situation (yes there's some wierdness with the collection, but was with the idea that I could have multiple devices and a current one)
XAML:
<UserControl x:Class="Views.StepExecuteView"
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"
mc:Ignorable="d"
d:DataContext="{Binding DeviceViewModelDesignTime, Source={StaticResource ViewModelLocator}}">
<UserControl.Resources>
<viewModels:DesignTimeDeviceManager x:Key="DesignTimeDeviceManager">
<viewModels:DesignTimeDeviceManager.DesignTimeDevices>
<device:FakeDeviceModel IsConnected="True"
IsBusy="False"
IsTrayOpen="True"
NumberOfChipSlots="4"
/>
</viewModels:DesignTimeDeviceManager.DesignTimeDevices>
[... CheckBox binding to datacontext and so on...]
And ViewModelLocator.cs:
public class ViewModelLocator
{
private static MainWindowViewModel _mainWindowViewModel;
public MainWindowViewModel MainWindowViewModelMainInstance
{
get
{
if (_mainWindowViewModel == null)
{
_mainWindowViewModel = new MainWindowViewModel();
}
return _mainWindowViewModel;
}
}
public static FakeDeviceModel DeviceModelToAddInDesignTime;
public DeviceViewModel DeviceViewModelDesignTime
{
get
{
var deviceViewModel = new DeviceViewModel();
if (DeviceModelToAddInDesignTime != null)
deviceViewModel.AddDevice(DeviceModelToAddInDesignTime );
return deviceViewModel;
}
}
}
public class DesignTimeDeviceManager
{
private ObservableCollection<FakeDeviceModel> _DesignTimeDevices;
public ObservableCollection<FakeDeviceModel> DesignTimeDevices
{
get { return _DesignTimeDevices; }
set
{
if (_DesignTimeDevices != value)
{
_DesignTimeDevices = value;
ViewModelLocator.DeviceModelToAddInDesignTime = value.FirstOrDefault();
}
}
}
}
Pros:
Worked super great on one project. the instance that I had in XAML, I could modify the booleans and I would get -immediate- feedback on how it affects my UserControl. So in the simple situation, the CheckBox's "Checked" state would change and I could modify my styling in real-time, without needing to recompile
Cons:
It stopped working in another project, and this by itself I couldn't find the reason why. But after recompiling and changing stuff, the designer would give me exceptions looking like "Cannot cast "FakeDeviceModel" to "FakeDeviceModel""!! My guess is that the Designer internally compiles and uses caches for those types (C:\Users\firstname.lastname\AppData\Local\Microsoft\VisualStudio\12.0\Designer\ShadowCache). And that in my solution, depending on the ordering of things, I was creating a "FakeDeviceModel" which was assigned to a static instances, and "later on", the next time the ViewModelLocator would be asked for a ViewModel, it would use that instance. However, if in the meantime he "recompiles" or uses a different cache, then it's not "exactly" the same type. So I had to kill the designer (XDescProc) and recompile for it to work, and then fail again a few minutes after. If someone can correct me on this it would be great.
Multi-Binding for d:DataContext and custom converter
The previous solution's problem was pointing me to the fact that the ViewModel and the FakeDeviceModel were created at different moment in time (giving the type/cast problem) and to solve it, I would need to create them at the same time
XAML:
<UserControl x:Class="MeltingControl.Views.DeviceTabView"
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"
mc:Ignorable="d">
<d:UserControl.DataContext>
<MultiBinding Converter="{StaticResource DeviceDataContextConverter}">
<Binding Path="DeviceViewModelDesignTime" Source="{StaticResource ViewModelLocator}" />
<Binding>
<Binding.Source>
<device:FakeDeviceModel IsConnected="False"
IsBusy="False"
IsTrayOpen="False"
SerialNumber="DesignTimeSerie"
/>
</Binding.Source>
</Binding>
</MultiBinding>
</d:UserControl.DataContext>
public class DeviceDataContextConverter: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length == 0)
return null;
var vm = (DeviceViewModel)values[0];
if (values.Length >= 2)
{
var device = (IDeviceModel)values[1];
vm.AddDevice(device);
}
return vm;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Pros:
-Works super nice! When the binding for the DataContext asks for the ViewModel, I take advantage of the Converter to modify that ViewModel and inject my device before returning it
Cons:
We lose intelissense (with ReSharper), since he doesn't know what type is returned by the converter
Any other ideas or modifications I could make to solve this issue?
You may create a design time ViewModel that returns IsConnected = true based on your view mode (FakeDeviceViewModel) and then set it as a design-time data context:
d:DataContext="{d:DesignInstance viewModels:FakeDeviceViewModel,
IsDesignTimeCreatable=True}"
Where viewModels: is the xaml namespace to the actual view model.
I've documented exactly how I managed to get the perfect setup to see live Design Time data in Visual Studio.
Look at Hint 9 - Design Time DataContext on this page:
ReSharper WPF error: "Cannot resolve symbol "MyVariable" due to unknown DataContext"
I would like to propose an alternative solution.
You could use that same view model for design time data and normal runtime, and check in your (single) viewmodel whether the designer is active and then load the design time data there.
In your view model you would do something like this:
public class ExampleViewModel : ViewModelBase
{
public ExampleViewModel()
{
if (IsInDesignMode == true)
{
LoadDesignTimeData();
}
}
private void LoadDesignTimeData()
{
// Load design time data here
}
}
The IsInDesignMode property could be placed in your view model base class - if you have one - and looks like this:
DesignerProperties.GetIsInDesignMode(new DependencyObject());
Please take a look at my answer here
This is how I am doing it one of my projects using MVVMLight.
Create interface for every viewmodel for which you need separate design time and run time properties and behavior.
Make separate viewmodels for every view - one for run time and another for design time. Derive both viewmodels from the same interface defined above.
Create a static class that has two static methods - one for registering services for run time in the IOC container and another for registering services for design time in the IOC container. I use the same SimpleIOC.Default container. Register appropriate viewmodels in both the methods bound to their interfaces.
public static class MyServiceLocator()
{
public static void RegisterRunTimeServices()
{
ServiceLocator.SetLocatorProvider(() => SimpleIOC.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<IAboutViewModel, AboutViewModel>();
}
public static void RegisterDesignTimeServices()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<IAboutViewModel, DesignTimeAboutViewModel>();
}
In constructor of ViewModelLocator, check if the app is in DesignMode and accordingly call the static method to register services.
public ViewModelLocator()
{
if (ViewModelBase.IsInDesignModeStatic)
{
MyServiceLocator.RegisterDesignTimeServices();
}
else MyServiceLocator.RegisterRunTimeServices();
}
Now, your Views just have to set datacontext as corresponding viewmodel interface instead of viewmodel object. To do that, instead of exposing viewmodel objects to each view from the ViewModelLocator, expose viewmodel interface.
In ViewModelLocator.cs
public IAboutViewModel About
{
get
{
return ServiceLocator.Current.GetInstance<IAboutViewModel>();
}
}
In AboutView.xaml
DataContext="{Binding Source={StaticResource Locator}, Path=About}"
Wherever needed in code, cast the interface to ViewModelBase type to convert it to ViewModel object and use.
In MainViewModel.cs
public class MainViewModel : ViewModelBase
{
private readonly IAboutViewModel _aboutViewModel;
public MainViewModel()
{
_aboutViewModel = ServiceLocator.Current.GetInstance<IAboutViewModel>();
CurrentViewModel = (ViewModelBase) _aboutViewModel;
}
}
So, basically I use DI to inject appropriate viewmodels to each view depending on whether the code is in run time or design time. The ViewModelLocator simply registers either design time or run time viewmodels in the SimpleIOC container. The benefit of this is that there is no mixing of code in viewmodel files and one can also setup the code for multiple design time data without much interference. If you want designtime data to show while the application runs, then also its possible with one line change in code.
I would create an instance of Fake View Model in a separate xaml e.g. DeviceViewModelDataSample.xaml (see example below)
Set Build Action to DesignData
Reference the file as such
<UserControl x:Class="YourNameSpace.YourControl"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataContext="{d:DesignData Source=/DataSample/DeviceViewModelDataSample.xaml}">
<!-- Skiped details for brevity -->
</UserControl>
DeviceViewModelDataSample.xaml
<vm:DeviceViewModel xmlns:dm="clr-namespace:YourNameSpace.DataModel"
xmlns:vm="clr-namespace:YourNameSpace.ViewModel">
<vm:DeviceViewModel.DeviceManager> <!-- Assuming this is a collection -->
<dm:DeviceModel DeviceName="Fake Device" IsConnected ="true" /> <!-- This creates an instance at design time -->
</vm:DeviceViewModel.DeviceManager>
</vm:DeviceViewModel>

WPF Combo and Rx FromEvent Pattern

I am in process of developing a WPF app to practice Rx with MVVM.
Scenario
I have a View (MVVM) with a combo (some company name) and a detail (company journal) section; I wanted to populate detail section when user select an item from combo box.
The detail section data is populated with the help of a WCF service method, which take company name as input and Task<> as output.
Problem
Users sometime select combo box items in quick succession, which leads my window to freeze. I presume, this might be because of event queue up Or due to slow result from wcf service method.
Therefore, I am thinking to use Rx's FromEvent pattern (MVVM fashion), which shall be able to observe ComboBox SelectedItem Change event to load data from wcf and skip events those are coming in quick succession using some throttle.
I appreciate any sample implementations while respecting MVVM.
I think that the operator you are looking for is Switch(). I couldn't find an msdn page for it, but this is the signature you're after:
public static IObservable<TSource> Switch<TSource>(this IObservable<Task<TSource>> sources)
That will take an IObservable<Task<T>> and turn it into an IObservable<T> which produces the results of the most recent Task<T> received.
Here is an example implementation that doesn't use any MVVM, but I'm sure you can see how it would apply:
MainWindow.xaml
<Window x:Class="LastFromCombo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<ComboBox Name="cbx" />
<TextBlock Name="result" />
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.cbx.ItemsSource = Enumerable.Range(0, 100);
Observable.FromEventPattern<SelectionChangedEventArgs>(this.cbx, "SelectionChanged")
.Select(ev => ev.EventArgs.AddedItems.Cast<object>().FirstOrDefault())
.Select(GetDetails)
.Switch()
.ObserveOnDispatcher()
.Subscribe(detail => this.result.Text = detail);
}
private static async Task<string> GetDetails(object data)
{
await Task.Delay(TimeSpan.FromSeconds(3.0));
return "Details from " + data;
}
}

WPF DataGrid bound to an ObservableCollection that is updated on separate thread fails to maintain sort

Download Sample Project
I have a wpf 4 datagrid that is bound to an ObservableCollection. This ObservableCollection is
updated on another thread. I can see the updates coming through to my simple gui just fine. I can even sort the data. But the sort does not "stick". It will sort once when you click the column header but when a value in the collection changes the sort does not change accordingly.
The MainWindow backing code is where most of the action goes down (just for simplicity of the example). I create an ObservableCollection and pass it to a thread that does the actual writes to the ObservableCollection. I then bind that same ObservableCollection to the datagrid via a CollectionView (I've tried binding it directly as well). My hunch is that the sorting depends upon the collectionChanged event which I'm pretty sure won't fire back to the Dispatcher ( see: http://bea.stollnitz.com/blog/?p=34).
What to do?
public partial class MainWindow : Window
{
private Thread _dataThread;
private Thread _marketThread;
private SampleData _sampleData;
private Market _market;
private ObservableCollection<Stock> stocks;
private ConcurrentQueue<Stock> _updates = new ConcurrentQueue<Stock>();
public MainWindow()
{
InitializeComponent();
stocks = new ObservableCollection<Stock>();
for (var i = 0; i < 5; i++)
{
var newStock = new Stock();
newStock.Id = (uint)i;
stocks.Add(newStock);
}
var source = CollectionViewSource.GetDefaultView(stocks);
dataGrid.ItemsSource = source;
_sampleData = new SampleData(_updates);
_dataThread = new Thread(_sampleData.CreateData) { Name = "Data Thread" };
_dataThread.Start();
_market = new Market(_updates, stocks);
_marketThread = new Thread(_market.Start){Name = "Market Thread"};
_marketThread.Start();
}
}
Challenge.
Download Sample Project
Have you looked at ObjectDataProvider IsAsynchonous="True" and bind in XAML? You might be able to not thread the collection creation. I have no experience how DataGrid sorts behave behind IsAsynchonous="True".
<ObjectDataProvider IsAsynchonous="True" ...>

Resources