Adding context menu to tree view by XAML only - c#

Trying to add a context menu to a TreeView with just xaml code.
Tv Show
Season 1
Season n
The context menu should only show when I right click a Season node.
Is that possible? I know how to solve it with code behind, but I'd like to learn to use WPF as it is intended. I have trouble finding out if I should be able to solve this with using only xaml.
Current xaml:
<TreeView
Grid.Row="1"
Grid.Column="0"
ItemsSource="{Binding TvShows}" x:Name="TvShowsTreeView"
SelectedItemChanged="TvShowsTreeViewOnSelectedItemChanged">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="tvShows:TvShow" ItemsSource="{Binding Seasons}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Try using the ItemTemplate property of HierarchicalDataTemplate. It should look like this:
<HierarchicalDataTemplate DataType="tvShows:TvShow" ItemsSource="{Binding Seasons}">
<TextBlock Text="{Binding Name}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="TypeOfSeasonInYourApplication">
<TextBlock Text="{Binding Name}">
<TextBlock.ContextMenu>
<ContextMenu>
<!-- Place MenuItems here -->
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
I actually didn't test that myself so please let me know if that works or not.

Related

WPF TreeView - Confusing data binding and style for child nodes

I am confused of WPFs data binding and style declaration for TreeViews, especially for child nodes.
My ViewModel contains an object with the following hierarchy:
- Component1
- SubcomponentA
- SubcomponentB
- Component2
- SubcomponentX
- SubcomponentY
- SubcomponentZ
I would like to modify the XAML file so I do not have to do anything within the .cs file.
This piece of code actually works:
<TreeView Name="tvComponent" ItemsSource="{Binding BpModule.BpComponentPrototypes.Elements}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding BpSubcomponents.Elements}">
<StackPanel Orientation="Horizontal">
<CheckBox Name="cb_run"></CheckBox>
<TextBlock Text="{Binding ShortName}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
However, I would like to create different styles for root and child nodes.
I tried different approaches with almost completely different XAML code. But the major problem was to describe the dependency of the binding of child nodes to their parent and so they remained empty during runtime.
Can you help me out?
Thank you.
In my opinion you can use the implicit DataTemplate mechanism (take a look here to the DataType property). In this way you can define more DataTemplates, each one of them "linked" to a specific Type.
<TreeView Name="tvComponent" ItemsSource="{Binding BpModule.BpComponentPrototypes.Elements}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:RootType}"ItemsSource="{Binding ...}">
...
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:ComponentType}" ItemsSource="{Binding BpSubcomponents.Elements}">
<StackPanel Orientation="Horizontal">
<CheckBox Name="cb_run"></CheckBox>
<TextBlock Text="{Binding ShortName}" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:SubcomponentType}">
...
</DataTemplate>
</TreeView.Resources>
</TreeView>
Otherwise you can always use a DataTemplateSelector to create your own logic which chooses the right template for you.
Well, somehow I achieved to provide different designs for root and children nodes. Here is the XAML code:
<TreeView Name="tvSoftwareComponentPrototypes" ItemsSource="{Binding Path=BpModule.BpComponentPrototypes.Elements}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding BpSubcomponents.Elements}">
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="cb_run"></CheckBox>
<Image Source="/Resources/SubComponent.png" Margin="5,0,3,0" />
<TextBlock Text="{Binding ShortName}" />
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="cb_swc" Checked="cb_swc_Checked" Unchecked="cb_swc_Unchecked"></CheckBox>
<Image Source="/Resources/Component.png" Margin="5,0,3,0" />
<TextBlock Text="{Binding ShortName}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
And the next problem is that I cannot access the Checkboxes at runtime.
WPF freaks me out :/
EDIT:
Hold on .. actually this is quite easy by changing the checkbox to the following XAML code:
<CheckBox Name="cb_swc" IsChecked="{Binding Path=PropertyName, Mode=TwoWay}"/>

How to bind properties of one ObservableCollection of ListView to properties of SelectedItem of another ListView?

So I have a few ListViews. The first is binded to ObservaleCollection<ComPort>. All properties of ComPort may take some predefined values. Other ListViews are responsible for that properties: they show all that possible (predefined) values and SelectedItem should be the current value of that property of ComPort from the first ObservaleCollection.
I can't attach images so here is an external picture, it would make the situation clean: http://i.stack.imgur.com/ZBRRx.png
<Window.Resources>
<ResourceDictionary x:Name="rd">
<l:ComPorts x:Key="vComPorts"/>
<l:SystemPorts x:Key="vSystemPorts"/>
<l:BaudRates x:Key="vBaudRate"/>
<l:Parities x:Key="vParities"/>
<l:DataBits x:Key="vDataBits"/>
<l:StopBits x:Key="vStopBits"/>
<l:Timeouts x:Key="vTimeouts"/>
<l:ComPort x:Key="vSelectedPort"/>
</ResourceDictionary>
</Window.Resources>
...
<ListView
Name="PortsList"
Grid.Row="1"
Grid.Column="0"
Margin="5"
VerticalAlignment="Stretch"
ItemsSource="{StaticResource vComPorts}"
DataContext="{StaticResource vComPorts}"
SelectedValuePath="PortName"
SelectedValue="{Binding ElementName=SystemPortsList, Path=SelectedItem.Value}"
SelectionChanged="PortsList_SelectionChanged"
MouseDoubleClick="PortsList_MouseDoubleClick">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox />
<TextBlock Margin="5,0,0,0" Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView
x:Name="SystemPortsList"
Margin="5"
VerticalAlignment="Stretch"
DataContext="{Binding Source={StaticResource vSelectedPort}}"
ItemsSource="{Binding Source={StaticResource vSystemPortsView}}"
SelectedItem="{Binding Source={StaticResource vSelectedPort}, Path=PortName}"
MouseEnter="SystemPortsList_Refresh"
MouseLeave="SystemPortsList_Refresh"
Grid.Row="1"
Grid.Column="1" SelectionChanged="SystemPortsList_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="tb" Margin="5,0,0,0" Text="{Binding Path=Name}" />
</StackPanel>
</ListView.ItemTemplate>
</ListView>
I've tried to make an instance of class ComPort for saving current value of selected item from the first ListView, but anyway I can't cope with it without help. How this task should be solved?
1) Instead of handling SelectionChanged on the PortsList ListView, bind your checkbox to the ListViewItemsPanel like so:
<CheckBox IsChecked={Binding IsSelected, RelativeSource=Parent/>
2) Add an x:Name to your first ListBox, say x:Name="ComPortLB";
3) Remove DataContext on SystemPortsList;
4) Fix SelectedItem on SystemPortsList like so:
SelectedValue="{Binding ElementName=ComPortLB, Path=SelectedValue.PortName}"
I haven't tested any of this code and I haven't done this kind of stuff for a while, so I apologize for errors, but it should get you closer. I've also had to make some assumptions about your classes since you don't provide enough information.

How to bind a list of list to a ListView control

I have The following structure
QPage class Object contains a List<List<QLine>>
QLine object contains List<Qword>
every list of words constructs a line and every list of lines consists a group(paragraph) and every list of paragraphs consists a page.
I want to bind the page to structure like this in XAML
<ListView>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock>
</TextBlock>
</StackPanel>
</StackPanel>
</ListView>
where each item of the ListView is a paragraph(List<QLine>) and each vertical stack panel holds an item of the List<QLine> and each item of the horizontal stack panel holds an item of the List<Qword> and the texblock is bound to Qword.text property. I have no idea how to do such binding from the XAML code.
Hopefully I did not miss some list but this should work. Basically it's a ListBox that hosts List<List<QLine>> (called it QPageList). Then you have ItemsControl that hosts each List<QLine> in vertical panel and finally there is another ItemsControl that hosts List<Qword> from QLine (called it QwordList) where each QWord is displayed as TextBlock on horizontal StackPanel
<!-- ItemsSource: List<List<QLine>>, Item: List<QLine> -->
<ListBox ItemsSource="{Binding QPageList}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- ItemsSource: List<QLine>, Item: QLine -->
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- ItemsSource: QLine.List<QWord>, Item: QWord -->
<ItemsControl ItemsSource="{Binding QwordList}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- Item: QWord -->
<TextBlock Text="{Binding text}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What you are looking for is ListView.ItemTemplate. Basically, you need to provide your list with a way to understand the nested data structure of your rows.
Here is a good tutorial to get you started on ItemTemplates.
Once your list has an item template then you just bind the ListView directly to your data source and that's it.
Hopefuly this will prove helpful. Taken from here
Authors (list)
- - Name
- - Books (list)
| - - Title
| - - Contents
Sample code :
<Window.Resources>
<DataTemplate x:Key="ItemTemplate1">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ItemTemplate2">
<StackPanel>
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource AuthorDataSource}}">
<ListBox x:Name="AuthorList" ItemTemplate="{DynamicResource ItemTemplate1}" ItemsSource="{Binding Authors }" >
<ListBox x:Name="BookList" DataContext="{Binding SelectedItem, ElementName=AuthorList}" ItemsSource="{Binding Books }" ItemTemplate="{DynamicResource ItemTemplate2}" />
<TextBlock x:Name="BookContent" DataContext="{Binding SelectedItem, ElementName=BookList}" Text="{Binding Contents }" />
</Grid>
Forward to what Alex is saying, it'd be a good idea to Encapsulate (If that's the correct word here) the object within classes, i.e.:
public class Page
{
public List<Paragraph> Paragraphs { get; set; }
}
public class Paragraph
{
public List<QWord> Sentences { get; set; }
}
public class Sentence
{
public List<QWord> Words { get; set; }
}
That'd help when you bind data in your XAML, i.e. if you look at the tutorial which Alex provided:
<TextBlock Text="Name: " />
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
<TextBlock Text="{Binding Age}" FontWeight="Bold" />
<TextBlock Text=" (" />
<TextBlock Text="{Binding Mail}" TextDecorations="Underline" Foreground="Blue" Cursor="Hand" />
<TextBlock Text=")" />
Hope that helps you.

Binding Dictionary<string,List<Class>> to TreeView

I have collection
Dictionary<string, List<Manager>> Stuff;
Manager is class with some properties.
I would like to bind this dictionary to TreeView or ListView like this:
Key as title, then list of Managers as children. For example:
Director (it's key from dictionary)
John (it's property Manager.Name)
Steve
Owner
Jack
I tried something like this:
<TreeView ItemsSource="{Binding Stuff}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate>
<TextBlock Foreground="Red" Text="{Binding Key}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
It shows me titles but I don't know how to make it further.
Or maybe it will be better to change collection and bind it in some other way.
EDIT
I unnecessarily complicated job with this dictionary. I created a class Stuff with property string Name;, and List<Managers> Managers;.
Use it in main class as ObservableCollection<Stuff> Stuff; and it works fine with this XAML:
<TreeView ItemsSource="{Binding Stuff}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Managers}">
<TextBlock Foreground="Red" Text="{Binding Name}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
So yeah using Dictionary wasn't best in this case.
Try this :
<TreeView Name="treeView1" ItemsSource="{Binding Stuff}" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Value}">
<TextBlock Foreground="Red" Text="{Binding Path=Key}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Try this:
<TreeView ItemsSource="{Binding Stuff}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Values}">
<TextBlock Foreground="Red" Text="{Binding Key}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
However, I'd always recommend using an ObservableCollection<CustomDataType> as the ItemsSource because it just makes the whole job simpler. For more help with the HierarchicalDataTemplate, please see the HierarchicalDataTemplate Class page on MSDN.

Hirearchial Data Template RadTreeView issue

I want to bind data to radtreeview through Hireachical Data Template. With Wpf treeview Its working. We wanted to change that to Radtreeview. When i am trying to achieve the same i am not getting that.
<TreeView Name="treeview2"
Grid.RowSpan="2" Tag=""
Grid.ColumnSpan="2"
ItemContainerStyle="{StaticResource StretchTreeViewItemStyle}" ItemsSource="{Binding Path=Cluster}" Width="250" Height="251" Margin="0,0,0,0" DockPanel.Dock="Bottom">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Nodes}">
<DockPanel LastChildFill="True">
<TextBlock Padding="15,0,30,0" Text="{Binding Path=numitems}" TextAlignment="Right" DockPanel.Dock="Right"/>
<TextBlock Text="{Binding Path=Text}" DockPanel.Dock="Left" TextAlignment="Left">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Rename" />
<MenuItem Header="Exlcude"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DockPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
I am looking for a sample which shows that bind a property. Cluster is a observablecollection property of type a class. Nodes is a child collection with in that. I am looking for transforming the same code to radtreeview-- Thanks

Categories