Im trying develope a databound polyline canvas.
Currently I databind a list of classes each containing an pointcollection and an offset. However I want to customize each of these lines further eg, their colour. Therefore I want to create a List inside the class containing a polyline model class. Which contain a pointcollection, offset X, Y and data for the polylines colour.
Currently it looks like this:
<Canvas Name="PolyLineCanvas" Width ="100" Height="100">
<ItemsControl ItemsSource="{Binding WaypointList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,NotifyOnTargetUpdated=True}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=TracedPathLeft, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Canvas.Top" Value="{Binding Path=TracedPathTop, UpdateSourceTrigger=PropertyChanged}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Polyline Stroke="Magenta" Points="{Binding TracedPath}" StrokeThickness="0.0244"></Polyline>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
And class:
public class WaypointListModel : INotifyPropertyChanged
{
public class Waypoint : INotifyPropertyChanged
{
ObservableCollection<Waypoint> wptList;
PointCollection tracedPath;
double tracedPathTop;
double tracedPathLeft;
public Waypoint(ObservableCollection<Waypoint> WptList)
{
wptList = WptList;
}
public PointCollection TracedPath
{
get
{
return tracedPath;
}
set
{
tracedPath = value;
}
}
public double TracedPathTop
{
get
{
return tracedPathTop;
}
set
{
tracedPathTop = value;
}
}
public double TracedPathLeft
{
get
{
return tracedPathLeft;
}
set
{
tracedPathLeft = value;
}
}
public void NotifyCanvas() //Method being called when pressing an update button
{
NotifyPropertyChanged("TracedPathTop");
NotifyPropertyChanged("TracedPathLeft");
NotifyPropertyChanged("TracedPath");
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
ObservableCollection<Waypoint> waypointList = new ObservableCollection<Waypoint>();
public ObservableCollection<Waypoint> WaypointList
{
get
{
return waypointList;
}
set
{
waypointList = value;
NotifyPropertyChanged("WaypointList");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Here is the polylineModel class I made (similar to the one present upwards):
class WayPointPolyline : INotifyPropertyChanged
{
SolidColorBrush tracedPathColour;
PointCollection tracedPath;
double tracedPathTop;
double tracedPathLeft;
public SolidColorBrush TracedPathColour
{
get
{
return tracedPathColour;
}
set
{
tracedPathColour = value;
NotifyPropertyChanged("TracedPathColour");
}
}
public PointCollection TracedPath
{
get
{
return tracedPath;
}
set
{
tracedPath = value;
NotifyPropertyChanged("TracedPath");
}
}
public double TracedPathTop
{
get
{
return tracedPathTop;
}
set
{
tracedPathTop = value;
NotifyPropertyChanged("TracedPathTop");
}
}
public double TracedPathLeft
{
get
{
return tracedPathLeft;
}
set
{
tracedPathLeft = value;
NotifyPropertyChanged("TracedPathLeft");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
However in the class called Waypoint
I want to replace PointCollection with:
public List<WayPointPolyline > TracedPaths
{
get
{
return tracedPaths;
}
set
{
tracedPaths = value;
}
}
The xaml is where the hard part comes, since currently it adds only a single pointcollection per class addded in the List, what I need is a List where you add x classes, class x can contain data for y lines. Any idea what to do?
Thanks on advance!
Credits to Chris Eelmaa for the hint!
Xaml should look like this: I have not noticed any drastic difference in performance. However as an amatuer it would be interesting knowing if the code below is "too messy"
<Canvas Name="PolyLineCanvas" Width ="100" Height="100">
<ItemsControl ItemsSource="{Binding WaypointList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,NotifyOnTargetUpdated=True}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding TracedPathList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,NotifyOnTargetUpdated=True}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=TracedPathLeft, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Canvas.Top" Value="{Binding Path=TracedPathTop, UpdateSourceTrigger=PropertyChanged}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Polyline StrokeDashArray="{Binding TracedPathDashStyle}" Stroke="{Binding TracedPathColour}" Points="{Binding TracedPath}" StrokeThickness="0.0244"></Polyline>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
Related
I have a simple form that as a dynamic set of Parent Labels ( could be 1 -10 labels ) that is updated on a timer, if all is good these labels stay green like:
If however one of the parents has a status change, i am trying to then display the offending child or childs and result in somewthing like this:
then once status returns to normal revert back to the original layout ( as above )
so currently i have a view like this :
<Grid>
<ItemsControl ItemsSource = "{Binding Path = CIs}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Label Content = "{Binding Path = NodeName, Mode = OneWay}"
Background = "{Binding Path = NodeStatus, Mode = OneWay}"
Tag="{Binding Path = Nodeid, Mode = OneWay}"
Foreground="White"
FontFamily="Arial Black"
HorizontalContentAlignment="Center"
BorderBrush="Black"
BorderThickness="1,1,1,1"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
a viewmodel populating the view with a simple add:
if (Node.level == 3)
{
CIs.Add(new CI { NodeName = Node.name, NodeStatus = Node.status, Nodeid = Node.id });
}
and the basic model :
public class CIModel {}
public class CI : INotifyPropertyChanged {
private string nodeName;
private string nodeStatus;
private string nodeid;
public string NodeName {
get {
return nodeName;
}
set {
if (nodeName != value) {
nodeName = value;
RaisePropertyChanged("NodeName");
}
}
}
public string Nodeid
{
get
{
return nodeid;
}
set
{
if (nodeid != value)
{
nodeid = value;
RaisePropertyChanged("Nodeid");
}
}
}
public string NodeStatus
{
get
{
return nodeStatus;
}
set
{
if (nodeStatus != value)
{
nodeStatus = value;
RaisePropertyChanged("NodeStatus");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
would creating a child view somehow on the parent status change be a possible way? or can i create all the parent and childs and toggle there visibility when there status changes?
Thanks
Did you mean something like this?
// Put this in MainWindow()
public MainWindow()
{
InitializeComponent();
new Demo(this);
}
// Demo code
public class Demo
{
public Demo(FrameworkElement view)
{
View = view;
View.DataContext = this;
StartDemo();
}
private FrameworkElement View { get; }
public ObservableCollection<Parent> Parents { get; } = new ObservableCollection<Parent>();
public async void StartDemo()
{
var delay = 500;
foreach (var index in Enumerable.Range(0, 5))
{
var item = new Parent { Name = $"Parent {index + 1}" };
Parents.Add(item);
await Task.Delay(delay);
}
// Add errors
for (var i = 0; i < 3; i++)
{
Parents[1].Errors.Add(new Child { Name = $"Child {i + 1}" });
await Task.Delay(delay);
}
// Remove errors
while (Parents[1].Errors.Any())
{
Parents[1].Errors.RemoveAt(Parents[1].Errors.Count - 1);
await Task.Delay(delay);
}
// Remove parents
while (Parents.Any())
{
Parents.RemoveAt(Parents.Count-1);
await Task.Delay(delay);
}
}
}
/// <summary>
/// Child (error item)
/// </summary>
public class Child
{
public string Name { get; set; }
}
/// <summary>
/// Parent
/// </summary>
public class Parent : INotifyPropertyChanged
{
public Parent()
{
System.Collections.Specialized.CollectionChangedEventManager.AddHandler(Errors,
delegate
{
OnPropertyChanged(nameof(Status));
});
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; OnPropertyChanged(); }
}
public string Status { get { return Errors.Any() ? "ERROR" : "OK"; } }
/// <summary>
/// Children/errors
/// </summary>
public ObservableCollection<Child> Errors { get; } = new ObservableCollection<Child>();
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
<!-- Xaml -->
<ItemsControl ItemsSource="{Binding Path=Parents}"
Grid.IsSharedSizeScope="True">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:Parent}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="ParentColumn" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- Parent label -->
<Label Content="{Binding Path=Name}"
x:Name="Label"/>
<!-- Errors -->
<ItemsControl ItemsSource="{Binding Path=Errors}"
Grid.Column="1">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:Child}">
<Label Content="{Binding Path=Name}"
Background="Red" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
<DataTemplate.Triggers>
<!-- Parent is ok -->
<DataTrigger Binding="{Binding Path=Status}"
Value="OK">
<Setter TargetName="Label" Property="Background" Value="Green" />
</DataTrigger>
<!-- Parent is not ok -->
<DataTrigger Binding="{Binding Path=Status}"
Value="ERROR">
<Setter TargetName="Label" Property="Background" Value="Red" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I'm working with a DataGrid in WPF and I'm trying to perform some data binding that it a little more complex than I'm used to. I have an ObservableCollection of a class that also implements an ObservableCollection of a subclass. I'm trying to bind the IsChecked property of a CheckBox to a value on that subclass and no matter when I try I can't seem to get it to work. Hopefully I'm just missing something simple.
In my main program I have the following, and it works fine for detecting changes to "SomeProperty" on the "MyDevice" class:
ObservableCollection<MyDevice> MyDevices = new ObservableCollection<MyDevice>();
DevicesGrid.ItemSource = MyDevices;
My class definition is below:
public class MyDevice : INotifyPropertyChanged
{
public class Input : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged([CallerMemberName] string PropertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
private bool _SyncDetected;
public bool SyncDetected
{
get { return _SyncDetected; }
set { _SyncDetected = value; RaisePropertyChanged(); }
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged([CallerMemberName] string PropertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
private bool _SomeProperty;
public bool SomeProperty
{
get { return _SomeProperty; }
set { _SomeProperty = value; RaisePropertyChanged(); }
}
public ObservableCollection<Input> MyInputs = new ObservableCollection<Input>() { new Input(), new Input() };
}
And this is my XAML:
<DataGrid x:Name="DevicesGrid" Margin="10,80,10,10" AutoGenerateColumns="False">
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="ContextMenu" Value="{StaticResource DeviceRowContextMenu}"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Sync/Hotplug" IsReadOnly="True" Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="2,2,2,2" VerticalAlignment="Center" HorizontalAlignment="Center">
<CheckBox Margin="2,2,2,2" IsHitTestVisible="False" IsChecked="{Binding MyInputs[0].SyncDetected}" Content="In1"/>
<CheckBox Margin="2,2,2,2" IsHitTestVisible="False" IsChecked="{Binding MyInputs[1].SyncDetected}" Content="In2"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I'm really new at working with WPF so any help is appreciated. Thanks.
Here is something wrong:
public ObservableCollection<Input> MyInputs = new ObservableCollection<Input>() { new Input(), new Input() };
MyDevice.MyInputs is a field, not a property, so the binding system cannot find it through reflection.
I tried to bind a property to a nested object, but it fails.
I have taken a look at those questions, but i think i made another mistake somewhere else. Maybe someone can give i hind.
WPF: How to bind to a nested property?
binding to a property of an object
To upper slider/textbox has a correct binding while the lower one fails to do so.
I have two sliders with corrosponding textboxes:
<StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox Text="{Binding Path= boundnumber, Mode=TwoWay, FallbackValue='binding failed'}" ></TextBox>
<Slider Value="{Binding Path= boundnumber, Mode=TwoWay}" Width="500" Maximum="1000" ></Slider>
</StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" DataContext="{Binding Path=myDatarow}">
<TextBox Text="{Binding Path= boundnumber, Mode=TwoWay, FallbackValue='binding failed'}" ></TextBox>
<Slider Value="{Binding Path= boundnumber, Mode=TwoWay}" Width="500" Maximum="1000" ></Slider>
</StackPanel>
</StackPanel>
Code behind:
public partial class MainWindow : INotifyPropertyChanged
{
public MainWindow()
{
DataContext = this;
InitializeComponent();
}
private int _boundnumber;
public int boundnumber
{
get { return _boundnumber; }
set
{
if (value != _boundnumber)
{
_boundnumber = value;
OnPropertyChanged();
}
}
}
Datarow myDatarow = new Datarow(11);
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
class Datarow : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
public Datarow()
{
}
public Datarow(int number)
{
boundnumber = number;
}
private int _boundnumber;
public int boundnumber
{
get { return _boundnumber; }
set
{
if (value != _boundnumber)
{
_boundnumber = value;
OnPropertyChanged();
}
}
}
}
You need to expose your myDatarow into a public property like your boundnumber.
private DataRow _myDatarow = new DataRow(11);
public DataRow myDataRow
{
get { return _myDatarow; }
}
And just an additional advice.
It's better to separate your DataContext class from the MainWindow.
I have the following user control XAML:
<UserControl x:Class="WpfEditorTest.PipelineView"
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:local="clr-namespace:WpfEditorTest"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ItemsControl ItemsSource="{Binding Processors}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:EditorWindow WindowResize="EditorWindow_WindowResize">
<StackPanel>
<Label Content="{Binding Name}"/>
<Label Content="{Binding X}"/>
<Label Content="{Binding Y}"/>
</StackPanel>
</local:EditorWindow>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
DataContext of the usercontrol (set in constructor):
DataContext = new Pipeline("Pipeline1")
{
Processors =
{
new Processor("Add1"),
new Processor("Add2"),
}
};
Minimal versions of used (view)models:
public class Pipeline : Processor
{
private ObservableCollection<Processor> m_Processors = new ObservableCollection<Processor>();
public ObservableCollection<Processor> Processors
{
get
{
return m_Processors;
}
}
public Pipeline(string name) : base(name)
{
}
}
public class Processor : NotifierBase
{
private string m_Name;
public string Name
{
get { return m_Name; }
set { m_Name = value; OnPropertyChanged("Name"); }
}
private double m_X;
public double X
{
get { return m_X; }
set { m_X = value; OnPropertyChanged("X"); }
}
private double m_Y;
public double Y
{
get { return m_Y; }
set { m_Y = value; OnPropertyChanged("Y"); }
}
public Processor(string name)
{
Name = name;
}
}
public abstract class NotifierBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion INotifyPropertyChanged Members
}
In this case, my DataContext (of the usercontrol itself) is an object with an ObservableCollection<> Processors, each processor has a Name, X and Y property. The EditorWindow also has a Name, X and Y property. How do i make it so the labels in the stackpanel show the value's of the DataContext of the usercontrol.
Result:
Where it says 'EditorWindowControl' it should say 'Add1' or 'Add2', the current text is the Name property of the EditorWindow instance, not from the current item in the datacontext (processor) collection
Thank you for reading my question
Edit:
I changed the propertyname from Name to ProcessorName, and set the bind to "{Binding ProcessorName}" but now the binding fails (label is empty). So this means the way it binds is wrong, but I still don't know where it goes wrong.
The mistake was in the EditorWindow control, in the constructor it sets the DataContext to itself, which overrides all other bindings from there on (apparently). After removing it the databinding worked.
Thanks to #dkozl for pointing this out
I am using MVVM and trying to represent my ViewModel data in View.
I have a class called Track containing list of Variations. I want to represent each variation as a TextBlock using data binding.
I am able to represent a single track as:
<Window.Resources>
<src:Track x:Key="trck"/>
...
</Window.Resources>
<StackPanel DataContext="{Binding Source={StaticResource trck}}" Orientation="Horizontal">
<ItemsControl ItemsSource="{Binding Vars}" Height="53" Width="349">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Background="{Binding Path=color}" Height="15" Width="{Binding Path=elapsedtime}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
I also have a class called TrackList containing collection of Tracks.
I tried to use HierarchicalDataTemplate to represent Hierarchical Data of TrackList.
But it's not working..
I am new to WPF, and I have tried the below things so far:
<DockPanel.Resources>
<DataTemplate DataType="{x:Type src:Variation}">
<TextBlock Background="{Binding Path=color}" Height="15" Width="{Binding Path=elapsedtime}"/>
</DataTemplate>
<HierarchicalDataTemplate DataType = "{x:Type src:Track}" ItemsSource = "{Binding Path=Vars}">
<StackPanel/>
</HierarchicalDataTemplate>
</DockPanel.Resources>
public class TrackList : ViewModel
{
private ICollection<Track> tracks;
private Track selectedTrack;
public string Name
{ get; set; }
public TrackList()
{
this.tracks = new List<Track>();
this.tracks.Add(new Track("T1"));
this.tracks.Add(new Track("T2"));
Name = "Track List";
selectedTrack = tracks.ElementAt(1);
}
public ICollection<Track> Tracks
{
get { return this.Tracks; }
set { this.Tracks = value; }
}
public Track SelectedTrack
{
get { return this.selectedTrack; }
set
{
if (this.selectedTrack != value)
{
this.selectedTrack = value;
this.OnPropertyChanged("SelectedTrack");
}
}
}
}
public class Track : ViewModel
{
private ICollection<Variation> vars;
private Variation selectedVar;
public string Name { get; set; }
public Track()
{
Init();
}
public Track(string p)
{
// TODO: Complete member initialization
this.Name = p;
Init();
}
private void Init()
{
this.vars = new List<Variation>();
this.vars.Add(new Variation("var1", 20, Brushes.Red));
this.vars.Add(new Variation("var2", 60, Brushes.Green));
this.vars.Add(new Variation("var3", 40, Brushes.Khaki));
this.vars.Add(new Variation("var4", 120, Brushes.Aqua));
selectedVar = vars.ElementAt(1);
}
public ICollection<Variation> Vars
{
get { return this.vars; }
set { this.vars = value; }
}
public Variation SelectedVar
{
get { return this.selectedVar; }
set
{
if (this.selectedVar != value)
{
this.selectedVar = value;
this.OnPropertyChanged("SelectedVar");
}
}
}
}
public class Variation : ViewModel
{
public int elapsedtime { get; set; }
public string Name { get; set; }
public System.Windows.Media.Brush color { get; set; }
public Variation(string varname)
{
Name = varname;
}
public Variation(string name, int time, System.Windows.Media.Brush br)
{
// TODO: Complete member initialization
this.Name = name;
this.elapsedtime = time;
this.color = br;
}
}
public abstract class ViewModel : INotifyPropertyChanged
{
private readonly Dispatcher _dispatcher;
protected ViewModel()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected Dispatcher Dispatcher
{
get { return _dispatcher; }
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChanged(this, e);
}
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
}
Please let me know for any farther information.
Thanks
I don't think you need HierarchicalDataTemplate, your tree has known number of levels (TrackList>Track>Variation). You can simply do this:
<DockPanel.Resources>
<DataTemplate DataType="{x:Type src:Variation}">
<TextBlock Background="{Binding Path=color}" Height="15" Width="{Binding Path=elapsedtime}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type src:Track}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<ItemsControl ItemsSource="{Binding Vars}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</DataTemplate>
</DockPanel.Resources>
<ItemsControl ItemsSource="{Binding Tracks}" />
Where ItemsControl bind to Tracks property of the TrackList (ItemsControl.DataContext = TrackList).
You can represent your hierarchical data using a TreeView:
<TreeView ItemsSource="{Binding Tracks}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type src:Track}" ItemsSource="{Binding Vars}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>