Powershell and WPF Treeview - wpf

I'm currently working on a powershell tool where I need to create a gui. It seems that according to my needs I would need to use WPF instead of Windows Form. The treeview control in windows forms doesn't let you customize the treeview items. Here is a sample of what I need :
Basically I would need to add treeviewitems on the fly. According to the nodeLevel, I would need to apply different image and progress bar. I would also need to be able to change the visibility of these controls. And all of these will be accomplished using powershell.
Can someone show me a direction, how should I approach this ? How/where should I start ?

You can use standard XAML for WPF to create window with arbitrary controls, events, styles and so on. Then call XamlReader.Load() to create a WPF Window object and Window.ShowDialog() to show it.
# WPF Window with XAML
[xml]$xaml = #"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="WPF Window from PowerShell" WindowStartupLocation = "CenterScreen"
Width = "800" Height = "600" ShowInTaskbar = "True">
<TreeView>
<TreeViewItem Header="Group 1">
<TreeViewItem Header="Item 1">
<StackPanel Orientation="Horizontal">
<Image Source="image.png" />
<TextBlock Text="Level 2.0" />
<ProgressBar Minimum="0" Maximum="100" Name="Progress" Width="100" IsIndeterminate="True"/>
<Button>Start</Button>
</StackPanel>
</TreeViewItem>
<TreeViewItem Header="Item 1"></TreeViewItem>
<TreeViewItem Header="Item 1"></TreeViewItem>
</TreeViewItem>
<TreeViewItem Header="Group 2">
<TreeViewItem Header="Item 1"></TreeViewItem>
<TreeViewItem Header="Item 1"></TreeViewItem>
<TreeViewItem Header="Item 1"></TreeViewItem>
</TreeViewItem>
</TreeView>
</Window>
"#
$XmlNodeReader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load($XmlNodeReader)
$Window.ShowDialog()

Related

WPF: Scrollviewer not limiting content to size of window

I have a treeview with a scrollviewer. When the treeview becomes to full with treenodes i want the scrollbar to show up. But no matter how big the treeview gets it never shows up. The treeview grows outside of window without limiting itself to staying inside window.
The structure is currently:
MainWindow contains a Frame that displays a page, the page contains a usercontrol, the usercontrol contains a treeview.
The usercontrol is set to "stretch", but instead of stretching to fit it's parent (limiting the space and thus making scrollbar appear), it stretches to fit all it's children (and thus stretching outside of screen).
How would i go on about making the "auto" sizing limiting itself to it's parent, instead of making it showing all children?
How i would like it to look/work like
How it actually looks/works like
Code, kinda irrelevant, i just wanna know how i should apply scrollview:
MainWindow:
<Frame Source="View/Pages/StartPage.xaml" x:Name="MainFrame" NavigationUIVisibility="Hidden"/>
</DockPanel>
MainPage:
<Grid>
<Frame Source="ParamFrameV.xaml" x:Name="pageFrame" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
ParamFrameV (the usercontrol):
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled" VerticalAlignment="Top" MaxHeight="I WANNA LIMIT HEIGHT SO THAT IT WONT GO OFF SCREEN" Width="283">
<TreeView ItemsSource="{Binding Nodes}" ItemContainerStyle="{StaticResource TreeViewItemExpandedStyle}">
//irrelevant code for this question
</TreeView>
</ScrollViewer>
that works just fine for me:
<Grid>
<ScrollViewer Height="{Binding ElementName=ParentGridName, Path=ActualHeight"}" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled" VerticalAlignment="Top" Width="283">
<TreeView Width="50" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<TreeViewItem Header="hi"></TreeViewItem>
<TreeViewItem Header="hi2"></TreeViewItem>
<TreeViewItem Header="hi3"></TreeViewItem>
<TreeViewItem Header="hi4"></TreeViewItem>
<TreeViewItem Header="hi5"></TreeViewItem>
<TreeViewItem Header="hi6"></TreeViewItem>
<TreeViewItem Header="hi7"></TreeViewItem>
<TreeViewItem Header="hi8"></TreeViewItem>
</TreeView>
</ScrollViewer>
</Grid>
Note:
scroling on the treeview itself will not scroll as it will capture your scroll event but i bet there is a way around this

How to add TreeView to AvalonDock?

I am using perfect library AvalonDock and would like to show TreeView inside docking layout. So my TreeView should be dockingable.
I cannot figured out how TreeView should be added to AvalonDock. For example, I have standard layout.
I've tried this old approach, however this code is not working as I'm using AvalonDock 2.0 and there is no ResizingPanel, DockableContent:
<avalonDock:ResizingPanel Orientation="Horizontal">
<avalonDock:DockablePane>
<avalonDock:DockableContent x:Name="fileFrame" Title="File List">
<TreeView Name="fileTree"/>
</avalonDock:DockableContent>
<avalonDock:DockableContent x:Name="viewFrame" Title="View List">
<TreeView Name="viewTree"/>
</avalonDock:DockableContent>
</avalonDock:DockablePane>
</avalonDock:ResizingPanel>
My goal is to have TreeView at the left side at start of program like in Visual Studio:
How to add TreeView to AvalonDock to see TreeView at start of MainWindow?
Edit:
Now I can see TreeView in Visual Studio:
However, there is no TreeView in started program(just yellow screen):
How to show TreeView with dummy data at the left side at start of program like in Visual Studio?
You can't add a control directly to the LayoutAnchorablePane - you have to wrap it in a LayoutAnchorable:
<avalonDock:DockingManager x:Name="dockManager" >
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Vertical">
<avalonDock:LayoutDocumentPane/>
<avalonDock:LayoutAnchorablePane Name="ToolsPane" DockHeight="150">
<avalonDock:LayoutAnchorable>
<TreeView Name="viewTree"/>
</avalonDock:LayoutAnchorable>
</avalonDock:LayoutAnchorablePane>
</avalonDock:LayoutPanel>
</avalonDock:LayoutRoot>
</avalonDock:DockingManager>
Edit:
If you want your treeview on the leftside, here a snippet with some dummy data:
<avalonDock:DockingManager x:Name="dockManager">
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Horizontal">
<avalonDock:LayoutAnchorablePane Name="ToolsPane" DockWidth="150">
<avalonDock:LayoutAnchorable>
<TreeView Name="viewTree">
<TreeViewItem Header="North America">
<TreeViewItem Header="USA" />
<TreeViewItem Header="Canada" />
<TreeViewItem Header="Mexico" />
</TreeViewItem>
<TreeViewItem Header="South America">
<TreeViewItem Header="Argentina" />
<TreeViewItem Header="Brazil" />
<TreeViewItem Header="Uruguay" />
</TreeViewItem>
</TreeView>
</avalonDock:LayoutAnchorable>
</avalonDock:LayoutAnchorablePane>
<avalonDock:LayoutDocumentPane />
</avalonDock:LayoutPanel>
</avalonDock:LayoutRoot>
</avalonDock:DockingManager>

How to Create DropdownList with CheckBox in WPF application?

I am new to WPF. I wan to create a Dropdown List which will contain CheckBox items in to it as show in image. Is it Possible?
This is not the perfect solution to your question, but maybe it helps you anyway.
(You don't have to use <Canvas> but i like it because it's more comfortable to place elements)
<Canvas>
<ListBox Canvas.Left="280" Canvas.Top="40" Width="170">
<ListBoxItem>
<TreeView>
<TreeViewItem Header="Outboard">
<TreeViewItem Header="Generic">
<CheckBox>Bronze</CheckBox>
<CheckBox>Clear</CheckBox>
</TreeViewItem>
<TreeViewItem Header="Guardian">
<CheckBox>Clear</CheckBox>
<CheckBox>UltraWhite</CheckBox>
</TreeViewItem>
</TreeViewItem>
</TreeView>
</ListBoxItem>
</ListBox>
</Canvas>
Sry can't post a picture yet because i don't have enough Reputations.
So i uploaded it.
http://imageshack.us/scaled/thumb/849/examplezt.png
I used a Listbox instead of a Combobox and you only can check the latest items.

DataBinding to selected TreeViewItem only if child of other TreeViewItem

I have a custom class (NewBlockLabelInfo) with an observable collection of another custom class (DoorControllerLabelInfo) I've successfully databound the NewBlockLabelInfo class to the treeview, and everything displays fine.
I have a lot of textboxs that are data bound to certain properties, and updating these reflects in the treeview.
I'd like to databind one set of textboxs for the properties, to the selected item in the treeview IF the selected item is a child of the specified treeviewitem (Observable Collection, Door Controllers)
The Data Context is specified at the window level.
I've looked long and hard for a way to do this, let alone the best way.
Heres the WPF XAML for the TreeView
<TreeView Margin="12,150,582,16" Name="treeView1">
<TreeViewItem Header="{Binding Path=BlockName}" Style="{StaticResource BlockItem}" IsExpanded="True">
<TreeViewItem Style="{StaticResource PhoneNoItem}" Header="{Binding Path=TelephoneNumber}"/>
<TreeViewItem Style="{StaticResource DataNoItem}" Header="{Binding Path=DataNumber}"/>
<TreeViewItem Style="{StaticResource CompanyItem}" Header="{Binding Path=CompanyName}"/>
<TreeViewItem Style="{StaticResource ConnectedItem}" Header="{Binding Path=ConnectedDC}" />
<TreeViewItem IsExpanded="True" Header="Door Controllers" Foreground="#FF585858" ItemsSource="{Binding Path=DoorControllers, UpdateSourceTrigger=PropertyChanged}" Name="DCTreeViewItem" Selected="DCTreeViewItem_Selected">
<TreeViewItem.ItemTemplate>
<HierarchicalDataTemplate>
<TreeViewItem Header="{Binding Path=DCName}" Style="{StaticResource DCItem}" IsExpanded="True" Selected="DCTreeViewItem_Selected" >
<TreeViewItem Header="{Binding Path=Address}" Style="{StaticResource AddressItem}" />
<TreeViewItem Header="{Binding Path=Channel1}" Style="{StaticResource Door1Item}" />
<TreeViewItem Header="{Binding Path=Channel2}" Style="{StaticResource Door2Item}" />
</TreeViewItem>
</HierarchicalDataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
<TreeViewItem IsExpanded="True" Header="Flats" Foreground="#FF585858" ItemsSource="{Binding Path=FlatNames, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<TreeViewItem.ItemTemplate>
<DataTemplate>
<TreeViewItem Header="{Binding}" Style="{StaticResource FlatsItem}" IsExpanded="True">
</TreeViewItem>
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
</TreeViewItem>
</TreeView>
How can I bind a textbox to a selected item property (or to the databound class property) of a TreeViewItem only if it is a child of Door Controllers TreeViewItem
Thank you in advance
Oliver
You would likely be best served with defining a DataTemplate selector, and creating several datatemplates. The selector can evaluate all kinds of logical rules, and return the template that you want.
Here is a pretty good getting started tutorial on DataTemplateSelectors.
EDIT
After rereading your question here is what I have got.
Do your model classes have navigation properties to get to parent objects? If so, you can use triggers (or more preferable if you are using MVVM) properties on the ViewModel to enable/disable/alter visibility based on what the parent object is rather than the parent TreeViewItem. It is a bit more difficult to access the visual tree the way you are describing.
I solved this myself by adding an event handler on click for each of the child TreeViewItems I am concerned with. With this I could then get the DataContext from it, and set it to be the DataContext of the TextBoxs, and create my own bindings.
Since DataContext retrieval is done by reference, and not by value this works.
Here is the event handler for when one of the child nodes are clicked than I am concerned with: (Forgive the temporary naming)
private void DCTreeViewItem_Selected(object sender, RoutedEventArgs e)
{
TreeViewItem currentItem = (TreeViewItem)e.OriginalSource;
textBox5.DataContext = ((DoorControllerLabelInfo)currentItem.DataContext);
Binding b = new Binding("DCName");
b.Mode = BindingMode.TwoWay;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding(textBox5, TextBox.TextProperty, b);
}
From this, I set the path, binding mode, and update source trigger in the XAML so that only the Data Context need to be updated.
Thanks
Oliver

Binding a TreeView with ContextMenu in Xaml

I'm pretty new to Xaml and need some advise.
A TreeView should be bound to a hierarchical object structure. The TreeView should have a context menu, which is specific for each object type.
I've tried the following:
<TreeView>
<TreeView.Resources>
<DataTemplate x:Key="RoomTemplate">
<TreeViewItem Header="{Binding Name}">
<TreeViewItem.ContextMenu>
<ContextMenu>
<MenuItem Header="Open" />
<MenuItem Header="Remove" />
</ContextMenu>
</TreeViewItem.ContextMenu>
</TreeViewItem>
</DataTemplate>
</TreeView.Resources>
<TreeViewItem Header="{Binding Name}" Name="tviRoot" IsExpanded="True" >
<TreeViewItem Header="Rooms"
ItemsSource="{Binding Rooms}"
ItemTemplate="{StaticResource RoomTemplate}">
<TreeViewItem.ContextMenu>
<ContextMenu>
<MenuItem Header="Add room"></MenuItem>
</ContextMenu>
</TreeViewItem.ContextMenu>
</TreeViewItem>
</TreeViewItem>
But with this markup the behavior is as intended, but the child items (the rooms) are indented too much.
Anyway all the bining samples I could find use TextBlock instead of TreeViewItem in the DataTemplate, but wonder how to integrate the ContextMenu there.
You would not normally create a DataTemplate containing a TreeViewItem, because the binding infrastructure will be creating the TreeViewItem for you -- all your DataTemplate needs to do is specify what should be displayed as the content of the TreeViewItem. That's why the samples you've found use TextBlocks instead of TreeViewItems in the DataTemplate.
I suspect the use of TreeViewItem rather than TextBlock causes the excessive indenting because you have a (manually created) TreeViewItem in your DataTemplate (which incurs one level of indent) inside another (automatic) TreeViewItem (which incurs another level of indent). Therefore, using a TextBlock instead of a TreeViewItem should cure this. Integrating the ContextMenu shouldn't be an issue because TextBlock has a ContextMenu property too.
So you should be able to just change your DataTemplate as follows:
<DataTemplate x:Key="RoomTemplate">
<TextBlock Text="{Binding Name}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Open" />
<MenuItem Header="Remove" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
Incidentally for TreeViews it is common to use a HierarchicalDataTemplate rather than a plain DataTemplate because this allows for multiple levels of items via the HierarchicalDataTemplate.ItemsSource property. This may not be required in your scenario though.

Resources