WPF: How to embed button inside text flow (wrap text around button)? - wpf

I'd like an advice to the following problem: I want to embed a Button into a text flow, but when I embed a Button and Label (or TextBlock) into the WrapPanel, I get the first figure:
alt text http://sklad.tomaskafka.com/files/wpf-wrappanel-problem.png
I think that one of solutions could be FlowDocument, but I feel that this is far too heavy for a control simple like this (which could be used in several hundred instances). Do you have some other ideas about how to implement this? Thank you!
EDIT:
One solution could be the following (I didn't know it was possible to put more stuff into TextBlock), but I would lose the ability to bind (which I need):
<TextBlock TextWrapping="Wrap">
<Span>
<Button x:Name="MyButton" Command="{Binding Path=MyCommand}" Content="+" />
<Run x:Name="MyLabel" Text="{Binding Path=Subject}" />
<!--
Problem: binding makes following error:
A 'Binding' cannot be set on the 'Text' property of type 'Run'.
A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
-->
</Span>
</TextBlock>

To bind to Run.Text, checkout the BindableRun class by Fortes. Simple to implement, I use it all over my projects.

I found that implementing BindableRun correctly is pretty tricky - and almost all other available implementations will cause an exception from wpf layouting engine when the bound content changes from null to something non-null - see this problem, keyword "Collection was modified; enumeration operation may not execute."
Corrrect implementation from Microsoft is here - it shows how tricky this really is.

Solution: BindableRun class + the following markup:
<TextBlock>
<Button x:Name="MyButton" Command="{Binding Path=MyCommand}" Content="+" />
<common:BindableRun x:Name="Subject" BindableText="{Binding Path=Subject}"/>
</TextBlock>

Funny thing it works on the designer of a UserControl...
In that case, using the Property Change of your control to set the value to the Run is enough. I mean, if you had something like:
<TextBlock>
<Run Text="{Binding ElementName=thisCtrl, Path=Description}" />
</TextBlock>
Then just name the run, and on your property change handler of your UserControl DependencyProperty get/set the value.

Related

WPF Binding up and down the Visual Tree

From a control in a WPF XAML view, I need to access the properties of another control that I can reach in the Visual Tree only when walking up to a common parent control and then down from there.
As an example:
<PageUserControl>
<Grid>
<TextBlock Text="Some example text" />
</Grid>
<TextBlock Text="{Binding Source={RelativeSource Mode=FindAncestor, AncestorType=PageUserControl, Path=??? I want to access the TextBlock}" />
</PageUserControl>
I want to access the text property of the first text block from the second text block (this is just an example).
What I would need is a way to combine relative sources, first one to go up the visual tree and find the PageUserControl, second one to go down the visual tree from there and find the grid and then finally a third one to find the text block within the grid.
Am I missing something here or is it just not possible?
I cannot add control IDs or something like this, it has to work with control types only.
I was thinking about something like a relative source that takes a XPath syntax, but it seems as if this was meant for another purpose (binding XML documents).
Maybe another idea?
Thank you!
I found a solution for my problem. It is possible using this approach:
<PageUserControl>
<Grid>
<TextBlock Text="Some example text" />
</Grid>
<TextBlock Text="{Binding Path=Children[0].Children[0].Text,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=PageUserControl}}" />
</PageUserControl>
While not very flexible, it is good enough for me.

SciChart: Custom RolloverModifierLabel for multiple DataSeries bound from code

Before I updated to the latest version of SciChart, I had this custom rollover modifier that displayed multiple values for any given point I "rolled over".
It was implemented like this:
<sci:RolloverModifier
DrawVerticalLine="True"
ShowTooltipOn="Always"
SourceMode="AllVisibleSeries"
TooltipLabelTemplate="{StaticResource RolloverLabelTemplate}" />
RolloverLabelTemplate was a ControlTemplate:
<ControlTemplate
x:Key="RolloverLabelTemplate"
TargetType="sci:TemplatableControl">
<Grid>
...
Now the RolloverModifier.TooltipLabelTemplate is gone from the API and seems to be replaced by TooltipTemplate, which takes a DataTemplate, not a ControlTemplate. I tried making an analogous DataTemplate:
<DataTemplate
x:Key="SomeTemplate"
DataType="s:XySeriesInfo">
<Grid>
But when I try to assign it to the RolloverModifier,
<s:RolloverModifier
...
TooltipTemplate="{StaticResource SomeTemplate}" />
I get the following exception:
Unable to cast object of type
'SciChart.Charting.ChartModifiers.RolloverModifier' to type
'SciChart.Charting.Visuals.RenderableSeries.BaseRenderableSeries'.
I've tried to follow this documentation: https://www.scichart.com/documentation/v4.x/webframe.html#RolloverModifier.html
and on the topic of styling the tooltip template, it suggests to have a RolloverModifier, but to add the TooltipTemplate to the RenderableSeries:
<s:SciChartSurface.RenderableSeries>
<s:FastLineRenderableSeries s:RolloverModifier.TooltipTemplate="{StaticResource XyTooltipTemplate}"/>
</s:SciChartSurface.RenderableSeries>
<s:SciChartSurface.ChartModifier>
<s:ModifierGroup>
<s:RolloverModifier ShowTooltipOn="Always" />
</s:ModifierGroup>
</s:SciChartSurface.ChartModifier>
</s:SciChartSurface>
This is a problem for me, because I don't have the RenderableSeries defined in xaml. They are bound to the view model:
<sciVisuals:SciChartSurface
...
SeriesSource="{Binding SciSeries}">
there will be more than one, and in fact I don't even know how many. How can I customize the rollover tooltip label in this case?
In SciChart WPF v4.x or later, it is necessary to apply the TooltipTemplate to the series, because many users requested the ability to individually style series. For example a Candlestick series should have a different tooltip than a Line series.
Please see the SciChart WPF Documentation for applying a RolloverModifier TooltipTemplate in v4+:
Styling the Tooltip Item Template
SciChart by default has a number of Tooltip templates which are unique to the series type.
To change the Tooltip template, use the RolloverModifier.TooltipTemplate attached property:
<s:SciChartSurface >
<s:SciChartSurface.Resources>
<!-- Tooltip Template for an XyDataSeries binds to XySeriesInfo -->
<!-- Check out the properties on XySeriesInfo to see what you can bind to -->
<DataTemplate x:Key="XyTooltipTemplate" DataType="s:XySeriesInfo">
<StackPanel Orientation="Vertical">
<TextBlock Foreground="White">
<Run Text="Series: "/>
<Run Text="{Binding SeriesName, StringFormat='{}{0}:'}"/>
</TextBlock>
<TextBlock Foreground="White">
<Run Text="X-Value: "/>
<Run Text="{Binding FormattedXValue}"/>
</TextBlock>
<TextBlock Foreground="White">
<Run Text="Y-Value: "/>
<Run Text="{Binding FormattedYValue}"/>
</TextBlock>
</StackPanel>
</DataTemplate>
</s:SciChartSurface.Resources>
<s:SciChartSurface.RenderableSeries>
<s:FastLineRenderableSeries s:RolloverModifier.TooltipTemplate="{StaticResource XyTooltipTemplate}"/>
</s:SciChartSurface.RenderableSeries>
<s:SciChartSurface.ChartModifier>
<s:ModifierGroup>
<s:RolloverModifier ShowTooltipOn="Always" />
</s:ModifierGroup>
</s:SciChartSurface.ChartModifier>
</s:SciChartSurface>
What I suggest in order to style these despite using the MVVM API is to create your styles in XAML and apply them using the SeriesBinding MVVM API.
There is an FAQ in the SciChart WPF Documentation on how to style a tooltip when using the MVVM API here.
A lot of customers ask us how to style various attached properties used in SciChart in the MVVM API. For example, the given following attached properties, how do we convert this to the MVVM API?
The solution is simple, to use our method of Styling the RenderableSeries presented in Worked Example - Style a Series in MVVM.
Simply declare the attached properties and tooltip templates in a style in your View.
Now, apply the style using BaseRenderableSeriesViewModel.StyleKey property. SciChart will pick up the style and do the rest.
If you are still using the older, SeriesSource API (note this is now obsolete as of v4.x) then I suggest declare your style in XAML and apply it using this technique to access a style in code-behind.

WPF show small number beside all Controls

I have many FrameworkElements (TextBlock, CheckBox, ListBox..) and I would like to make something allowing me to show a small number besides every one control.
Some text ³
I came with the idea to write a MarkupExtension, where I could write that number like this:
..
<TextBlock Text="Some Text" SomeExtension="3" />
..
and then to add it somehow to the template of the Control.
But I'm sure, you guys have better solution for this problem ;)
One way to go with it would be create a Attached Property. Upon setting it on a control, a custom Adorner would be added for that control showing specified number.
Use the tag property to provide the number you want and inside the custom template databind to the property
<TextBlock Text="Some Text" Tag="3" />
and inside the controltemplate
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"/>

Context Menu for textbox

What exactly I want to do is that there are 2 tables,ie, user and userprofile and both of them have almost identical fields. I shall take example of the email field. There is a textbox and the User table email field value is displayed in it. What I want to do is, have a context menu such that when the user right clicks on the textbox, the menu displays both the User and UserProfile email field values. – developer 1 hour ago
Whatever value one selects from the context menu the textbox then displays that value. You can use Binding Email1 and Binding Email2, as I have no problems getting those two values from database so I shall change my code accordingly. As I am new to WPF and .NET framework itself, I am not sure how to achieve this. Please let me know if I have made myself clear this time.
I am not sure how to handle commands and events. Can anybody show me the code to accomalish this..
<TextBox Style="{StaticResource FieldStyle}" Text="{Binding Email1, UpdateSourceTrigger=PropertyChanged}">
<TextBox.BorderBrush>
<MultiBinding Converter="{StaticResource TextBoxBorderConverter}">
<Binding Path="Email1"/>
<Binding Path="Email2"/>
</MultiBinding>
</TextBox.BorderBrush>
</TextBox>
Thanks in advance
At risk of giving you a WPF/MVVM noob answer and getting flamed, here goes. I can't advise you on databinding with databases since I've never done it, so I will just give you the XAML and it's up to you to work on the database end.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBox Height="28" Text={Binding PreferredEmail}">
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Header="{Binding Email1}" Command="{Binding Email1Command}" />
<MenuItem Header="{Binding Email2}" Command="{Binding Email2Command}" />
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</Grid>
</Page>
In the databinding to objects case, PreferredEmail, Email1, and Email2 would bind to a dependency property or a property that raises the PropertyChanged event. This is how your ViewModel (or whatever you want to call the lower-level code) will update the data. If you change those values in code-behind, ultimately it'll get reflected in the context menu automagically. Then you have to implement two ICommand-based classes to handle the setting of PreferredEmail.
I think it's super lame to implement two command handlers, and it certainly won't scale well if you have to add more email sources. I think a better solution would be to use one command handler and a CommandParameter that is the selected MenuItem header, but I don't know how to do that. But in any case, the two command handler solution will still work if you're in a bind.

Silverlight 4 RichTextBox Bind Data using DataContext

I am working with Silverlight 4 and trying to put my test apps multilingual but I am having some trouble when I arrive to the "RichTextBox" control. I am able to bind it properly by doing back-code (c#), but when trying using the "DataContext" attributes I am not able to load it at all.
I have created a FormatConverter that return a Block (paragraph) for testing and my code where I have my RichTextBox looks like:
<RichTextBox x:Name="rtaTest" BorderThickness="0" IsReadOnly="True" UseLayoutRounding="True"
DataContext="{Binding Source={StaticResource Localization}, Path=Home.MainContent, Converter={StaticResource ParagraphFormatConverter}}">
</RichTextBox>
I am wondering if there is a way of binding a RichTextBox from the XAML.
Run seems to support databinding in SL4, as in:
<RichTextBox>
<Paragraph>
<Run Text="{Binding Path=LineFormatted}" />
</Paragraph>
</RichTextBox>
I think you may be a little confused about the used of the DataContext. You might for example have some Rich text where some children of one or more InlineUIContainer elements may retrieve their text from a property of some object. You would assign the object to the DataContext.
Whilst I'm not quite sure what you were expecting to achieve but I suspect that what you really need is for your converter to actually return a BlocksCollection (even if it just contains the single Block you were originaly returning) and then to bind as:-
<RichTextArea x:Name="rtaTest" BorderThickness="0" IsReadOnly="True"
UseLayoutRounding="True"
Blocks="{Binding Source={StaticResource Localization},
Path=Home.MainContent, Converter={StaticResource ParagraphFormatConverter}}" />
This FillFromXml is a WPF thing? Don't see it in Silverlight.
Blocks cannot be set, they can only be fetched. One way to set the blocks for a RichTextArea is
public static void UpdateRichTextArea(RichTextArea area, string xmlText)
{
if (area == null)
return;
area.Blocks.FillFromXml(xmlText, true);
}

Resources