WPF discussions 08082009

Jaime Rodriguez
On Windows Phone, Windows Presentation Foundation, Silverlight and Windows 7

WPF discussions 08082009

  • Comments 0

Raw/unedited useful WPF advise..


Subject: Control Verifier
From: Samantha Durante, our controls PM

Answer:
I just wanted to let you know that we’ve just released Version 0.1 of the WPF Control Verifier tool. 
WPF Control Verifier is a tool that verifies the correctness of WPF Controls. This tool is geared towards WPF Control developers with the goal of providing a set of verifications that all controls can run and consume. Version 0.1 includes one category for verification – default style verification. These tests verify that your control can be styled such that its dependency properties are inheriting or template binding correctly. Future versions will include additional categories of verification.

You can download this tool in the new WPF Test Tools release at the WPF Codeplex site.  


Subject: Application checking .NET 3.0 is installed
What's the best way to determine if the user's computer has .NET 3.0 installed?

Answer:
Check the Registry.
The official guide:
http://msdn.microsoft.com/en-us/library/aa480198.aspx#netfx30_topic14


Subject: RE: Binding doesn't seem to work: System.Windows.Data Error: 4
Long discussion on how RelativeSource (binding to Ancestor) is indeterminate with regards to when parent is added to the tree;

Answer:
In general, RelativeSource looking for an Ancestor type isn't robust against delayed addition to the tree, and not at all against reparenting.  I only learned this earlier this week, debugging a similar issue.  Consider instead making "MyProperty" an inheritable property, and just binding to Self, MyProperty.

(Jaime’s personal take added now).  I do use RelativeSource within generated items in ItemsControls. Seems usable there and seems like a good place to apply it; if the scenario was different (less items in particular and shallow trees) then inherited property sounds good too.


Subject: Knowing if a control is partly occluded

I’m working on adding tooltips to controls that are partly occluded on mouse hover (like the Outlook folders pane does). What’s the right way to know whether something has been partly occluded?

Answer:

///<summary>
/// This eliminates the part of bounding rectangle if it is at all being overlapped/clipped by any of the visual ancestor up in the parent chain
///</summary>
internal Rect CalculateVisibleBoundingRect()
{

    Rect boundingRect = Rect.Empty;

    boundingRect = new Rect(_owner.RenderSize);
    // Compute visible portion of the rectangle.

    Visual visual = VisualTreeHelper.GetParent(_owner) as Visual;
    while (visual != null && boundingRect != Rect.Empty && boundingRect.Height != 0 && boundingRect.Width != 0)
    {
        Geometry clipGeometry = VisualTreeHelper.GetClip(visual);
        if (clipGeometry != null)
        {
            GeneralTransform transform = _owner.TransformToAncestor(visual).Inverse;
            // Safer version of transform to descendent (doing the inverse ourself and saves us changing the co-ordinate space of the owner's bounding rectangle),
            // we want the rect inside of our space. (Which is always rectangular and much nicer to work with)
            if (transform != null)
            {
                Rect clipBounds = clipGeometry.Bounds;
                clipBounds = transform.TransformBounds(clipBounds);
                boundingRect.Intersect(clipBounds);
            }
            else
            {
                // No visibility if non-invertable transform exists.
                boundingRect = Rect.Empty;
            }
        }
        visual = VisualTreeHelper.GetParent(visual) as Visual;
    }

    return boundingRect;
}

 


Subject: RE: BitmapImage.StreamSource - best practice for closing the stream?
If I use BitmapImage, then set in the StreamSource, no one seems to ever close the stream.  The net effect is this locks the file in memory – preventing file renames, etc.

Answer:
By default images are delay decoded. Set the CacheOption to BitmapCacheOption.OnLoad to force eager decode of the stream. 


Subject: CollectionView, Sort Descriptions, Turkish I, and Custom Sorts

Given a CollectionView, and some SortDescriptions, how does one ensure that the sorting is correct for the current culture? Should I use Custom sort?

Answer:
ListCollectionView’s sorting uses the Culture property.   If you don’t set this, it’s set to agree with the Language of the client element.  For example,

                <ListBox  ItemsSource=”…” Language=”tr-TR”/>

will sort in Turkish.

The CustomSort lets you define your own comparison logic.  You can pay attention to whichever columns you like, and choose case-sensitive or insensitive.


Subject: DecodePixelWidth
I’d like to investigate DecodePixelWidth to reduce memory consumption when viewing large images on the design surface. 
Is there a way without loading the image itself to grab the metadata that would tell me what the size of the image is?


Answer:
Unfortunately no.


Subject: Getting HyperLink content
I'm trying to get the text of a hyperlink via code, and I can't find it.

Answer:
TextRange range = new TextRange(link.ContentStart, link.ContentEnd);
string text = range.Text;


Subject: Implement Attribute x:Uid
Is it possible to implement the localization attribute x:Uid? We would like to implement this attribute without inheriting from UIElement and make it possible to use XAMLReader/XAMLWriter API.

Answer:
If you’re working with 4.0, you can set the UidPropertyAttribute on your type and it’ll set whatever property you need it on.
There is no way in 3.X.  Uid was hard coded in the system to only work with UIElements. Uid is ignored on all other types at runtime.


Subject: Invisible Hyperlink can still receive focus

For following xaml, the hyperlink hyper1 is invisible, but can still receive keyboard focus, I need to set it’s Focusable to false to stop it receiving focus, is this the expected behavior?
<TextBlock Visibility="Collapsed"><Hyperlink x:Name="hyper1"/></TextBlock>

Answer:
This appears to be a bug in TextBlock and is not specific to Hyperlink.  If you replace the Hyperlink with a Button, it loses Tab navigation completely while other panels work as expected.
 


Subject: Mouse wheel in winform interop scenario

Hi,

Our project embed a Dunas chart control inside a WindowsFormHost. We want to support mouse wheel on it for zooming. The dunas document specifically call out that mouse wheel does not work unless the control is focused (indeed, when there is no focus, the chart does not receive mouse wheel message, and I guess this is not specific to dunas control but to general winform control too). The  initial thought is to programmatically set focus on the dunas control. However, this is apparently bad that if other elements get focus this stops working.

Now my goal is to enable mouse wheel without messing with focus. If I am able to intercept mouse wheel message (no matter focused or not) I can work with the control to simulate zooming. The first attempt was to derive from WindowsFormHost and override WndProc to see if I can receive mouse wheel message there without being focused. It did not working (not surprising).

After looking into MSDN I found ComponentDispatcher class. So I tried the following code:

ComponentDispatcher.ThreadFilterMessage += delegate(ref MSG msg, ref bool handled)

            {

if (msg.message == 0x20A) /*MouseWheel*/

                {

                    System.Diagnostics.Trace.WriteLine("Receiving mouse wheel message");

                    System.Diagnostics.Trace.WriteLine("msg window " + msg.hwnd);

                    System.Diagnostics.Trace.WriteLine("WindowsFormsHost handle : " + this.wfhost.Handle);

                }

            };

Well now I do get mouse wheel message. But I get ALL of them even if the mouse is not on the control. The windows handle in the message is not the same as reported by WindowsFormHost, it is actually the main window (which is logical since this essentially comes from main message pump).

Answer:
Windows will deliver the WM_MOUSEWHEEL to the HWND with focus.  So you will have to start from there.  You can either subclass that window proc, or you can use the ComponentDispatcher to watch the messages come through the message pump.  The HWND in the message will be whatever HWND has focus – such as the main App window.

You can then look at chart.IsMouseOver to decide whether or not to respond to the message.


Subject: Override tab ordering of panel

We implemented our custom Panel class and want to change the tab navigation behavior.
Does anyone know where to override the default behavior?

Answer:
You can set KeyboardNavigation.TabNavigation property on the custom Panel to the mode you like.
Then TabIndex property on subelements if you want to change the Tab traverse order.


Subject: Question with ReadOnly RichTextBox

I have a window that contains a RichTextBox control used to display read-only text. As such, I have set the IsReadOnly property to ‘True’ so that the text inside the RichTextBox is not editable. However, setting this property also disables many keyboard navigation commands, such as arrow up/down, page up/down. Some commands, such as text selection (Ctrl+A, Shift+Up/Down/Left/Right) still work. Does the RichTextBox require any additional configuration for the keyboard navigation commands to work when IsReadOnly is set to True?

Answer:

In <=3.5sp1, keyboard navigation is not fully supported when IsReadOnly is set to true. In 4.0, we’ve added a new property to TextBoxBase (IsReadOnlyCaretVisible) which enables both the caret rendering and keyboard navigation in read only mode.


Subject: Is it possible to utilize the functionality of DocumentViewer's FindToolBar programatically?
Answer:

Unfortunately the search API used by the document viewers is not publicly exposed and as far as I know there are no plans to expose it in the near future.

-----------------

Subject: SplashScreen Bug

Hello Folks,

Our client has a bug with the use of the SplashScreen class present in the Framework 3.5 Sp1. The bug are the same that the one describe in these differents threads:

· http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=378575

· http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=362735

It seems that this bug is corrected en the next release of WPF (4.0) But our client needs to release our application

Answer:

You can work around both of those issues using the existing SplashScreen by not using the fade out.To do that you’ll need to write a main method that looks something like this:

[STAThread]

public static void Main(string[] args)

{

SplashScreen sp = new SplashScreen("splash.png");

    sp.Show(false);

Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => sp.Close(TimeSpan.Zero)), DispatcherPriority.Loaded);

    WpfApplication1.App app = new WpfApplication1.App();

    app.InitializeComponent();

    app.Run();

}

 


Subject: Question about ListView sorting feature

When I am developing sorting feature for the ListView, I observed a interesting behavior. Could someone help to identify whether it is by design? I also attached the project.

Say I have a listview, and the values in column “Test Enabled” are all the same. When I click the column header, the column will be sorted.

Step 1, see picture 1, no column is sorted.
Step 2, click column header of column “Test Enabled”, column “Machine” is sorted. (Could anyone tell me why?).
Step 3, click column header of column “Test Enabled”, no changes.
Step 4, click column header of column “Test Enabled”, no changes.

The way I implement the sorting is very simple:

//sort the machines.

ICollectionView view = CollectionViewSource.GetDefaultView(this.Machines);

view.SortDescriptions.Clear();

view.SortDescriptions.Add(new SortDescription(sortColumn.Tag as string, direction));

view.Refresh();

Questions:

1. In step 1, why column “Machine” is sorted when I try to sort column “Test Enabled”?

2. In step 3, 4, why wouldn’t the list view change anymore?

Picture 1:

clip_image001

Picture 2:

clip_image002

Picture 3:

clip_image003

Picture 4:

clip_image004

Answer:

LCV.CustomSort only specifies the comparer, the actual algorithm is implemented by Array.Sort (it’s a Quicksort).

When you click the ‘Test Enabled’ column, we sort by that column only.  Since all the values in that column are equal, any permutation of the rows is sorted.  The actual result depends on the implementation of the sort algorithm, not on the data at all.  (In other words, it’s not really true that it sorts by ‘Machine’;  all you can say is that the algorithm permutes the rows in some arbitrary way.)  When you click the column again and nothing changes, that only means that Array.Sort produces the same result given the same input – not terribly surprising.

It’s pretty difficult to implement a sorting algorithm that is both stable (records with equal keys end up in the same relative order as they began) and efficient (O(n log n) with small coefficient).    I think you’ll find that the algorithm Marco pointed to (http://thomas.baudel.name/Visualisation/VisuTri/inplacestablesort.html) is quite a bit slower than Quicksort in practice.

There’s no way to replace the sorting algorithm used by the collection view.  If you want a more intuitively deterministic result, you can add a second SortDescription that says how to compare records that are equal w.r.t. the first SortDescription.

BTW, your code actually sorts the array twice.  The collection view automatically refreshes whenever you change the sort descriptions, so you sort once for view.SD.Add() and a second time for view.Refresh().   If you added a second SortDescription, you’d sort three times.  The right way to do it is:

                using (view.DeferRefresh())

                {

                                view.SortDescriptions.Clear();

                                view.SortDescriptions.Add(….);

                                view.SortDescriptions.Add(…);

                }

This turns off the automatic refresh until you’re done changing things.