Archive

Posts Tagged ‘WPF’

Textblock showing full text in tooltip when text truncated inside control

June 3, 2012 1 comment

This post describes implementation of custom textblock which will show the full text of the textblock in tooltip when Text can not be shown fully inside the given width of textblock control.

Textblock has property named “TextTrimming”. Value set for this property defines how text is trimmed when it overflows from the edge of Textblock. When “TextTrimming” property is set to “WordEllipsis’ / “CharacterEllipsis” and text value can not be shown fully in given width then text will truncate with “…” (i.e. ellipsis) shown at the end of text. Now one option to show the full text to user is through Tooltip. This can easily be achieved by binding text value as tooltip. However, the heck is showing full text value as tooltip only when needed i.e. when text has been truncated inside Textblock.

Unfortunately, Textblock doesn’t provide any property to indicate that text has been truncated / trimmed. Hence, we need to detect when the text has been truncated i.e. text size has increased beyond the width of textblock’s width. So now the problem is measuring width of text considering text settings applied. “FormattedText” class provided by Microsoft can help us for this. “FormattedText” takes into consideration FontSize, FontStyle, FontWeight, FlowDirection, current culture, etc. while calculating the width of text. Following code snippet shows how to measure text width using “FormattedText”.

Typeface typeface = new Typeface(this.FontFamily,
                this.FontStyle,
                this.FontWeight,
                this.FontStretch);            

// FormattedText is used to measure the whole width of the text held up by this container.
FormattedText formmatedText = new FormattedText(
                this.Text,
                System.Threading.Thread.CurrentThread.CurrentCulture,
                this.FlowDirection,
                typeface,
                this.FontSize,
                this.Foreground);

After getting the FormattedText object, just Check

formmatedText.Width > this.ActualWidth

to determine whether text has been truncated or not.

I have attached herewith the full implementation of Custom TextBox class (TextBoxEx) in a word file. In the implementation when Tooltip is opening, it is checking whether text has truncated or not. If text has not truncated then tooltip won’t be displayed (as it is not necessary because full text is anyway visible). Also, in order to show the tooltip, text property of the Textblock should be bound with the tooltip.

ToolTip="{Binding Path=Text, RelativeSource={RelativeSource self}}"

It is pretty obvious that if binding for tooltip is not set then this control will not work.

This one is pretty simple fix for the problem and it works well in the scenarios I have tested so far. Any feedback/bug/enhancement request on this is welcome.

TextBlockEx

Advertisements

Interop & IDataErrorInfo

September 17, 2011 Leave a comment

Despite of all the interop support available sometimes you will still come across some tricky issues which will be difficult to overcome. One such problem I faced recently. I had to configure the Dialog with MFC PropertySheet control. This PropertySheet control was holding few Property pages. These property pages didn’t had any MFC controls as content but hosting the user controls developed in WPF. First I will write very briefly about how to load the WPF user control inside the MFC container and then I will explain about my tricky problem and how I fixed it.

Hosting of WPF user control as content of PropertyPage wasn’t that challenging. In order to host the WPF content inside property page, first HwndSource needs to be configured. In order to create HwndSource, first you need to create HwndSourceParameter. Typical configuration for HwndSourceParameter can be as under :

System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew System::Windows::Interop::HwndSourceParameters (<Window Name>);

// X position where WPF content to be placed
sourceParams->PositionX = x;
// Y position where WPF content to be placed
sourceParams->PositionY = y;
// height of the WPF content
sourceParams->Height = height;
// width of the WPF content
sourceParams->Width = width;
// Handle for the Parent window inside which WPF content to be hosted
sourceParams->ParentWindow = IntPtr(parent);
// style attributes as needed (“WS_TABSTOP” style needs to be set if WPF content needs to get focus while tabbing
sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP;

Another important property for HwndSourceParams is “ResetFocusMode”. Default value for this property is “Auto”. Setting this property to “Auto” makes sure that when when the PropertySheet control (in my case) looses the focus and receives focus back the control which had focus prior to loosing focus retains the focus back. If you set this property to “None” then, none of the controls inside the page will have focus when propertysheet control receives the focus.

// now create HwndSource using this parameters
System::Windows::Interop::HwndSource^ hwndSource = gcnew HwndSource(*sourceParams)

Now suppose I have a WPF user control named “PageUserControl” then create instance of this user control.

PageContentUserControl^ pageContent = gcnew PageContentUserControl();
//Now set this user control as RootVisual of HwndSource object. 
hwndSource->RootVisual = pageContent ;

With above code in place it is possible to host the WPF content inside MFC control. This is just basic information which one should know in order to host the WPF content inside MFC container however somewhat plumbing work will be needed depending upon MFC container control in which you are placing the WPF control.

After hosting the control I had one more issue to deal with. My User control developed in WPF had few checkboxes, text boxes, etc. as it’s content. In order to validate my inputs and giving visual indication about the data validation failure, I had implemented interface “IDataErrorInfo”. (Now how this interface is implemented and how it works is not covered in this Post. Google it to find more on it)

When “IDataErrorInfo” interface implemented and bound value to the control is invalid, control will have a red border around it to indicate user about the validation failure. Also, when you set focus on the control like check box through tabbing, you will not be able to see the dotted line around check box when it receives the focus. Following figure shows the focus styles for each case. When User Control is hosted within MFC container, you will assume that “IDataErrorInfo” implementation should work but infect it won’t.

The problem of not being able to see all such decoration is absence of Adorner layer. All these error templates and focus styles etc. are drawn inside the AdornerLayer. The WPF window has an AdornerLayer by default, so we can always see validation errors in WPF. When hosting a user control in MFC, adornerlayer is not available by default and need to add an AdornerLayer into your UserControl to support adorners.

So in order to view all such Focus styles / Error template styles, we need to decorate the UserControl with AdornerDecorator. So following code should do the fix for you :

<UserControl x:Class="TestPjt.TestUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:TestPjt"
             mc:Ignorable="d" 
             d:DesignHeight="50" d:DesignWidth="300">
    <AdornerDecorator>
        <Grid>
              <TextBox x:Name="txtbox"/>
        </Grid>
    </AdornerDecorator>
</UserControl>

This fix will start showing the expected focus and error template style for each control. HTH!!

Order of Property and Event Processing in WPF

December 20, 2008 Leave a comment

At run-time, event handlers are always attached before any properties are set for an object declared in XAML (excluding the Name property, which is set immediately after object construction). This enables appropriate events to be raised in response to properties being set, without worrying about the order of attributes used in XAML.

Categories: WPF Tags: , ,