WPF TabControl - Do I need an ItemTemplateSelector *and* a ContentTemplateSelector? - wpf

So I have as the main user control in my WPF app a TabControl that will support several different views (basically forms for data entry) and their underlying view models (basically ORM mappings.)
I built a ContentTemplateSelector to throw out the correct content view for the selected item.
So my question is:
Should I build an ItemTemplateSelector to select the correct property from the underlying view model that will act as the tab header title?
Or, should I assign a property from each view model to another property called something like DisplayTitle and then use that in the ItemTemplate?
And more generally, is there a way to combine the "selection" of an ItemTemplate and ContentTemplate under a single selector?

I usually use type based data-templating for the content and a common property (set as DisplayMemberPath) or an attribute on the class for the header (in case there is one item per class).
I doubt that you can conveniently combine the selectors, nor do i like selectors in general...

Related

In WPF (or silverlight or WP7), should a picture wall derive from ItemsControl or Panel?

Assume that I need to create a class called PictureWall, which will be used to show pictures.
Now I find that Panel and ItemsControl can both be used to hold Children elements. So should the class PictureWall derive from Panel? or should it derive from ItemsControl.
Note: This is not a real requirement, it's just a hypothetical question. The real question is: when should I create a subclass of Control (or ItemsControl) and when should I create a subclass of Panel?
Note 2: This imagined picture wall control is not to be used in one application only. It may be used by other developers. If it derives from Panel or ItemsControl, it'll expose the property named Children to other developers. So in this case, deriving from Control is a better idea, right?
Note 3: This imagined picture wall control has its own default way of loading certain pictures (for example, pulling pictures from a server) and it does not want this way to be messed around. If this is the case, then we should not inherit ItemsControl, right?
Panel is a container that is used to arrange its children. For example: Grid with a title and one button on the bottom and an image on center - Grid is very flexible to help you move stuff and arrange them when you change the size of window etc.
ItemsControl is a control that helps you with a collection of items. Let's take a concrete example: Listbox. You can very easly show a list of items, applay template to all of them, so on and so forth.
Control class is basically a UI element that can have its own template.
Note that, it is a way much better to define own UserControl, edit template or style of your PictureWall, insted of subclassing (there are many advantages, for example you can use Blend to redefine the style).
Edit:
# note2
If I were you I would make my own User Control to reuse existing controls to make what I want. If that won't be enough I would subclass Control.
[StyleTypedProperty(Property = "FooStyle", StyleTargetType = typeof(Control))]
public partial class MyDangControl: Control
{
...
# note3
This is a bad idea to combine all in one. You should split the logic that fetch the data form yout Picture Wall. For instance, user presses thumbnail to download the image and whole UI hangs. Horrible UX.
To be crystal clear, let me quote Pro WPF in C# 2010
Control
This is the most common starting
point when building a control
from scratch. It’s the base class for
all user-interactive widgets. The
Control class adds properties for
setting the background and foreground,
as well as the font and alignment of
content. The control class also places
itself into the tab order (through the
IsTabStop property) and introduces the
notion of double-clicking (through the
MouseDoubleClick and
PreviewMouseDoubleClick events). But
most important, the Control class
defines the Template property that
allows its appearance to be swapped
out with a customized element tree for
endless flexibility.
ContentControl
This is the base class for controls
that can display a single piece of
arbitrary content. That content can be
an element or a custom object that’s
used in conjunction with a template.
(The content is set through the
Content property, and an optional
template can be provided in the
ContentTemplate property.) Many
controls wrap a specific, limited type
of content (like a string of text in a
text box). Because these controls
don’t support all elements, they
shouldn’t be defined as content
controls.
ItemsControl
ItemsControl is the base class for
controls that wrap a list of items but
don’t support selection, while
Selector is the more specialized base
class for controls that do support
selection. These classes aren’t often
used to create custom controls,
because the data templating features
of the ListBox, ListView, and TreeView
provide a great deal of flexibility.
Panel
This is the base class for controls
with layout logic. A layout control
can hold multiple children and
arranges them according to specific
layout semantics. Often, panels
include attached properties that can
be set on the children to configure
how the children are arranged.
They both can be used to display elements, but really an ItemsControl offers much more functionality. In addition, an ItemsControl doesn't really display it's elements, it leverages a Panel to do that.
An ItemsControl can display a list of items, which may or may not be UIElements/Visuals. The items can be templated using a configurable DataTemplate, which ultimately determines how the item is displayed. In addition, then items can be bound to an observable collection so it will automatically update.
Neither of these features are supported by a Panel. DataTemplates can be used, but you have to manually create an associated ContentControl/ContentPresenter and add it to your panel.
Ultimately, their functions are different. A Panel is used to display UIElements/Visuals. An ItemsControl is used to display any type of data and apply templates as needed.

Where do I define dependency properties shared by the detail views in a master-detail MVVM WPF scenario?

I can think of two ways to implement dependency properties that are shared between the detail views:
Store them in the master view model and add data bindings to the detail view models when they are created, and bind to them in the detail view.
Don't store them in the view models at all, and use FindAncestor to bind directly to properties of the master view instead.
What are the pros and cons of each, and are there other/better options?
Edit:
To clarify, I have a custom control (derived from Control) that uses a master view model for its DataContext. The custom control's control template contains an ItemsControl with ItemsSource bound to a dependency property in the master view model. This dependency property is an ObservableCollection of detail view model objects. The ItemsControl's item template binds to properties in the detail view model. What I need is a single property that is shared by the control template of the custom control (master view) and the item template for all the items in the ItemsControl. The custom control will contain a Slider or something to set the value, and the item template will simply read it.
Sorry if I'm abusing the terms, I'm still trying to get the hang of MVVM. If the problem still is unclear, I can try to write some code for a simple test case.
Implementing the dependency properties in the the View's code behind is the most popular practice I have seen. This allows you to interact with the DP via Databinding to the ViewModel. There aren't really any cons, DPs are meant to go one the object that needs to implement databinding.
If the above is not what you are asking, please include a brief Code Example to.

HeaderedContentControl ItemsSource

Why there is no HeaderedContentControl ItemsSource property?
How then can I databind to a list of objects to be represented by HeaderedContentControl?
Thanks
John
Because ItemsSource is all about multiple pieces of content, and HeaderedContentControl has one piece of content. Put another way, HeaderedContentControl's job is to present a single object, so it doesn't need a property whose job is to feed it multiple pieces of content.
Use HeaderedItemsControl instead, or (depending on your requirements) an ItemsControl where the DataTemplate is a HeaderedContentControl. (Though in the latter case you might as well just use a Panel and multiple elements within the panel -- the HCC isn't really buying you anything.) HIC's job is to present multiple items under a single header, and it's pretty flexible. For example, the framework uses HIC as the base class for both TreeViewItem (whose "header" is the item at hand, and whose "items" are the children of that item) and MenuItem (whose "header" is the menu item, and whose "items" are any sub-menu-items, for example in a drop-down or pop-out menu).
There's no ItemsSource property, since it can have only a single child (or two children if you count Header in), just like the class it inherits from - ContentControl. Use Content property instead.
You can find more about it on MSDN.
If you want to display list of objects within HeaderedContentControl, then just add ListBox as its Content and fill ListBox with objects.
Maybe you need a HeaderedItemsControl.
You can find a sample here.
You should be able to bind the collection to the Content property.
HeaderedContentControl by name itself is a collection of ContentControl each with Header.

What are your 'best practices' for writing custom controls in WPF

I have started writing some custom controls for a highly visual project. I was wondering what are your 'best practices' when coding WPF custom controls?
If you want your custom control to support direct content like this:
<CustomObject>
Direct content example 1
</CustomObject>
<!-- or -->
<CustomObject>
<Button Content="Direct content example 2" />
</CustomObject>
Then you need to use the ContentPropertyAttribute which tells WPF which property is actually being set when you write xaml like this.
The attribute can be used like this:
[ContentProperty("NameOfProperty")]
public class CustomObject
{
[...]
ContentControl uses this attribute to set the Content property but note that the property can be called anything; the WPF TextBox, for example uses this attribute to set the Text property.
E.G.
[ContentProperty("Text")]
The property also does not have to be a dependency property (see the MSDN documentation example for evidence of this).
Finally, this attribute is specific to the xaml parser and not to ContentControl and can be used with any type which can be seen from the TextBox example above (TextBox does not derive from ContentControl).
Keep property names the same as the property names for built-in Controls if you can do so without changing their meaning.
e.g. if you have a CustomerDisplayer custom control don't call the list of customers Customers, call it ItemsSource.
It might seem counter intuitive at first but it saves a lot of headache in the long run because future programmers can make a lot of assumptions about how a property called ItemsSource will act that they can't necessarily make about a Customers property.
Make sure the control can be re-styled and re-templated without changing the way the control operates. Don't make the control assume that the Listbox and Button are both within the same panel or that there even is a Listbox or Button. Check out the MSDN article on control authoring for some recommendations on how to do this.
Some content controls are dependant on the existence of other controls in their ControlTemplate. Typically this should be documented using the TemplatePart attribute.
The Combobox control, for example, is dependant on the existence of a TextBox and a Popup controls in its template.
This would be documented by placing the attribute on the class like so:
[TemplatePart(name="PART_EditableTextBox", type=typeof(TextBox))]
[TemplatePart(name="PART_Popup", type=typeof(Popup))]
public class Combobox : Selector
{
[...]
The naming convention is "PART_controlIdentifier".
The relevant items would then be given the same names in the control template so that they can be located in the OnApplyTemplate method.
This then allows the control to hook up to events, set properties and call methods on the controls contained in the template.
This attribute is for documentation purposes so that people designing custom control templates (and tools such as Expression Blend) know that the control is dependant on the existence of another.
Learn how to use both dependency properties and routed events (and how they work) so that you can use them effectively in your own control.
Both of these types provide services for integrating your control with the systems built into WPF.
By using these two features in your custom controls you will get the following advantages:
Dependency Properties provide support for databinding, animations and can be used in styles.
Routed Events can be propogated through the visual tree which means that other elements can handle the events.

In a WPF tabControl how can I dynamically select a tab page from an object's type?

I've implemented the MVVM pattern and have some viewModels that are bound to tab pages on a tab control.
When a specific object type changes (i.e. from Car myVehical, to Bike myVehical), then i want the relevant tab page to become selected.
Thanks.
You could hack it by using a custom IValueConverter. You could then bind TabControl.SelectedIndex to a property on your view model and use the converter to convert from the type (Car or Bike) to an index. The value converter code would have to be updated when you change the tabs.
Rather than using a tab control, you can use DataTemplates. The view itself will get set automatically based on the object you set as the content.

Resources