Accessing a WPF GroupItem text for conversion in a template - wpf

I'm customising the appearance of grouping in a ListBox. In ListBox.Resources, I have declared something like (formatting removed):
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<StackPanel Orientation="Vertical">
<!-- Group label -->
<ContentPresenter />
<!-- Items in group -->
<ItemsPresenter />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The actual group label is not very readable and I'd like to use a value converter to make it more presentable. However I cannot find a way to obtain this text and convert it.
I figure that a Binding would let me use a converter.
I've tried replacing the ContentPresenter above with the likes of...
<TextBlock Text="{TemplateBinding Content}"/>
<TextBlock Text="{Binding}"/>
...and numerous other things, but to no avail. Any suggestions?

Well isn't that just typical. I found the answer shortly after posting...
<TextBlock Text="{Binding Path=Content.Name,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=GroupItem},
Converter={StaticResource MyConverter}}"/>
Sometimes just the process of actually asking the question draws the answer out of thin air. In this case looking at the source code of GroupItem in .NET Reflector did the trick.
Hope someone else finds this edge case useful. Still, it would be a lot nicer if GroupItem exposed a property for this directly.
I'll still award a correct answer to anyone who knows a nicer way of doing this.

Related

Ensuring AdornmentDecorator within a ContentPresenter, but without a ControlTemplate

I've searched around quite a bit and can't seem to crack this nut.
I've got an app with a main view that changes dynamically, and to do this I use content presenter with a binding to a control:
<ScrollViewer Grid.Column="2" x:Name="StepScrollViewer">
<StackPanel Margin="20,20,20,500">
<ContentPresenter Content="{Binding MainControl}"/>
</StackPanel>
</ScrollViewer>
Then I change the MainControl at runtime in my view model. The problem is that the controls getting bound don't reliably display their error templates... I suspect it is for the reasons discussed here:
Validation ErrorTemplate not showing on data errors
But the fix for this problem doesn't seem to work for me because I'm not using a control template around my content presenter. When I wrap an AdornmentDecorator tag around my content presenter, it doesn't seem to fix the problem. It DOES work if I put an AdornmentDecorator inside each control I load into the contentpresenter (as the root element), but I'd like to avoid this repetition if possible.
Any insights?
UPDATE
I tried this approach suggested by Dennis, but to no avail. The control binds okay, but it works no better than the current approach (also shown commented below). Note: I tried it both with the AdornerDecorator as a singleton element the way Dennis has it, and surrounding the ContentPresenter, as shown below. Neither show any difference - the adorners around my controls all disappear when the MainControl binding is changed.
<UserControl.Resources>
<Style x:Key="MainContentControl" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Grid>
<AdornerDecorator>
<ContentPresenter Content="{Binding MainControl}"/>
</AdornerDecorator>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
.....
<ScrollViewer Grid.Column="2" x:Name="StepScrollViewer">
<StackPanel Margin="20,20,20,500" >
<ContentControl Style="{StaticResource MainContentControl}"/>
</StackPanel>
</ScrollViewer>
<!-- THE BELOW WORKS IF I SURROUND EACH BOUND CONTROL WITH adornerdecorator -->
<ScrollViewer Grid.Column="2" x:Name="StepScrollViewer">
<StackPanel Margin="20,20,20,500">
<ContentPresenter Content="{Binding MainControl}"/>
</StackPanel>
</ScrollViewer>
-->
Instead of using a ContentPresenter directly, I would instead use a ContentControl. A ContentControl is the base class for controls that contain other elements and have a Content property, e.g. Button.
Then you can override the template to have an AdornerDecorator next to the ContentControl. This is different to what you previously tried as now the ContentPresenter is part of the same visual tree as the Adorner.
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Edit: Forgot that the AdornerDecorator needs to wrap the container, not just sit side-by-side.

Avalon Dock v2 Layout Issue

I am currently working with avalon dock v2, in the template of my document sources, i'm also putting in a docking manager.
Yes for each of my document, I want anchorable panes inside it. But when I try to do that, it doesn't work, it just shows the toString of the docking manager for each of the document, is there a way to fix that.
Also, how do i default dock my anchorable?
Thanks and Regards,
Kev84
In creating a template for the AvalonDock's LayoutDocument (via the LayoutDocumentControl) I also came across a similar issue. The solution was to set the ContentSource of the ContentPresenter to point to the Model property of my control. The code below illustrates it:
<!--The LayoutDocument is templated via the LayoutDocumentControl-->
<Style TargetType="{x:Type ad:LayoutDocumentControl}">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ad:LayoutDocumentControl}">
<ScrollViewer
Background="AliceBlue"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" SnapsToDevicePixels="True">
<!--Make sure that the ContentSource points the Model Property of the Control-->
<ContentPresenter
Content="{Binding Path=Content, UpdateSourceTrigger=PropertyChanged}"
ContentSource="{Binding Path=Model, UpdateSourceTrigger=PropertyChanged}"
/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
A similar approach should apply to your case. This is just a temptative answer (since I am also new to AvalonDock 2.0), but it may be worth trying.
Live long and prosper!

XAML: UniformGrid where you can define cells as not unifrom in size?

As a part of an ItemsControl style I'd like to have something that works similar ot Grid/UniformGrid as an ItemsPanel.
In its simplest form, the Style would look like this:
<Style TargetType="{x:Type ItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="2" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style>
<Setter Property="Control.Margin" Value="10"/>
</Style>
</Setter.Value>
</Setter>
</Style>
and I would use it like this:
<WrapPanel Orientation="Vertical">
<ItemsControl>
<TextBlock Text="Label1:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label2:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label3:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label4:"/>
<TextBlock Text="ThisWillBeBoundButIsSomewhatLongerThenTheOtherProperties" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label5:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
<ItemsControl>
<TextBlock Text="Label6:"/>
<TextBlock Text="ThisWillBeBound" />
</ItemsControl>
</WrapPanel>
As you can see, you would throw a Label for a property into this plus a binding to that property and they would stick together even if things would wrap around becuase of different sizes of the app window for example.
The nice thing here about theUniformGrid is that it seems that if one Label is longer the others will get the same space meaning the bound properties would line up neatly (why this happens I don't understand because these should be seperate UniformGrids I guess). Problem here is that the cell width of the Label part and the Property part is the same, so if the property is long there will be a large gap between the Label and the Property.
Using normal Grid instead would mean I'd have to set the Grid.Column="0" and Grid.Column="1" everyplace I put items into this ItemsControl. That's not really what I wan't.
Is there a way for me to have some sort of grid that lines up like the uniform one but doesn't stratch all columns when one only needs to be and assumes you are putting into columns the same way you declare the items?
The way I've typically seen this sort of scenario handled is via a combination of Grid+IsSharedSizeScope+ListView+DataTemplate.
In this case, the label text (i.e. "Label1:") and entry text (i.e. "ThisWillBeBound") would be in a single item type and a collection of that type of item would be bound to the list view. The Grid.IsSharedSizeScope allows for sharing column size info between different entries while using a template - very handy.
There's a great example of this at http://www.wpftutorial.net/DataTemplates.html. Is this the sort of scenario you're looking for?

XamDataGrid Collection Column

Is there a way to bind to a collection column in a XamDataGrid DataSource?
What i am trying to do is to show all the items of the specific column collection in a single grid field. (using the appropriate templates).
Hope it makes sense to you all. Let me know if you need me to clarify things a little bit more.
I finally found the answer.
I just used a Wrapper class to host the collection and bind to the column to the Wrapper class property instead of the collection property.
After that, making the appropriate template is very easy.
Here is an example:
<Style x:Key="ValidationsStyle" TargetType="{x:Type igDP:CellValuePresenter}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type igDP:CellValuePresenter}">
<ContentControl DataContext="{TemplateBinding Value}">
<ItemsControl ItemsSource="{Binding Validations}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ValidationName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ContentControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

WPF ControlTemplate with foreach?

I currently try to create classes for a paint-like WPF application. I have to base classes LineMovement (line from StartPoint to EndPoint) and PathMovement (line going through all points specified in a property Points of type PointCollection). These classes inherit from Control and get their looks through a ControlTemplate.
Now I want to add (what I call) PointMovers to the ControlTemplate. These should be little visual elements residing on each of the points in either of the Movement classes. They should become a kind of grip mechanism to drag the underlying point around.
The problem is of course that I don't know a way to create a variable number of elements in a ControlTemplate. It would be cool if I could do something like this:
<Style x:Key="{x:Type mov:PathMovement}" TargetType="{x:Type mov:PathMovement}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type mov:PathMovement}">
<Grid>
<Polyline Points="{TemplateBinding Points}" />
<!-- interesting part start -->
<foreach loopvariable="Point" in="{TemplateBinding Points}">
<PointMover Point="Point" />
</foreach>
<!-- interesting part end -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is this possible? Do you have another approach in mind that could work?
Thanks in advance!
Use an ItemsControl in conjunction with an ItemTemplate:
<ItemsControl ItemsSource="{Binding Points}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- rendered for each point -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
By the sounds of your use case, you may also want to read up on AdornerLayers.

Resources