Search code examples
c#wpfdatatemplateitemsourcevisifire

WPF Itemcontrol and datatemplate do not show properly


I have a problem using ItemControl, DataTemplate and Visifire Charts.

First, the code in XAML is as follow

<DataTemplate x:Key="markerChartTemplate">
    <vc:Chart Height="200" Theme="Theme1" Style="{StaticResource ChartStyle}">
        <vc:Chart.Series>
            <vc:DataSeries RenderAs="Line" LightWeight="true" ShadowEnabled="false" LightingEnabled="false" MarkerSize="4" LineThickness="1" DataPoints="{Binding _xAxisCollection}" />
            <vc:DataSeries RenderAs="Line" LightWeight="true" ShadowEnabled="false" LightingEnabled="false" MarkerSize="4" LineThickness="1" DataPoints="{Binding _yAxisCollection}" />
            <vc:DataSeries RenderAs="Line" LightWeight="true" ShadowEnabled="false" LightingEnabled="false" MarkerSize="4" LineThickness="1" DataPoints="{Binding _zAxisCollection}" />
        </vc:Chart.Series>
    </vc:Chart>
</DataTemplate>

<ScrollViewer HorizontalScrollBarVisibility="Disabled" HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto">              
    <ItemsControl VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ItemsSource="{Binding Path=_markerChartsCollections}" ItemTemplate="{StaticResource markerChartTemplate}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</ScrollViewer>

_markerChartsCollections is defined as

public ObservableCollection<My3DLineChartObject> _markerChartsCollections

in both ViewModel and Model.

Now, in Model, I initialise two My3DLineChartObject objects and put it into _markerChartsCollections.

The result is that I can see two , the same number as My3DLineChartObject in _markerChartsCollections. However, the properties in My3DLineChartObject, including _xAxisCollection, _yAxisCollection and _zAxisCollection, cannot be shown.

Can anyone help to see what is the possible reason?

The Output information is

'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero2\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero2.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_32\Microsoft.Kinect\v4.0_2.0.0.0__31bf3856ad364e35\Microsoft.Kinect.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\Users\admin\Desktop\Hand\SkeletonMarkerCapture_Good_2\SkeletonMarkerCapture\bin\Debug\AForge.Imaging.dll'. Cannot find or open the PDB file.
'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\Users\admin\Desktop\Hand\SkeletonMarkerCapture_Good_2\SkeletonMarkerCapture\bin\Debug\Emgu.CV.dll'. Module was built without symbols.
'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\Users\admin\Desktop\Hand\SkeletonMarkerCapture_Good_2\SkeletonMarkerCapture\bin\Debug\Emgu.Util.dll'. Module was built without symbols.
'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\Users\admin\Desktop\Hand\SkeletonMarkerCapture_Good_2\SkeletonMarkerCapture\bin\Debug\AForge.dll'. Cannot find or open the PDB file.
The thread 0x75d4 has exited with code 259 (0x103).
'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXmlLinq\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXmlLinq.dll'. Cannot find or open the PDB file.
'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXml\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXml.dll'. Cannot find or open the PDB file.
'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\Users\admin\Desktop\Hand\SkeletonMarkerCapture_Good_2\SkeletonMarkerCapture\bin\Debug\GalaSoft.MvvmLight.dll'. Symbols loaded.
'SkeletonMarkerCapture.vshost.exe' (CLR v4.0.30319: SkeletonMarkerCapture.vshost.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.`enter code here`0__31bf3856ad364e35\UIAutomationTypes.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.

Solution

  • I'm including the comments from my origin answer below, but after playing with Visifire a bit, you may actually be running into problems with the design of the library (I started to remember this from using it years ago). Many of the DependencyProperties exposed on charts cannot be bound to. I worked out an example like yours and posted it here. Specifically, bindings with DataPoints are managed internally. What you really want is to bind DataSource. You'll also need to set a YValue mapping even if you're using their DataPoint type in your ViewModel.

    For example, your DataTemplate will need to bind your point collections more like this

    <DataTemplate x:Key="MarkerChartTemplate">
        <vc:Chart Height="200" Width="400">
           <vc:Chart.Series>
                <vc:DataSeries RenderAs="Line" DataSource="{Binding XAxisCollection}">
                    <vc:DataSeries.DataMappings>
                        <vc:DataMapping MemberName="YValue" Path="YValue"/>
                    </vc:DataSeries.DataMappings>
                </vc:DataSeries>
            </vc:Chart.Series>
        </vc:Chart>
    </DataTemplate>
    

    You should take a look at the Visifire docs for more details. Unfortunately the docs aren't very explicit about other DependencyProperty updates not being effective in the library.


    Other things you should check and general good practices:

    It looks like you're trying to use Visifire charts to display an ItemsControl of 3-series charts. There are a number of things that could be going wrong. Here's what I'd suggest to look at.

    First, check to see if your bindings are working. Maybe you've forgotten to make something public. Maybe your series are not showing because they're not notifying properties and you don't have them set when initially binding. Having a complex DataTemplate is just going to cloud things at first so try something simpler like

    <DataTemplate x:Key="SimplerTemplate">
        <UniformGrid Columns="3">
            <TextBlock Text="{Binding _xAxisCollection}"/>
            <TextBlock Text="{Binding _yAxisCollection}"/>
            <TextBlock Text="{Binding _zAxisCollection}"/>
        </UniformGrid>
    </DataTemplate>
    

    Let's say you do that and you see a string in each TextBlock that corresponds to a Visifire.Charts.DataPointCollection. That's great. That means your DataBinding will actually work. In that case I would post more example code around how you're defining your DataSeries so someone more familiar with Visifire can help out (you should tag Visifire in that case too).

    However, let's say it doesn't work. There's one helpful thing you can check from within Visual Studio (your output window). There are also some ways to make your program a bit easier to debug.

    • Check your console output for System.Windows.Data binding errors. If there's a typo or your fields are not accessible, WPF will log an error about it.
    • Don't bind to raw fields. Make your ObservableCollections private and readonly. Wrap them with a getter. You want to make sure that none of your other code, especially DataBindings defined in XAML are swapping your collections out on you under the hood. With TwoWay bindings, its not hard to make that mistake.
    • On My3DLineChartObject - same thing, wrap your three series with getter properties and bind to those.
    • Implement INotifyPropertyChanged on your ViewModel and My3DLineChartObject. Whenever you change one of your series fields in My3DLineChartObject, you'll also want to raise NotifyPropertyChanged("...AxisCollection"). If you never change them, you should make them readonly and just provide a getter. Again, this avoids them being swapped out by a TwoWay binding.
    • Put breakpoints in your AxisCollection getters. When you run your applications and you display this view, are those getters getting called? Databinding uses reflection and it will invoke your getter properties.

    Hope that helps.