Binding collection of objects on a tooltip - wpf

Can someone tell me how to bind the tooltip of a StackPanel with its children?
Here's some code I used:
<StackPanel>
... (some UI like grid, textblock, border, ...)
<StackPanel.ToolTip>
<ToolTip Placement="RelativePoint" Padding="0" HasDropShadow="False">
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=StackPanel, AncestorLevel=3}, Path=Children}"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=StackPanel, AncestorLevel=3}, Path=ActualWidth}"
Height="11">
</ItemsControl>
</ToolTip>
</StackPanel.ToolTip>
<StackPanel>
I first tried with VisualBrush that was binded on a ToolTip, but this shows only the non-hidden controls, so when a child was hidden (invisible for the eye, not for the PC) in the StackPanel, then that child was also invisible in the ToolTip.
Also want to say that the binding with ActualWidth works. Now i have a tooltip that has the right measures, but there is no content in it (it's just a filled white space rectangle).
Someone please help me?? :)
FYI, what i want is the same like you bind on the Content property of a Textblock with his tooltip. The only difference is that i want to bind on a collection of objects instead of a string value.

The problem is probably caused by the fact the ToolTip is not part of the StackPanel's visual tree.
Therefore the StackPanel is not an Ancestor of the ToolTip -> hence why the RelativeSource binding wont work.

In WPF you are supposed to use MVVM, because it will allow you to bind always to data, instead of other controls. You have to think about WPF controls as data visualizers, not as data containers.
So, if you are using MVVM, just bind the Tooltip ItemsControl to your (observable?)collection of items.

Related

Difficulties binding colors for WPF ComboBoxItem ItemTemplate with TemplateBinding

I'm trying to implement a simple combo box (bound to a list of strings) that shows each item as the string label on the right and icon (which is in the form of a GeometryDrawing) on the left. I want the items in the box to inherit the colors I'm using because I've got a custom scheme (with a dark background and white text).
I am able to use TemplateBinding (binding to to ComboBoxItem.Foreground) to make the colors of the text label appear properly but am not able to do the same for the Geometry drawing and I can't figure out why.
Here an image of what I am trying to achieve.
Note that the icon shows up nicely to the left of the name. This only works if I explicitly specify "White" as the brush of the GeometryDrawing.
Below is the XAML I'm using to do make this work.
<tk:RadComboBox ItemsSource="{Binding PostAnalysisRoutines}"
Grid.Row="8" Grid.Column="2"
Text="{Binding Settings.PostCaptureAnalysisRoutine, Mode=TwoWay}">
<!--
Each item in the box is a horizontal stackpanel with an icon for
the routine on the left and the routine name on the right
-->
<tk:RadComboBox.ItemTemplate>
<DataTemplate DataType="sdk:AnalysisRoutine">
<StackPanel Orientation="Horizontal">
<Image Width="30" Height="30">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<!-- ***FORCE TO USE "White" here WHY???*** -->
<GeometryDrawing Brush="White"
Geometry="{Binding Converter={StaticResource PathGeometryConverter}}"
/>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<!-- *** BUT ITS OK TO USE TemplateBinding HERE. WHY??? *** -->
<Label Foreground="{TemplateBinding tk:RadComboBoxItem.Foreground}"
Background="{TemplateBinding tk:RadComboBoxItem.Background}"
Content="{Binding}"/>
</StackPanel>
</DataTemplate>
</tk:RadComboBox.ItemTemplate>
</tk:RadComboBox>
A couple of notes:
I am using Telerik's RadComboBox here but I see a similar problem if I switch this over to regular WPF ComboBox.
I am able to use TemplateBindings for the Label's foreground and background colors to bind to the ComboBoxItem. Those work fine.
The PathGeometryConverter just takes the string name and finds a predefined PathGeometry resource for it.
Unfortunately I am NOT a able to use that same TemplateBinding for the GeometryDrawing's "Brush" property. When I try...
<GeometryDrawing Brush="{TemplateBinding tk:RadComboBoxItem.Foreground}"
Geometry="{Binding Converter={StaticResource PathGeometryConverter}}"
/>
I end up with this:
Therefore I am forced to explicitly specify "White" as the brush color for the
Geometry drawing to make this work.
What is the proper way to make my GeometryDrawing in my template "inherit" the surrounding color scheme...? Is there some sort of TemplateBinding I am missing?
I think your problem is because you're using templatebinding combined with something that is coming out of a resource and or because it's several levels down from the thing being templated. If the geometry was directly in the template then I think it'd work.
What I suggest is you instead try a binding with relativesource and ancestortype tk:RadComboBoxItem, path=foreground.
Or relativesource templatedparent.
I would also use a path rather than an image. It might make very little difference in this case but paths can be sharper. You can bind the Data of a Path to a Geometry resource. Or at least I think you can, I usually set them to a dynamic or staticresource directly.

Extended WPF Toolkit RichTextBox display text vertically

I'm trying to bind a rich content (RTF format) to a rich text box (of Extended WPF Toolkit) via its Text property like this
<extToolkit:RichTextBox x:Name="rtbKIContent" Margin="8,8,8,8"
IsEnabled="{Binding IsEditable}"
Text="{Binding Content}">
<extToolkit:RichTextBox.TextFormatter>
<extToolkit:RtfFormatter></extToolkit:RtfFormatter>
</extToolkit:RichTextBox.TextFormatter>
<extToolkit:RichTextBoxFormatBarManager.FormatBar>
<extToolkit:RichTextBoxFormatBar />
</extToolkit:RichTextBoxFormatBarManager.FormatBar>
</extToolkit:RichTextBox>
Sometimes it works just fine, but there are circumstances that they just display the text vertically like this.
I don't know what's wrong with it...What should I do to make it display text from left to right like normal?
If you add a width to the RichTextBox, it should fix it.
I did this so it binds to the parent.
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Grid, AncestorLevel=1}, Path=ActualWidth}"
Note you will have to determine AncestorType for you. But you can do this too. Width="100"
Agree with "jmogera".
Need to set width for this issue.
HorizontalAlignment="Stretch" MinWidth="100"
You can set MinWidth to 100 and keep HorizontalAlign to streach if you want control to resize.

Using TemplateBinding inside DataTemplates

I'm creating a custom control, and I'm having problems binding UI elements inside a DataTemplate to the custom control's dependency properties.
There's a content control in my control that should change its content and content template according to a certain property, so I bound it this way -
<ContentControl Content="{TemplateBinding ControlMode}" ContentTemplateSelector="{StaticResource TemplateSelector}"/>
The Content Template selector is defined this way -
<ns:TemplateSelector x:Key="TemplateSelector">
<ns:TemplateSelector.Template1>
<DataTemplate>
<TreeView ItemsSource="{TemplateBinding TreeSource}"/>
</DataTemplate>
</ns:TemplateSelector.Template1>
<ns:TemplateSelector.Template2>
<DataTemplate>
<ListView ItemsSource="{TemplateBinding ListSource}"/>
</DataTemplate>
</ns:TemplateSelector.Template2>
</ns:TemplateSelector>
The problem is that the TreeView and the ListView can't be bound to their itemssource with TemplateBinding due to this error for example -
"Cannot find TreeSourceProperty on the type ContentPresenter"
I've been looking around for an answer and I found this answer that simple states that this is impossible.
How to use template binding inside data template in custom control (Silverlight)
So if this really is impossible, how else could I bind the elements inside my template to the DependencyProperties of the CustomControl?
Thanks!
In WPF you can use a binding with RelativeSource targeting the "templated" control.
e.g.
{Binding TreeSource,
RelativeSource={RelativeSource AncestorType=MyCustomControl}}
Edit: If you have a break in a tree you could possibly work around that by passing that control around, e.g.
<ControlThatOwnsPopup
Tag="{Binding RelativeSource={RelativeSource AncestorType=MyCustomControl}}">
<Popup>...
<TreeView ItemsSource="{Binding PlacementTarget.Tag.TreeSource,
RelativeSource={RelativeSource AncestorType=Popup}}"/>

Silverlight RelativeSource of TemplatedParent Binding within a DataTemplate, Is it possible?

I'm trying to make a bar graph usercontrol. I'm creating each bar using a DataTemplate.
The problem is in order to compute the height of each bar, I first need to know the height of its container (the TemplatedParent). Unfortunately what I have:
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Height, Converter={StaticResource HeightConverter}, Mode=OneWay}"
does not work. Each time a value of NaN is returned to my Converter. Does RelativeSource={RelativeSource TemplatedParent} not work in this context? What else can I do to allow my DataTemplate to "talk" to the element it is being applied to?
Incase it helps here is the barebones DataTemplate:
<DataTemplate x:Key="BarGraphTemplate">
<Grid Width="30">
<Rectangle HorizontalAlignment="Center" Stroke="Black" Width="20" Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Height, Converter={StaticResource HeightConverter}, Mode=OneWay}" VerticalAlignment="Bottom" />
</Grid>
</DataTemplate>
To answer your question RelativeSource only works in a ControlTemplate it doesn't work in a DataTemplate.
Is there a reason why the Silverlight Toolkit Chart controls don't work for you in creating a bar graph (or a Column Chart as the Tookit refers to vertical set of bars).
Have you tried the ActualHeight property? It should return you a value. RelativeSource with the TemplatedParent mode will work in a data template, but it will return the content presenter of the templated control/item, not the control/item itself (which it does when used in a control template). To experiment, put a button in the data template, and assign that binding expression (without the path) to its Tag property. Handle its Click event, and put a breakpoint in the event handler. Now when you run the project and click on the button, the breakpoint will be hit in your code, and you can see the object that it is binding to from the Tag property of the button (which you can see from the sender parameter). Hope this helps...

How can I change the visibility of elements inside a DataTemplate when a row is selected in a Silverlight datagrid?

I'm using the MVVM pattern. I've bound my items and I want to only show the edit button when a row is selected in the datagrid. It appears to be possible with triggers in WPF but we don't have triggers in Silverlight. I tried a TemplatedParent binding but I'm not sure what the TemplatedParent is in this case. We don't have RelativeSource ancestor in Silverlight either. At this point I'm going to look at a solution using the code behind...
<data:DataGrid.Columns>
<data:DataGridTemplateColumn IsReadOnly="True" Header="Name" Width="300">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock x:Name="textBlock" Text="{Binding Name, Mode=OneWay}" VerticalAlignment="Center" Margin="4,4,0,4"/>
<Button Margin="1,1,4,1" HorizontalAlignment="Right" VerticalAlignment="Center" Padding="7,4" Content="Edit" />
</Grid>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
There are a couple ways you could do this in silverlight, although I don't think any of them can be pure XAML solutions. With MVVM, you then create property in your view model that you bind to the SelectedItem property of the DataGrid. From there, there are two differnt options:
If the individual items in the DataGird are themselves other view models, then you can give them a property like "IsEditable" and bind it to the visibility of the button. When the SelectedItem fo the parent ViewModel changes, go and update the IsEditable property of all the child viewmodels
If you dont have child view models, you can handle the loaded event of the Edit button. In the code behind, bind the visibility of the button to the selecteditem property in your view model, but also set up a binding converter that takes in the original bound item as a converter parameter. In the converter, you can check if the selected item is equal to the originally bound item
If only Silverlight had a RelativeSource FindAncestor binding...
One kind-of hacky idea I could suggest would be to put your editing controls into a RowDetailsTemplate on the DataGrid itself, then set the RowDetailsVisibilityMode to VisibleWhenSelected.
It might not be what you're after look-wise, but it probably "solves" your particular use-case.
If it doesn't, then I'd probably violate MVVM here (very carefully). Usually DataGrids are the bastard child edge case; they almost all need some variety of code-behind.

Resources