There is a collection of categories with products.
Each category is represented in the interface by the AvalonDock tab, which has a DataGrid with products.
Now when switching from tab to tab, DataGrid updates the collection every time. If you select a pair of rows in the table on the first tab, switch to the second tab and return to the first one, the selection disappears.
What could be the problem?
XAML:
<xcad:DockingManager DocumentsSource="{Binding Examples}">
<xcad:DockingManager.LayoutItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Content.Items}"
SelectionMode="Extended" />
</DataTemplate>
</xcad:DockingManager.LayoutItemTemplate>
<xcad:LayoutRoot />
</xcad:DockingManager>>
Code-behind:
public partial class MainWindow : Window
{
public class Example
{
public List<int> Items { get; } = new List<int>();
public Example()
{
for (var i = 0; i < 10; i++)
{
Items.Add(i);
}
}
}
public List<Example> Examples { get; } = new List<Example>();
public MainWindow()
{
InitializeComponent();
DataContext = this;
Examples.Add(new Example());
Examples.Add(new Example());
}
}
As #nobody suggested, switching between tabs seems to update the layout, and the selection state is lost. If UI can't persist the selection state, then you can use the next layer i.e. presentation or view-model to do the same.
In this case, adding a IsSelected property to view-model item and a binding to ListViewItem should do the trick.
XAML:
<Grid>
<xcad:DockingManager DocumentsSource="{Binding Examples}">
<xcad:DockingManager.DocumentHeaderTemplate>
<DataTemplate>
<TextBlock Text="Doc" />
</DataTemplate>
</xcad:DockingManager.DocumentHeaderTemplate>
<xcad:DockingManager.LayoutItemTemplate>
<DataTemplate>
<ListBox
DisplayMemberPath="Value"
ItemsSource="{Binding Content.Items}"
SelectionMode="Extended">
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="LightBlue" />
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</ListBox.Resources>
</ListBox>
</DataTemplate>
</xcad:DockingManager.LayoutItemTemplate>
<xcad:LayoutRoot />
</xcad:DockingManager>
</Grid>
Code-behind:
public partial class MainWindow : Window
{
public class ExampleItem
{
public int Value { get; set; }
public bool IsSelected { get; set; }
}
public class Example
{
public List<ExampleItem> Items { get; } = new List<ExampleItem>();
public Example()
{
for (var i = 0; i < 10; i++)
{
Items.Add(new ExampleItem { Value = i });
}
}
}
public List<Example> Examples { get; } = new List<Example>();
public MainWindow()
{
InitializeComponent();
DataContext = this;
Examples.Add(new Example());
Examples.Add(new Example());
}
}
Related
Im using DevExpress and Prism in my application which Im new to both. Im trying to access "MyText" in the content item I create in my viewmodel. Currently when this item is created in CreatedSelectionEventReceived() via the viewmodel I don't see this property show up in my parameter list while debugging. I would like to know how to access this once its been created so I can update the property when a property is updated NumGaugeValue via the viewmodel. Right now I can hard code a value for "MyText" but unable to bind to it.
ResourceDictionary.xaml
<ResourceDictionary
x:Class="MyProject.WPF.Resources.CustomShapes"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/charts"
xmlns:dxdiag="http://schemas.devexpress.com/winfx/2008/xaml/diagram"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns:dxga="http://schemas.devexpress.com/winfx/2008/xaml/gauges"
xmlns:ctrl="clr-namespace:MyProject.WPF.Controls"
xmlns:vm="clr-namespace:MyProject.WPF.ViewModels">
<Style x:Key="NumGaugeContentItem" TargetType="dxdiag:DiagramContentItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ctrl:NumberGauge MyText="22"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
MyView.xaml
<dxdiag:DiagramControl
x:Name="Diagram"
Width="{Binding ElementName=Dashboard, Path=ActualWidth}"
Height="{Binding ElementName=Dashboard, Path=ActualHeight}"
AllowAddRemoveItems="True"
AllowMoveItems="True"
AllowResizeItems="True"
CanvasSizeMode="Fill"
GridSize="25,25"
MaxZoomFactor="1"
MinZoomFactor="1"
ScrollMode="Content"
SelectedStencils="BasicShapes"
SelectionMode="Single"
ShowRulers="False"
ShowSelectionRectangle="False"
SnapToGrid="True"
SnapToItems="False"
ZoomFactor="1" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="Drop">
<prism:InvokeCommandAction Command="{Binding DiagramControlDropCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type dxdiag:DiagramControl}}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
MyViewModel.cs
public class MyViewModel: BindableBase
{
public string NumGaugeValue
{
get { return _numGaugeValue; }
set { SetProperty(ref _numGaugeValue, value); }
}
private DiagramControl DiagramCtrl { get; set; }
private Point CtrlPlacementCoordinates { get; set; }
public DelegateCommand<string> UpdateCommand { get; set; }
public DelegateCommand<DragEventArgs> DiagramControlDropCommand { get; set; }
public MyViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
UpdateCommand = new DelegateCommand<string>(Execute).ObservesProperty(() => NumGaugeValue);
DiagramControlDropCommand = new DelegateCommand<DragEventArgs>(HandleDropOnDxDiagram);
ItemSelectionCommand = new DelegateCommand<object>(ProcessSelectionCommand);
_eventAggregator.GetEvent<ControlSelectionEvent>().Subscribe(ControlSelectionEventReceived);
}
public MyViewModel() { }
private DiagramContentItem CreateDiagramItem(string styleId, Point position)
{
var ctrlItem = new DiagramContentItem() {CustomStyleId = styleId, Position = position};
return ctrlItem;
}
private void HandleDropOnDxDiagram(DragEventArgs sender)
{
DiagramCtrl = (DiagramControl)sender.Source;
CtrlPlacementCoordinates = sender.GetPosition(DiagramCtrl);
}
private void DoDragDrop(object sender)
{
// Grab the control from the accordion item and store as the control that was dropped
var item = (AccordionItem)sender;
var controlDropped = (ControlType)item.Items[0];
if (controlDropped.DataContext != null)
{
DragDrop.DoDragDrop(controlDropped, controlDropped.DataContext, DragDropEffects.Move);
}
}
private void ControlSelectionEventReceived(ControlSelectionMessageInfo controlName)
{
// Create the control that was selected dynamically
switch (controlName.SelectedControlName)
{
case "NumberGauge":
var numGauge = CreateDiagramItem("NumGaugeContentItem", CtrlPlacementCoordinates);
DiagramCtrl.Items.Add(numGauge);
break;
//other cases here but not relevant
}
}
}
I'm working on a small WPF project,
for now it contains one window which should display as much checkboxes are many values in lists are.
For testing purposes, before I get values from database I tried something like this:
public class StatusOption
{
public string name { get; set; }
public bool IsSelected { get; set; }
}
public void GetSerialNumbers()
{
List<StatusOption> serialNumbers = new List<StatusOption>();
for(int i = 0; i<10;i++)
{
StatusOption x = new StatusOption();
x.name = "Random name" + i;
x.IsSelected = false;
serialNumbers.Add(x);
}
}
And my xaml looks like this:
<ListBox x:Name="SerialNumbersListBox"
AllowDrop="True"
Grid.ColumnSpan="2"
Grid.Row="2"
ItemsSource="{Binding GetSerialNumbers}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding serialNumbers}"
IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But unfortunatelly nothing is displayed below textbox...
But for now everything is empty, and I can not find out why..
Thanks guys
Cheers
You could not bind a method. Please use property instead.
<ListBox HorizontalAlignment="Left" Height="171" Margin="334,96,0,0" VerticalAlignment="Top" Width="248" AllowDrop="True" x:Name="SerialNumbersListBox"
ItemsSource="{Binding SerialNumbers}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding name}"
IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
public class SerialNumbersListBoxViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public class StatusOption
{
public string name { get; set; }
public bool IsSelected { get; set; }
}
private ObservableCollection<StatusOption> _SerialNumbers;
public ObservableCollection<StatusOption> SerialNumbers
{
get
{
return _SerialNumbers;
}
set
{
if (value != _SerialNumbers)
{
_SerialNumbers = value;
OnPropertyChanged(nameof(SerialNumbers));
}
}
}
public void GetSerialNumbers()
{
if (_SerialNumbers == null)
_SerialNumbers = new ObservableCollection<StatusOption>();
for (int i = 0; i < 10; i++)
{
StatusOption x = new StatusOption();
x.name = "Random name" + i;
x.IsSelected = false;
_SerialNumbers.Add(x);
}
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public SerialNumbersListBoxViewModel()
{
GetSerialNumbers();
}
}
You can refer this link for more details
Regard!
You cannot bind to methods, you can only bind to Properties or DependencyProperties.
So you need to create a Property for your serialNumbers. You should also implement INotifyPropertyChanged, so that the ListBox can know when your property changed.
public List<object> SerialNumbers
{
get => this._serialNumbersProperty;
set
{
if (!List<object>.Equals(value, this._serialNumbersProperty))
{
this._serialNumbersProperty = value;
OnPropertyChanged(nameof(this.SerialNumbers));
}
}
}
<ListBox x:Name="SerialNumbersListBox"
AllowDrop="True"
Grid.ColumnSpan="2"
Grid.Row="2"
ItemsSource="{Binding SerialNumbers}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding name}"
IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm trying to make a ListBox with checkboxes into it.
In xaml I have:
<ListBox ItemsSource="{StaticResource ResourceKey=lstMaterialesCL}" SelectionMode="Multiple" Name="lstMaterial" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="chkMaterial" Content="{Binding DescCompuesta}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and my ListBox looks as:
It is ok, but look it, when I checked "Municipales" the item in the ListBox is not selected, and when I select in the ListBox "Industriales" it is not checked
If I inspect the items selected into the ListBox it don't coincide with the items Checked
foreach (var item in lstMaterial.SelectedItems)
{
MessageBox.Show(((MaterialesCL)item).DescCompuesta);
}
It shows me "Oficiales", "Industriales" and "Destrucciones" but the user was want select "Municipales" and "Destrucciones"
How I can to make coincide the ListBox items selected with the CheckBox checked if the CheckBox checked is mandatory?
XAML:
DescCompuestaList is a list of CheckListGeneric
<ListBox ItemsSource="{Binding DescCompuestaList}" >
<ListBox.ItemTemplate>
<HierarchicalDataTemplate>
<CheckBox Content="{Binding DescCompuesta}" IsChecked="{Binding IsChecked}"/>
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here your CheckListGeneric class
public class CheckListGeneric: ViewModelBase
{
#region ..:: Fields ::..
private bool _isChecked;
#endregion
#region ..:: Properties ::..
public long Id { get; set; }
public string DescCompuesta{ get; set; }
public bool IsChecked
{
get { return _isChecked; }
set { _isChecked = value; OnPropertyChanged("IsChecked"); }
}
#endregion
}
You can get all selected using a simple query
var selectedItems = DescCompuestaList.Where(x => x.IsChecked)
simple as life.
How about binding CheckBox's IsChecked property to ListBoxItem's IsSelected property.
Something like: IsChecked={Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}
In your example:
<ListBox ItemsSource="{StaticResource ResourceKey=lstMaterialesCL}" SelectionMode="Multiple" Name="lstMaterial" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="chkMaterial" Content="{Binding DescCompuesta}" IsChecked={Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
For me it's always easiest way to use Blend for making templates.
Open project in blend and make one listBox, then select that ListBox and add template like in picture.
just to show purpose i have add simple checkBox and TextBlock, and you can make it as u like it.
in ViewModel i have made simple observable collection just to show purpose and bound ItemsSource to Users:
public class TestVM
{
public ObservableCollection<User> Users { get; set; }
public TestVM()
{
Users = new ObservableCollection<User>
{
new User{ IsChecked=true, Name="User1" },
new User{ IsChecked=false, Name="User2" },
new User{ IsChecked=true, Name="User3" },
new User{ IsChecked=false, Name="User3" },
};
}
}
public class User
{
public bool IsChecked { get; set; }
public string Name { get; set; }
}
This way you can make any template you like.
Wow, I tested all your suggestions, thank you so much to all, after all tests, the solution how I need it is more or less like this:
On xaml:
<StackPanel Orientation="Horizontal">
<ListBox ItemsSource="{Binding MaterialesVM}" SelectionMode="Multiple"
Name="ListBoxMateriales" Width="300" Height="200"
HorizontalAlignment="Left" VerticalAlignment="Top">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding IsChecked, Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}"
Content="{Binding DescCompuesta}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="btnPrueba" Style="{StaticResource BotonContent}"
Content="Selected" Width="80" Height="30" HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10,0,0,0" Click="btnPrueba_Click"/>
<Button Name="btnLimpia" Style="{StaticResource BotonRechazar}"
Width="30" Height="30" Click="btnLimpia_Click" HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="5,0,0,0" ToolTipService.ToolTip="Limpia Todos"/>
<Button Name="btnMarca" Style="{StaticResource BotonAceptar}"
Width="30" Height="30" Click="btnMarca_Click" HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="5,0,0,0" ToolTipService.ToolTip="Selecciona Todos"/>
</StackPanel>
On this way I don't care on where clicked, the item will be selected or un-selected (on the CheckBox and on the ListItem)
And to see the items selected:
// To show the selected items
private void btnPrueba_Click(object sender, RoutedEventArgs e)
{
var selectedItems = MaterialesVM.Where(x => x.IsChecked);
foreach (var item in selectedItems)
{
MessageBox.Show(((MaterialesCL)item).DescCompuesta);
}
}
To select all items:
// To select all items
private void btnMarca_Click(object sender, RoutedEventArgs e)
{
var Items = ListBoxMateriales.Items;
foreach (MaterialesCL item in Items)
{
item.IsChecked = true;
}
}
To un-select all items:
// To un-select all items
private void btnLimpia_Click(object sender, RoutedEventArgs e)
{
var Items = ListBoxMateriales.Items;
foreach (MaterialesCL item in Items)
{
item.IsChecked = false;
}
}
and my classes are:
MaterialesCL.cs
public class MaterialesCL : INotifyPropertyChanged
{
public int Material { get; set; }
public string Descripcion { get; set; }
public string DescCompuesta { get; set; }
private bool _ischecked;
public bool IsChecked
{
get { return _ischecked; }
set
{
_ischecked = value;
OnPropertyChanged("IsChecked");
}
}
#region PropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
LstMaterialesCL.cs
public class LstMaterialesCL : ObservableCollection<MaterialesCL>, INotifyPropertyChanged
{
public LstMaterialesCL()
{
BasculaEntities _context = new BasculaEntities();
var Query = (from m in _context.Materiales
select new { m.Material, m.Descripcion}
).OrderBy(m => m.Material).ToList();
foreach (var item in Query)
{
this.Add(new MaterialesCL { Material = item.Material,
Descripcion = item.Descripcion, DescCompuesta = item.Material.ToString("000") + " - " + item.Descripcion,
IsChecked=false});
}
}
}
and on my UserControl MaterialesVM is an instance of LstMaterialesCL
LstMaterialesCL MaterialesVM = new LstMaterialesCL();
and so my test of ListBox with CheckBoxes works as I need.
Thank to all you I has learn so much.
I have already made some view with a LongListSelector, but now I have a really strange issue...
In fact, when I try to "tap" on my GroupHeader to my JumpList, my application throw an InvalidOperationException.
My container Model:
public class NextArrivalContainer<T> : List<T>
{
#region Properties
public string Destination { get; private set; }
public string Line { get; private set; }
#endregion //Properties
public NextArrivalContainer(string key, List<T> items)
: base(items)
{
if (key.Contains(' '))
{
int index = key.IndexOf(' ');
Line = key.Substring(0, index);
Destination = key.Substring(index + 1);
}
else
{
Destination = string.Empty;
Line = string.Empty;
}
}
}
My ViewModel Property:
private List<Model.NextArrivalContainer<string>> _trams;
public List<Model.NextArrivalContainer<string>> Trams
{
get { return (_trams); }
set
{
if (_trams != value)
{
_trams = value;
OnNotifyPropertyChanged("Trams");
}
}
}
My ViewModel where I fill the Property:
var tramGrouped = from item in trams
orderby item.Destination
group item by item.Destination into tramGroupedByDestination
select new Model.NextArrivalContainer<string>(tramGroupedByDestination.Key,
(from item in tramGroupedByDestination select item.Time).ToList());
Trams = new List<Model.NextArrivalContainer<string>>(tramGrouped);
And my View:
<phone:PivotItem Header="Tram">
<phone:LongListSelector ItemsSource="{Binding Trams}"
ItemTemplate="{StaticResource ItemTemplate}"
GroupHeaderTemplate="{StaticResource TramHeaderTemplate}"
JumpListStyle="{StaticResource JumpStyle}"
IsGroupingEnabled="True"
HideEmptyGroups="True"
LayoutMode="Grid" GridCellSize="70, 50"/>
</phone:PivotItem>
And his template:
<Style TargetType="phone:LongListSelector" x:Key="JumpStyle">
<Setter Property="LayoutMode" Value="List"/>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource backgroundConverter}}"
Width="450" Height="70">
<TextBlock Text="{Binding Destination}"
Foreground="{Binding Converter={StaticResource foregroundConverter}}"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
I am looking forward your answers.
Edit:
I just try something, my view was a UserControl, (I didn't know why I did it, but I did...)
So I try to changes to a phone:PhoneApplicationPage and It fix my issue.
If somebody can explain me why.
I hope that my question will help another developers.
I have a WPF TreeView populated by an observable collection using a hiarchialdatabinding
I need to access the item in my observable collection or the database that was used to populate it.
An example use case is that the user right clicks a treeview item to add a subgroup. I obviously need to access its parent to add the child.
Any suggestions? Im so lost..
I cant just edit the treeview item itself cause then the changes wont reflect back to my database
Database Code:
[Serializable]
public class LoginGroup
{
public string Name { get; set; }
public Guid ID { get; set; }
public List<Login> LoginItems = new List<Login>();
public List<LoginGroup> Children { get; set; }
}
public static ObservableCollection<LoginGroup> _GroupCollection = new ObservableCollection<LoginGroup>();
public ObservableCollection<LoginGroup> GroupCollection
{
get { return _GroupCollection; }
}
TreeView:
<TreeView x:Name="groupView" Width="211" TreeViewItem.Selected="OnTreeItemSelected" DockPanel.Dock="Left" Height="Auto" ItemsSource="{Binding GroupCollection}" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
You can just cast the SelectedItem to LoginGroup:
LoginGroup selectedGroup = (LoginGroup)groupView.SelectedItem;
You can't reflect back changed of your properties because they don't have way to "notice" back that they are edited. You need inherit LoginGroup from DependencyObject or implement INotifyPropertyChanged
You should use TreeView's ItemContainer style.
Here's sample TreeNode view model:
public class TreeNode : ViewModel
{
public TreeNode()
{
this.children = new ObservableCollection<TreeNode>();
// the magic goes here
this.addChildCommand = new RelayCommand(obj => AddNewChild());
}
private void AddNewChild()
{
// create new child instance
var child = new TreeNode
{
Name = "This is a new child node.",
IsSelected = true // new child should be selected
};
// add it to collection
children.Add(child);
// expand this node, we want to look at the new child node
IsExpanded = true;
}
public String Name
{
get { return name; }
set
{
if (name != value)
{
name = value;
OnPropertyChanged("Name");
}
}
}
private String name;
public Boolean IsSelected
{
get { return isSelected; }
set
{
if (isSelected != value)
{
isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
private Boolean isSelected;
public Boolean IsExpanded
{
get { return isExpanded; }
set
{
if (isExpanded != value)
{
isExpanded = value;
OnPropertyChanged("IsExpanded");
}
}
}
private Boolean isExpanded;
public ObservableCollection<TreeNode> Children
{
get { return children; }
}
private ObservableCollection<TreeNode> children;
public ICommand AddChildCommand
{
get { return addChildCommand; }
}
private RelayCommand addChildCommand;
}
Some comments:
ViewModel is any base implementation of INotifyPropertyChanged
interface.
RelayCommand (a.k.a. DelegateCommand) is ICommand implementation for use in MVVM approach.
Here's the view:
<Window x:Class="WpfApplication1.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">
<TreeView ItemsSource="{Binding}">
<TreeView.ItemContainerStyle>
<!-- Let's glue our view models with the view! -->
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<!-- Here's menu item, which is responsible for adding new child node -->
<MenuItem Header="Add child..." Command="{Binding AddChildCommand}" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Window>
... and sample data context initialization:
public MainWindow()
{
InitializeComponent();
DataContext = new ObservableCollection<TreeNode>
{
new TreeNode { Name = "Root", IsSelected = true }
};
}
Hope this helps.
Upd.
Of course, you have to expose child nodes as the ObservableCollection too. Otherwise, changes made to nodes collection won't be reflected.