WPF Dashboard and Widgets - wpf

Hi I would like to write some kind of dashboard. You should be able to drag widgets on the dashboard from some source. The layout of the widgets should be free (first Canvas, later some own Panel).
My questions:
Do you have any hints for information about this kind of controls for me?
Is it a good idea to use Selector as BaseClass or should inherit from Control

I would make a BaseClass for all widgets, and then build a ViewModel that inherits from that BaseClass for each Widget, along with a View to go with that ViewModel
After that, I would have something like ObservableCollection<WidgetBaseViewModel> OpenWidgets in the main application ViewModel, and bind it to an ItemsControl.
The ItemsControl would have it's ItemsPanelTemplate set to a Canvas, and each WidgetBaseViewModel would contain a Top, Left, Height, and Width property.
The actual UI to display each Widget with would be based on a DataTemplate, and could be anything you want, although a UserControl would be easiest
<ItemsControl ItemsSource="{Binding OpenWidgets}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:WidgetAViewModel}">
<local:WidgetAView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:WidgetBViewModel}">
<local:WidgetBView />
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas ... />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Also, you'll need to bind your Canvas.Top/Canvas.Left on the ItemContainerStyle instead of on the actual ItemTemplate to get it to display correctly in the canvas.

Related

WPF Binding To Child Control

I've got a TabControl which contains a nested ListView. The ListView is bound to the selected item in the parent TabControl. This works great in that switching tab displays the child elements in the ListView. What I can't figure out, is how to bind to the ListView's SelectedItem from outside of the Menu UserControl.
i.e.
<TabControl x:Name="Parent">
<TabControl.ContentTemplate>
<DataTemplate>
<ListView x:Name="Child"
ItemsSource="{Binding Path=SelectedItem.Tabs, ElementName=Parent}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
<ItemsControl ItemsSource="{Binding Path=SelectedItem.Controls, ElementName=Child}">
<ItemsControl.ItemTemplate>
<DataTemplate>
... controls go here ...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I'm using M-V-VM so don't want to do my binding in code ideally - I'm sure it's possible, just can't figure it out :)
In general, if you need a property on a higher level you could move the property to the ViewModel that is bound to the higher level.
So, if I understand correctly, I would move the property of the ViewModel that is bound to the SelectedItem to the VM of the TabControl.
Does this make sense?

Switch View based on selected TreeViewItem

I have a Shell.xaml file which contains two other UserControls. On the left is my TreeView and on the right is a detail screen.
I want the detailscreen to be switchable based on a selected TreeViewItem. I know this can be achieved by using DataTemplates, because I've done it with simple button clicks and using the <ContentControl Content="{Binding CurrentDetailViewModel}"> tag to accomplish this, but I have no idea how to accomplish this based on a selected TreeViewItem. I also have a separate ViewModel class for my UserControl which holds my TreeView and a separate for each detail screen.
I've been using Josh Smith's tutorial on TreeViews: http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx
So I also do use the TreeViewItemViewModel.cs class of his.
Could someone shed some light onto this?
Thanks,
Grant
If both the treeview and the details are displaying the same object (i.e the ItemsSource of the treeview contains the objects that you want to data template in the custom control) then you should be able to set a property on an underlying ViewModel that both controls share and have the custom control display something relevant with data templates.
for example, in the ViewModel:
object TreeViewSelectedItem
{
get{ return _treeViewSelectedItem;}
set {_treeViewSelectedItem = value; NotifyPropertyChanged("TreeViewSelectedItem");}
}
Treeview xaml
<TreeView ... SelectedItem={Binding TreeViewSelectedItem Mode=OneWayToSource}".../>
custom control xaml
<UserControl>
<Control.Resources>
<DataTemplate DataType="{x:Type Plane}">
....
</DataTemplate>
<DataTemplate DataType="{x:Type Train}">
....
</DataTemplate>
<DataTemplate DataType="{x:Type Automobile}">
....
</DataTemplate>
</Control.Resources>
<ContentControl Content={Binding TreeViewSelectedItem}"/>
</Usercontrol>

How to expose ItemTemplate and ContentTemplate from a UserControl

I have written a Well control, similar to the Visual Studio editor tabs so that a user can have multiple documents open and can see one or more at a time. It is derived from a UserControl and exposes an ObservableCollection of OpenDocuments that binds to the ViewModel. If I were to implement this as a simple TabControl, then this would be how it would look:
<TabControl
Grid.Row="1"
Grid.Column="1"
ItemsSource="{Binding OpenDocuments}"
SelectedItem="{Binding SelectedTab, Mode=TwoWay}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<vw:DocumentView />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This gives me Name in the tabitem header and the DocumentView (another user control in the Content area).
My control has a ContentTemplate but it is of course representing the whole of the control so all I get to see is the DocumentView. My control doesn't have an ItemTemplate.
How do I expose an ItemTemplate and ContentTemplate?
Andrew
EDIT -------------------------------------------------------------------------
Thanks for the replies. It looks like this:
A user can have one or more document wells holding one or more tabs. All the consumer has access to is the list of visible tabs and the currently selected tabitem.
Notice that the tabs are all empty! I don't understand how to specify the ContentTemplate for the <vw:DocumentView> in the same way as the TabControl example above.
Andrew
I am a little confused on exactly what your control looks like but here is what I think you are after.
If your control can inherit from ItemsControl you will get the ItemTemplate property already defined for you. All you have to do in your control template is to Template bind the ItemsControl property to the correct place in the template.
The same applies for the ContentTemplate. If you have the a ContentTemplate property already defined for you control you just need to Template Bind it to the correct place in the control.
It would look something like this
Control Consumer
<MyControlNamespace:MyControl ContentTemplate="{StaticResource MyContentTemplate}" ItemTemplate="{StaticResource MyItemTemplate}" />
Implementation of "MyControl" from above (totally pseudo code)
<MyControl>
<ItemsPresenter ItemTemplate="{TemplateBinding ItemTemplate}" />
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" />
</MyControl>
Again, my example doesn't fully make sense but I am not sure what your control looks like and not entirely sure what you are asking, but hopefully this helps.

Use a user control as a DataTemplate within a WPF application

I am trying to create a user control within a WPF application that will serve as a DataTemplate for a ListBoxItem. The user control a grid with 4 TextBlocks. This control also contains other shapes and images more for visual aid than anything so I am omitting them from the code in this question for clarity.
When I drop the user control on my mainwindow.xaml I can see the control and the properly bound fields point to the first record in the datasource. What I want to do is have this control render repeatedly within either a listbox or a wrap panel for each record within the database.
Can anyone provide me with a pointer or sample of how to have a user control render as a DataTemplate within the ListBox control/other panel.
Up to this point I have tried the following with no avail:
Thanks in advance for any tips.
<!--within Window.Resource -->
<DataTemplate x:Key="myActivity">
<local:ucActivityItm /> <!--usercontrol -->
</DataTemplate>
<!-- Listbox within the window -->
<ListBox HorizontalAlignment="Stretch" ItemTemplate="{DynamicResource myActivity}" VerticalAlignment="Stretch">
<ListBoxItem>
<!-- control also added for testing to ensure it rendered out-->
<local:ucActivityItm />
</ListBoxItem>
</ListBox>
That DataTemplate isn't actually being assigned to your ListBox. There's three ways:
1: Replace the template in the Resources section with
<ListBox.ItemTemplate>
<DataTemplate>
<local:ucActivityItm />
</DataTemplate>
</ListBox.ItemTemplate>
in the ListBox.
2: Somewhat related:
<ListBox ... ItemTemplate="{StaticResource myActivity}">
3: Set the DataType parameter of the DataTemplate above to whatever the content of your ListBox is.
<DataTemplate x:Key="myActivity" DataType="{x:Type ...}">
I usually just do the first, but any should work.

How to bind items of a TabControl to an observable collection in wpf?

What is the simplest example of binding the items of a TabControl to an ObservableCollection?
Each tab's content will have unique data, and indeed this data will have observableCollections of its own bound to the items components.
Currently I have a user control, which I would like to set as the content of each tab as soon as it is created. I also need to dynamically set the datacontext of this new user control when the tab is created. So, essentially, I would like the tabcontrol's observablecollection contain modelviews that map to the data in each tab.
On top of that, I need to do all this without violating MVVM in WPF! Any help?
Much appreciated!
Basic example :
<Window.Resources>
<DataTemplate x:Key="templateForTheContent" DataType="{x:Type vm:TheViewModelType}">
<v:YourUserControl/>
</DataTemplate>
<DataTemplate x:Key="templateForTheHeader" DataType="{x:Type vm:TheViewModelType}">
<TextBlock Text="{Binding ThePropertyToDisplayInTheHeader}"/>
</DataTemplate>
</Window.Resources>
...
<TabControl ItemsSource="{Binding YourCollection}"
ContentTemplate="{StaticResource templateForTheContent}"
ItemTemplate="{StaticResource templateForTheHeader}">
</TabControl>

Resources