xaml - How to specify which ContentTemplateSelector to use? - c#

I've seen a ton of examples where a content control's ContentTemplateSelector property is assigned a StaticResource.
Example: <ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource MyTemplateSelector}"/>
MSDN states:
Typically, you create a DataTemplateSelector when you have more than
one DataTemplate for the same type of objects and you want to supply
your own logic to choose a DataTemplate to apply based on the
properties of each data object.
Source: DataTemplateSelector Class
Knowing this - my situation is that I have two types of objects where each object has its own set of data templates it can use. Is there any way I can simply have the content control's ContentTemplateSelector bind to a ContentTemplateSelector property on the view model? The tricky part is that the data templates are defined in the xaml file - I can't just initialized a new instance of the specific ContentTemplateSelector for that class.
Additional info: I have a parent view model where each of its subclasses should be represented as a different type of object. So depending on which subclass view model is toggled, it should use its respective ContentTemplateSelector and data templates.
I've also gotten the above to work with a converter, but I want to stay away from this. Ideally, I'd like to have code that makes this process as general as possible. i.e. Not needing to maintain the converter code to add new types of objects in the future just to return the right DataTemplateSelector. The case should be that anytime a new subclass is added, it'll just work right away.

Related

WPF create your own type

I want to create a template (resource dictionary) for my app. where my type inherits the button type and I then can call it through:
<my-custom-type inherit from button>
</my-custom-type inherit from button>
And of course in WPF.
More specifically, I would like to create copies of the control in the image below with simple XAML syntax as above.
There are two approaches to this, each with their own pros and cons:
Templates allow you to reuse a section of XAML. There is (almost always) no code-behind, and you certainly won't be deriving from Button. For example, if you wanted to have a bordered text box repeated in an ItemsControl:
<DataTemplate x:Key="MyDataTemplate">
<Border>
<TextBox/>
</Border>
</DataTemplate>
Or in a button class you use ContentTemplate:
<Button ContentTemplate={StaticResource MyTemplate}>
</Button>
And you would use it as XTemplate="{StaticResource MyDataTemplate}" in an existing control that used templates. This is usually the way to go. Note that the name of the property won't be Template, but ItemTemplate, or ContentTemplate or something similar.
The exception is if you want custom behavior, in which case you use a UserControl. This technically could inherit from Button though you usually wouldn't. Subclassing a basic control should only be done if you are sure you actually want to do that. Once your user control is created, the syntax would look similar to what you have in your question:
<local:MyButton>
</local:MyButton>
Note that "local" is a made-up xmlns. Your user control would consist of whatever controls you wanted, and you can expose "attributes" to the using code via dependency properties.

Binding doesn't work on DependencyObject created in XAML

I'm trying to pass multiple CommandParameters in XAML with the use of a custom class.
I have created a class called ValueCommandArgs that inherits from DependencyObject and has two DepencyProperties (lets call them Value1 and Value2 for this example).
The button which is supposed to call a command and pass this object looks like this:
<Button Command="{Binding ChangeValueCommand}" Content="Execute Command">
<Button.CommandParameter>
<args:ValueCommandArgs Value1="{Binding TestValue1}" Value2="{Binding TestValue2}" />
</Button.CommandParameter>
</Button>
I do get an ValueCommandArgs-Object in my command as paramter, however the properties Value1 and Value2 are always null/empty.
I know this can be solved with a MultiBinding and Converter, but I think the way I'm trying it would be a cleaner approach.
Why doesn't this work?
A Binding needs a source object to be able to provide a value. When the Binding source is not specified (with Source or ElementName etc.) eg: Value1="{Binding TestValue1}" the DataContext of the element is used.
The args:ValueCommandArgs object does not inherit the DataContext from the Button element because property value inheritance is particularly about how property values can inherit from one element to another on the basis of the parent-child relationships within a tree of elements.
The button object does not include the value of the CommandParameter property in its logical nor the visual tree.
In many cases the need for such a CommandParameter with multiple bound values can be avoided by binding the values directly to the ViewModel.
When it can't be avoided you can use a different type of binding markup extension like: https://github.com/JohanLarsson/Gu.Reactive#ninjabinding that will use the root FrameworkElement as the source of the binding.
Another approach would be a binding proxy technique shown in this blog post: How to bind to data when the DataContext is not inherited

How do I implement a WPF control with its own DataTemplate DependencyProperty?

I am an intermediate WPF developer, with working knowledge on how to implement dependency properties as well as simple custom controls. I do not yet understand how I can add a DataTemplate dependency property to a custom control, and use it to define the element tree for each datum in a collection of data.
The full story is that I have been working on creating a WPF map control that displays many different points and geometric shapes on the map, over map tiles. These shapes will translate with the rest of the map when user "drags" the map around.
I have accomplished this, insofar that I have created the map control, and can add child elements to it in Xaml that have map coordinates. I would like to take this farther, and add properties for collections of data, i.e. points, areas, etc. To better understand what I'm looking for, I would like to re-create two properties from ListBox: ItemsSource and ItemTemplate.
I have added two dependency properties to my Map control - PointsSource and PointsTemplate. PointsSource is of type IEnumberable and represents the collection of data to display on the map. PointsTemplate represents what each of those datum should look like. Simply throwing these properties into my control is obviously not enough, but I am unsure of how to coordinate them with one another. If anyone has working knowledge of creating a custom data control with it's own DataTemplate properties for changing the UI tree for each data element, I would really appreciate it.
I have found what I am looking for in the DataTemplate itself. The DataTemplate provides a function for code behind called LoadContent(). LoadContent produces a dependency object that represents the tree of content for a given datum. From what I have found elsewhere, the common use for LoadContent might look like the following:
foreach (object point in PointsSource)
{
FrameworkElement pointElement = _PointsTemplate.LoadContent() as FrameworkElement;
pointElement.DataContext = point;
this.Children.Add(pointElement);
}
The above code will add a content tree for every single element of data, and we give it the datum to bind its DataContext to.
If anyone has working knowledge of creating a custom data control with it's own DataTemplate properties for changing the UI tree for each data element, I would really appreciate it.
Basically, you will want to use an ItemsControl inside your control template, and bind its ItemsSource and ItemTemplate properties to your custom Dependency Properties. Ie,
<Style TargetType="{x:Type local:CustomControl}">
<Setter Property="Template">
<ControlTemplate TargetType="{x:Type local:CustomControl}">
<ItemsControl ItemsSource="{TemplateBinding PointsSource}"
ItemTemplate="{TemplateBinding PointsTemplate}"
/>
</ControlTemplate>
</Setter>
</Style>
(assuming the DPs IEnumerable - "PointsSource" and DataTemplate - "PointsTemplate")

DataContext changes before I can pass parameters

I have a control with a dependency property which I want to pass which is a property in a class, and I also want to use an ObservableCollection which part of that class as the datacontext for that control.
<mycontrols:News
feedStatus="{Binding newsData.newsStore.feedStatus}"
DataContext="{Binding newsData.newsStore.news}"
/>
The problem here is that the DataContext is used when it evaluates {Binding newsData.newsStore.feedStatus} how can I get it to pass feedStatus first and then set the DataContext.
I would use just the single datacontext if silverlight had the ability to back track up the datacontexts parent, but I don't think this is the case.
Could I set datacontext as a nested parameter?
Set the DataContext to DataContext="{Binding newsData.newsStore} and then bind the feedStatus and news properties inside your UserControl.
Alternatively use multiple dependency properties, instead of the DataContext.
Also, please use .NET naming conventions (PascalCase!). Java style casing makes my eyes cringe.

Multiple DataContext in a View vs MVVM? Is that right?

I have the following problem: I'm building a chat WPF application on which I want the user to be connected with different accounts to GTalk. I've made a ViewModel that permits handling the communication but I don't know which is the best way to handle DataContext. I think that I need different DataContexts for every connection instance but I don't know if this is the right way and don't know how to define multiple DataContexts in a View.
A DataContext provides the default binding source for an element in the view. It is inherited from parent to child within the visual tree. You can change the DataContext for any element by binding it to some property of its parent DataContext. This is a common way of creating 'islands' that bind to a child view model.
For example, if you have a User view model that has an Address Property, you can render this in an AddressUserControl as follows:
<StackPanel>
... elements bound to properties of User ...
<AddressUserControl DataContext="{Binding Address}"/>
</StackPanel>
If you have a variable number of accounts, you can use the ItemsControl.
The rough idea behind this: You can bind the ItemsControl to a list of "Sub-ViewModels" in your main ViewModel and define a DataTemplate (= a View) for each of them. The DataContext of each DataTemplate is automatically assigned to a corresponding item in your ViewModel's list.

Categories