I want to display the following using a wpf TreeView:
My objects are different, there is no Base class or Interface, I must define a HierarchicalDataTemplate for each item, STOP for example I can add just one ItemSource "Deliveries" but I want to add the pickups also for this stop.
<!-- DELIVERY-->
<DataTemplate x:Key="DeliveryDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="DeliveryId" Margin="3,3" />
<TextBlock Text="{Binding DeliveryStatus}" VerticalAlignment="Center" Margin="5" />
<TextBlock Background="{Binding StopStatus, Converter={StaticResource StatusConverter}}" Width="16" Height="16" />
</StackPanel>
</DataTemplate>
<!-- STOP -->
<HierarchicalDataTemplate x:Key="StopTemplate"
ItemsSource="{Binding Deliveries}"
ItemTemplate="{StaticResource DeliveryTemplate}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Stop" Margin="3,3" />
<TextBlock Text="{Binding StopId}" Margin="3,3" />
<TextBlock Background="{Binding StopStatus, Converter={StaticResource StatusConverter}}" Width="16" Height="16" Margin="3,3" />
</StackPanel>
</HierarchicalDataTemplate>
<!-- ROUTE -->
<HierarchicalDataTemplate x:Key="RouteTemplate"
ItemsSource="{Binding Stops}"
ItemTemplate="{StaticResource StopTemplate}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Route" Margin="5,5" />
<TextBlock Text="{Binding RouteId}" Margin="5,5" />
<TextBlock Background="{Binding RouteStatus, Converter={StaticResource StatusConverter}}" Width="16" Height="16" Margin="5,5" />
</StackPanel>
</HierarchicalDataTemplate>
I have a collection of Routes, each Route has Stops, each Stop has Deliveries and Pickups, each Delivery has its items each item has its own items and so on... How to solve this?
This sounds like a heterogenous datasource problem. I think this solution might be what you are looking for.
I like this answer because it need some very short codes.
WPF Treeview Databinding Hierarchal Data with mixed types
And you might need reading this question to import the System.Windows.Data.ObservableCollection Class. To be short, it can only be imported in a Wpf Library or so, not in a normal .net Class Library.
Cannot Import System.Windows.Data
Related
We are going to develop a behavior tree editor using WPF.
However, we are totally new to WPF.
How to generate shape components that represent tree nodes and the components should be able to respond to mouse event like right mouse clicked.
Do you have any suggestions on this?
You can specify different HierarchicalDataTemplate for your tree. They get chosen automatically by classname. You can also specify one for your base type. Be sure not to use interfaces, but real classes.
So if you use different classes for your view models you can get along with something like this:
<TreeView
ItemsSource="{Binding MyTreeVariable}"
SelectedItemChanged="MyTree_SelectedItemChanged">
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}" DataType="{x:Type self:MyBaseType}">
<StackPanel Orientation="Horizontal">
<Rectangle Width="16" Height="16"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}" DataType="{x:Type self:MySpecialType1}">
<StackPanel Orientation="Horizontal">
<Ellipse Width="16" Height="16"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}" DataType="{x:Type self:MySpecialType2}">
<StackPanel Orientation="Horizontal">
<!--- Triangle -->
<Polygon Points="50,0 100,100 0,100" Width="16" Height="16"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
If you like to tell the different behaviors by data, you can use DataTrigger and Setter, but I`d recommend the way shown above.
I feel like I'm missing some essential concept in WPF databinding. It's always hit-or-miss whether my bindings are going to work for me.
In this example, I want to two-way bind the IsExpanded property of a TreeViewItem to the corresponding property on a bound object. It does work with the first example; it does NOT with the second.
Can anyone explain why? I cannot understand why the second version doesn't work. And I can't help thinking it would save me untold grief if I could.
This works when placed in UserControl.Resources (binding to IsExpanded is done with a Style applied to TreeViewItem:
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded"
Value="{Binding Path=IsExpanded, Mode=TwoWay}" />
</Style>
<DataTemplate DataType="{x:Type viewModels:FolderItem}">
<TreeViewItem ItemsSource="{Binding Folders}"
IsExpanded="{Binding Mode=TwoWay,Path=IsExpanded}" >
<TreeViewItem.Header>
<StackPanel Orientation="Vertical">
<Image Source="{Binding IconSource}"
Width="16" Height="16"
Margin="4,0,4,0" VerticalAlignment="Center" />
<TextBlock Text="{Binding Title}"
VerticalAlignment="Center" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</DataTemplate>
This does not (direct binding to IsExpanded in the data template):
<DataTemplate DataType="{x:Type viewModels:FolderItem}">
<TreeViewItem ItemsSource="{Binding Folders}"
IsExpanded="{Binding Path=IsExpanded,Mode=TwoWay}" >
<TreeViewItem.Header>
<StackPanel Orientation="Vertical">
<Image Source="{Binding IconSource}"
Width="16" Height="16" Margin="4,0,4,0"
VerticalAlignment="Center" />
<TextBlock Text="{Binding Title}"
VerticalAlignment="Center" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</DataTemplate>
The DataTemplate is used in the following Xaml fragment, with the data template given above used to perform data conversion. Documents is an observable list of FolderItems which has been bound correctly.
<TreeView ItemsSource="{Binding Documents}" />
Both DataTemplates show the file tree. But there is no binding (two-way or otherwise) for IsExpanded in the second case.
Not shown is DataTemplating for FileItem's which are the leaf nodes of FolderItem's..
The issue is that TreeViewItem is actually a wrapper that is used by the TreeView itself. It needn't (and shouldn't) be part of your DataTemplate, as what you have now is creating a TreeViewItem within a TreeViewItem (the outer one being created by the TreeView, and the inner one being part of the template).
This is why your style works, as it gets applied to all TreeViewItems, both the one that you're declaring (which ends up being meaningless) and the one created by the TreeView.
What you should do is replace your DataTemplate with this:
<HierarchicalDataTemplate ItemsSource="{Binding Folders}">
<StackPanel Orientation="Vertical">
<Image Source="{Binding IconSource}"
Width="16" Height="16" Margin="4,0,4,0"
VerticalAlignment="Center" />
<TextBlock Text="{Binding Title}"
VerticalAlignment="Center" />
<HierarchicalDataTemplate>
(Unfortunately I can't test at the moment, but that should at least get you headed in the right direction).
Leave your style as-is to continue binding the property.
How do I update a nested ListBox in my viewmodel (Mvvm Light) without page navigation after the initial view has been displayed. Currently I am doing a re-entrant page navigation using a changing querystring - there must be a better way?
RaisePropertyChanged is having no effect although I can see the data is populated with the correct data when the callback from the soap request triggered via OpenCallingPoints has fired.
The grid I am trying to populate with soap data is CallingPointsGrid
Short version of the code...
<ListBox x:Name="ResultsListBox" Margin="0" VerticalAlignment="Top" ItemsSource="{Binding JourneyLegs, Mode=TwoWay}" Background="{StaticResource BackgroundWhiteGradientBrush}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="StationItem" Orientation="Vertical" VerticalAlignment="Top" background="{Binding id, Converter={StaticResource myconverter}}">
<Grid Name="CallingPointsGrid" Margin="15,10,55,10" Visibility="{Binding JourneyCallingPoints, Converter={StaticResource CallingPointsVisibilityConverter}}" Background="{StaticResource BackgroundWhiteGradientBrush}">
<ListBox Grid.Row="1" Name="CallingPointsListBox" DataContext="{Binding}" VerticalAlignment="Top" ItemsSource="{Binding JourneyCallingPoints, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Top" Orientation="Horizontal">
<TextBlock Margin="0" VerticalAlignment="Center" HorizontalAlignment="Left" Width="210" x:Name="Destination" Foreground="Black" Text="{Binding stationName}" />
<TextBlock Margin="5,0,5,0" VerticalAlignment="Center" HorizontalAlignment="Left" Width="75" x:Name="ScheduledDepartureTime" FontWeight="Bold" Foreground="{StaticResource BackgroundBlueLightSolidColor}" Text="{Binding timetable.scheduledTimes.arrival, StringFormat=\{0:HH:mm\}}" />
<TextBlock Margin="5,0,5,0" VerticalAlignment="Center" HorizontalAlignment="Left" Width="75" x:Name="ScheduledArrivalTime" FontWeight="Bold" Foreground="{StaticResource BackgroundBlueLightSolidColor}" Text="{Binding timetable.scheduledTimes.departure, StringFormat=\{0:HH:mm\}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger SourceName="ResultsListBox" EventName="Tap">
<i:EventTrigger.Actions>
<local:OpenCallingPoints />
</i:EventTrigger.Actions>
</i:EventTrigger>
</i:Interaction.Triggers>
You might look at this:
http://matthamilton.net/madprops-mvvmlight-screenconductor
I was going to suggest you look at Caliburn Micro and was searching around to see if Mvvm-Light had something similar. That article talks about that.
That's one of the things I really like about CM, when you inherit your ViewModel from Screen you automatically get OnInitialize, OnActivate, OnDeactive, OnViewLoaded, and OnViewReady methods you can override. So in this case you'd stick that logic in OnActivate.
On windows phone CM will also auto parse out the query string parameters and populate a property on your VM with them.
It looks like the screen conductor allows you to do similar with mvvm-light.
I'm new to WPF and this following has stumped me for a while now:
I have an observableCollection of People object in my model that is bound to my tabControl. So each my a new People object is added, a new tab is created with People.Title as the Tab's header.
Each People object has an ObservableCollection of Friend object. Inside of the Tab I would like to have a List of two textboxes, one for Friend.FirstName and another for Friend.LastName.
My first requirement is working fine, but the second one is giving me an error 'ItemsSource is already in use'
Here's my code so far:
<TabControl Name="ConversationTabs" Grid.Row="0"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource HeaderInfoTabControl}"
ContentTemplate="{StaticResource DialogueList}" />
<Window.Resources>
<DataTemplate x:Key="HeaderInfoTabControl">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
<DataTemplate x:Key="DialogueList">
<ItemsControl ItemsSource="{Binding Path=DialogueCollectionVM}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Sent}" />
<TextBlock Text="{Binding Path=DateSent}" />
<TextBlock Text="{Binding Path=Message}" />
</StackPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
I appreciate your help.
You cannot add items to an ItemsControl and use the automatic population (via ItemsSource) at the same time. If that StackPanel is supposed to be used for the items in the ItemsSource you should do this:
<ItemsControl ItemsSource="{Binding Path=DialogueCollectionVM}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Sent}" />
<TextBlock Text="{Binding Path=DateSent}" />
<TextBlock Text="{Binding Path=Message}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have a UI that displays a pattern of "first name/last name". So I thought I would reuse the same template. But I am facing some issues getting the binding right.
Note:-
PrimaryContactDataContext is nothing but a class, with a property named "value" which implements the *INotifyPropertyChanged" interface.
<StackPanel>
<ContentControl DataContext="{Binding Path=PrimaryContactDataContext.Value,Mode=TwoWay}" ContentTemplate="{StaticResource PersonalDetailsTemplate}" />
</StackPanel>
// See the Reusable template below
<UserControl.Resources>
<DataTemplate x:Key="PersonalDetailsTemplate" >
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Width="30" Text="Name"></TextBlock>
<TextBox Width="110" Text="{Binding LastName}" IsReadOnly="True"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Width="30" Text="Title"></TextBlock>
<TextBox Width="110" Text="{Binding firstName}" IsReadOnly="True"></TextBox>
</StackPanel>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
Set the Content of the ContentControl, not its DataContext:
<ContentControl Content="{Binding Path=PrimaryContactDataContext.Value,Mode=TwoWay}" ContentTemplate="{StaticResource PersonalDetailsTemplate}" />