Best wpf questions in March 2012

How to convert a pinyin string to chinese in C#

6 votes

I have a touch screen keyboard in my WPF application and I would like to allow the users to write in chinese.

I saw that there is an IME in Windows that allows to write in chinese with Pinyin. It works great but I'd like to customize it for my WPF application. (Especially the candidate list). I didn't find any documentation for this.

The idea will be that the user write in Pinyin with the virtual keyboard and there will be a list of choice with chinese ideograms next to the textbox.

Do you have any advice to achieve it? Maybe there is a library (not from Microsoft) that can make it and in this case I won't use the IME from MS?

Thanks in advance!

Rodrigue

http://www.microsoft.com/downloads/zh-cn/details.aspx?FamilyID=7D1DF9CE-4AEE-467F-996E-BEC826C5DAA2

http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=15251

Microsoft in fact has good components/libraries for that, but they are hidden here in the Visual Studio International Feature Pack.

Note that You need 1.0 SR 1 which provides the basic libraries, while 2.0 adds many WinForms or WPF controls.

Unit Testing WPF Application with siteoforigin pack Uri

5 votes

I have some unit tests that I'm writing for a WPF application, and as much as I've tried to avoid it, I have some code under test that instantiates a View. As soon as the view is instantiated, all the markup extensions, styles, etc are evaluated. To resolve this I've created a dummy Application and registered any required resources when the test assembly is initialized:

[TestClass]
public class AssemblyInitialize
{
    [AssemblyInitialize]
    public static void SetupTestAssembly(TestContext context)
    {
        if (Application.Current == null)
            new Application();

        var resources = new List<string>
            {
              "pack://application:,,,/AssemblyName;component/ResourceDictionary.xaml"
            };

       foreach(var resource in resources)
       {
           var uri = new Uri(resource);
           var dictionary = new ResourceDictionary { Source = uri };
           Application.Current.Resources.MergedDictionaries.Add(dictionary);
       }
    }
}

I've used this approach in the past, and it works ok.

I've run into a small snag with this approach. I have a few resources that use pack://siteoforigin: in the pack Uri, and when the tests instantiate this view I get an error about not being able to resolve the file.

The XAML:

<ResourceDictionary
   xmlns="...">

   <ImageBrush 
      x:Key="ResourceName"
      ImageSource="pack://siteoforigin:,,,/Resources/image.png" 
      />
</ResourceDictionary>

Error Message:

 Could not find a part of the path 'C:\\Solution\\TestResults\\Workspace_2012-03-01 14_54_29\\Resources\\image.png'

I've added the Resources directory as a deployment item, and I've confirmed that the image is the TestRun output directory. It seems that the AppDomain is operating one folder above where the location of my test assemblies, because the file is actually located at:

c:\Solution\TestResults\Workspace_2012-03-01 14_54_29\ Out \Resources\image.png

Any suggestions on how I can get the WPF Application to use the Out directory as it's primary folder?

This is because the AppDomain.BaseDirectory that is setup by NUnit doesn't have a trailing '/' character, this causes the code that resolves siteoforigin paths to lose the last directory in the path.

You can check this by looking at the result of the following code when running normally or in NUnit tests.

Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);

This has been recently fixed in NUnit, so upgrading to v2.6 should work.

If you're interested this is the equivalent of what the siteoforigin code is doing:

new Uri(new Uri(baseDirectory), "some/relative/path.jpg").LocalPath

Try that with and without a trailing slash in baseDirectory.

How to create tab-able content in WPF/C#?

5 votes

I have a TabControl in my WPF application. I want my application to basically support multiple "instances" within the single program. For example, think about web browsers, they allow you to have multiple instances of websites in different tabs, I want to achieve similar functionality where my application contains several instances of "sub applications".

The problem I currently face is that I have to copy-paste the same XAML to every tab, because each tab has exactly the same markup and UI, but different data. Another problem is that I need functionality to dynamically create those tabs.

Here's a screenshot of my application at its current state. As you can see, there are 2 tabs on the top and the second has transparent background since it's inactive.

enter image description here

So, how do I create a tab-able system where the UI of the tab remains the same for every tab and I only need to develop with one XAML UI and duplicate that for each tab?

Requirements:

  • Every tab has the same UI.
  • Every tab has different data for the UI elements.
  • As a developer I want to work on the tab's XAML only once and right within Visual Studio.

Ideally I would love a plain simple sample project/code where there is one unstyled tab control and the application upon startup dynamically creates 2-n tabs which all have the same UI, but with different data.

As noted in another answer there are probably lots of ways to do this, but here's my simple way:

Define a DataTemplate that defines the content of each your identical tabs. The controls in the data template will bind to the view model of the currently selected tab. I've put a single TextBlock in my example but you can easily extend this.

using this Xaml:

<Page.DataContext>
    <Samples:TabBindingViewModels />
</Page.DataContext>

<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="ContentTemplate" 
                      DataType="{x:Type Samples:TabBindingViewModel}">
            <TextBlock Text="{Binding Content}"/>
        </DataTemplate>
    </Grid.Resources>
    <TabControl ContentTemplate="{StaticResource ContentTemplate}"  
                DisplayMemberPath="Header" ItemsSource="{Binding Items}" />
</Grid>

and this view model code:

public class TabBindingViewModels
{
    public TabBindingViewModels()
    {
        Items = new ObservableCollection<TabBindingViewModel>
                    {
                        new TabBindingViewModel(1),
                        new TabBindingViewModel(2),
                        new TabBindingViewModel(3),
                    };
    }

    public IEnumerable<TabBindingViewModel> Items { get; private set; }
}

public class TabBindingViewModel
{
    public TabBindingViewModel() : this(0)
    {
    }

    public TabBindingViewModel(int n)
    {
        Header = "I'm the header: " + n.ToString(CultureInfo.InvariantCulture);
        Content = "I'm the content: " + n.ToString(CultureInfo.InvariantCulture);
    }

    public string Header { get; set; }
    public string Content { get; set; }
}

we get:

enter image description here

I quite like this tutorial on styling the tab control. You can easily put more complex content into the tab headers as well as the content.

You should examine the full template of the tab control to gain an insight into how it works. Use Blend or VS11 beta to extract the template.

In order to dynamically add/delete tabs, now all you need to do is add/delete items to the ObservableCollection of view models.

Can give me an example that when should use UIElement.UpdateLayout()?

5 votes

I was reading about this UpdateLayout() method in MSDN.

It says:

Ensures that all visual child elements of this element are properly updated for layout.

But I don't understand what is meant by layout not updated properly.

I have been working with Silverlight/WPF for over a year, but I still haven't used this method once.

So can someone give me an example that will require use of this method? So I can really understand what it does and when I should use it?

You might want to call this if you need a control to immediately complete its layout so that you can do something based on that. For example, you might call UpdateLayout on a child control so that it gets an ActualHeight and ActualWidth, if you want do do something else based on that (eg position it, or draw something with a corresponding size).

WPF/Silverlight VS WinRT

5 votes

I never actually built an application (nor a HelloWorld) in WinRT, and I'm very suspicious.

My question is if there are features in WPF/Silverlight that don't exist in WinRT (excluding features that are implemented differently by design)?

And these aspects are most important to me and are the core of my question, and in result, decision to whether start using WinRT or wait for these to be implemented for it:

  • Entity Framework?
  • WCF RIA?
  • MVVM support (Prism)???
  • Various toolkits (Silverlight/WPF toolkit), that provide additional controls such as DatePicker etc.?

It's not clear to me whether WinRT fully targets .NET or how it works.

Also, is WinRT a client-only (like WPF) application or can be ran on a remote client while sitting on a server (like Silverlight)?

Another one: What about backwards compatibility, if I develop a WinRT app, will it ever be able to work on Win XP?

I anyway can't understand why MVVM is not integrated inline and has seamless IDE support as MVC has. but that's just a side note. I can't use XAML without MVVM, any app that is a bit bigger than hello world is easier to do with MVVM.

Update after answer

As I commented on the answer, I do like the design of WinRT, but the question remains unsolved until I know about the specific technologies mentioned above (EF, WCF-RIA + Validation, MVVM, SDKs and Toolkits). And obviously, I'm not gonna start selling WinRT apps or digging into it until I have the above techs as a least.

WinRT is basically a collection of COM objects that wrap a bunch of Win32 API', exposed as CLI-compliant assemblies.

Microsoft modified their C++ compiler to consume and generate ECMA 335 (i.e. CLI) metadata rather than the more traditional and (largely) C++/COM-only MIDL or lib file formats. Microsoft also modified their "Chakra" Javascript engine to also consume and emit CLI metadata.

This means that when targeting WinRT, Javascript and C++ code, along with .NET languages, of course, can consume CLI-compliant (i.e. .NET) assemblies and can emit CLI-compatible (i.e. .NET) assemblies.

So, one can write WinRT code in C++, any .NET language (i.e. C#, VB.NET, F#, Iron*, etc) and in Javascript.

The WinRT API's will be VERY familiar to you if you've ever written any .NET code. The Windows team actually sought the help & guidance of the .NET Framework design team when designing WinRT, so the same design guidelines that have guided the entire .NET framework team and most of the .NET community for the last 11 years have been applied to the WinRT API's.

WinRT is, quite frankly, beautiful :)

WinRT's primary impact is that it replaces System.IO's file, network, stream IO classes with similar API's but which ONLY support async IO. This means that you will not be able to write apps that block threads while they wait for calls to the filesystem or external systems via the network to return.

This is a GOOD thing.

Luckily, the new async/await features of C# v5 & VB.NET v.next, along with specific support for C++ mean that you don't have to go and fundamentally change how you write code in this new async world - typically you just need to add an "async" keyword to method signatures that call async API's and then use the 'await' keyword prefixing each async API call.

I STRONGLY encourage you to watch Anders Hejlsberg's session which should make this whole thing very clear. While you're there, I also encourage you to watch several of the other //BUILD sessions, especially Harry Pierson's talk on using WinRT with C# & VB.NET and Mads' session on Async Made Simple in C# and VB.

I'd also recommend that you take a look at the improved Win8/WinRT platform architecture diagram that I blogged a few weeks back which should make things a little clearer.

As for .NET itself, as I articulate in my post above, .NET is not "going away". While a few of the .NET API's will be prohibited in WinRT apps (i.e. blocking IO API's), most of the API's you depend upon remain and are fully accessible.

Regarding Silverlight: Silverlight is a browser plug-in. It's a modified-subset of WPF and offers some very powerful and attractive features. So much so, in fact, that the Silverlight XAML engine was moved into the core Windows team and is used for most of the Metro UI rendering in Windows8 - even by the OS itself!

The net result is that most of your Silverlight code will run just fine with barely any modification, other than just changing a few 'using' namespaces.

There are a ton of XAML-focussed sessions from BUILD available to watch here.

With regards backward compatibility, aim to:

  • Isolate code that you want to use in WinRT as well as in .NET desktop apps, Windows Phone, etc. into Portable Assemblies wherever possible.
  • Abstract code that needs to take specific platform dependencies and consider manually loading them or using IoC to compose your modules together.

Frankly, I don't think it's Microsoft's job to write every framework for every scenario. There are several MVVP approaches/frameworks out there in the wild from various people with various pro's and con's. And if you don't find one then create one and stick it up on GITHub and become famous ;)

Above all, though, there's little stopping you from downloading and trying Win8 Consumer Preview & Dev11 Beta. Go get them and try them out - I think you'll find them very refreshing :)

HTH.

Update#1 in answer to the specific support for EF, WCF, etc:

You can find the WinRT API surface area enumerated here in some detail. The core WCF API's are enumerated here.

Note, however, that Microsoft is strongly recommending against using network coomms to communicate between Metro apps and other metro apps or desktop apps/services on the same machine. Read this SO question & Kate Gregory's answer - she links to a video where this scenario is discussed in detail.

If you want to communicate with off-box network services, then you have a wide variety of options including WCF, sockets, etc.

Regarding RIA: Microsoft are currently saying that if you want data, you'll need to get it via a service rather than directly from a DB. There's no ADO.NET for Metro and the recommendation is to surface data via OData, JSON, XML/HTTP, etc. Data as a service is very much a RIA scenario, so I expect RIA to be well supported for Metro apps. Here's a BUILD session on this very subject which may shed more light.

Only you can tell whether or not your specific scenarios are supported in WinRT. I think your best bet would be to download the bits and start exploring.

Binding issues with RadioButton

4 votes

I have a seemingly simple task, that is giving me headaches and would appreciate some help.

What I want to accomplish is binding two boolean values to the IsChecked property of two RadioButtons, sharing the same GroupName (so only one is checked at a time).

The problem I'm facing is that when the Content of a ContentPresenter is about to change (through binding to SelectedItem of a ComboBox), the current content receives a call to a Property-setter with a value of the same property but from the view model that is about to become the new content. (!) The end result is that there is a change of the view model despite no click on the RadioButton bound to the property in question.

I've put together a sample app that shows the problem. To reproduce, run the app and follow these steps:

  1. Select "One" in the combobox => MyPropery is checked, MyProperty2 is not.
  2. Select "Three" in the combobox => MyPropery is checked, MyProperty2 is not.
  3. While still having "Three" selected, click MyProperty2 => MyProperty2 is checked (also indicated in the debug output window)
  4. Select "One" in the combobox => MyPropery is checked, MyProperty2 is not. Notice how the debug window shows how MyProperty2 of object "Three" is set to false here
  5. Select "Three" in the combobox => Neither of the Radiobuttons are now checked (due to #4).

If between #3 and #4, you first select "Two" in the combobox to have the ContentPresenter display another view (as selected through the DataTemplate), the problem does not appear!?

Could someone please explain why the property is set at step #4 when the views are exchanged by the ContentPresenter, and what can be done about it?

DataTemplates are cached, so both One and Three use the exact same UserControl. You can verify this by adding a Loaded event to the control and switching between options.

When you switch to Two and back to Three, WPf will simply re-draw the item from cache, however switching to One and back to Three, it changes the DataContext behind the object. I think this is causing the problem because it seems to be clearing the 2nd RadioButton IsChecked prior to removing the DataContext, so the end result is that Property2 gets set to false. This does not happen if both One and Three have the 2nd radio button selected.

Usually in this kind of situation, I will have the VM contain an ObservableCollection<T> Items and an int SelectedIndex. I'll then draw the UI using a ListBox which has been overwritten to use RadioButtons for the items. This way only one item can be selected at a time, and there is only one property for storing the selected item.

Why is x:key required on ControlTemplate in the ResourceDictionary

4 votes

Consider the following XAML file:

<Window x:Class="ExpressionVisualizer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sle="clr-namespace:System.Linq.Expressions;assembly=System.Core"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate DataType="{x:Type sle:BinaryExpression}"/>
        <ControlTemplate TargetType="{x:Type ContentControl}"/>
    </Window.Resources>
</Window>

This is giving the following compile error:

All objects added to an IDictionary must have a Key attribute or some other type of key associated with them. Line 10 Position 10.

If I add an x:key attribute to the ControlTemplate, it compiles. However, I should not have to do that. The ControlTemplate is decorated with the DictionaryKeyProperty attribute which specifies TargetType as the key property. So as long as I specify a TargetType for my ControlTemplate, I should not have to specify an explicit key (similar to how I don't have to specify one on the DataTemplate I've defined).

I have a second and tangentially related question. If I define a ControlTemplate in this way (either specifying a key or not) in the XAML, does it get automatically applied to all controls of type ContentControl that don't specify another template, or would I have to embed the ControlTemplate inside a Style for that to occur?

From MSDN ControlTemplate:

If you have a standalone ControlTemplate in the resources section with the TargetType property set to a type, the ControlTemplate does not get applied to that type automatically. Instead, you need to specify an x:Key and apply the template explicitly.

Also note that the TargetType property is required on a ControlTemplate if the template
definition contains a ContentPresenter.

So the ControlTemplate is not automatically applied and you have to always specify the x:Key. So the DictionaryKeyProperty doesn't apply.

I did some research:

Although the DictionaryKeyPropertyAttribute MSDN page states:

WPF Usage Notes

The following list references examples of WPF APIs where this attribute is applied:

ControlTemplate.TargetType

DataTemplate.DataTemplateKey

Style.TargetType

But on the Resources Overview page they only mention Styles, DataTemplates, and Implicit Keys which has implicit keys. This also implies that you need to always specify the x:Key for ControlTemplate despite the DictionaryKeyProperty.

By the way it seems there is something wrong with the DictionaryKeyPropertyAttirubte see this connect issue.

Should I put this function in View (code-behind) or in ViewModel?

4 votes

I am creating a simple WPF Application. I've a function OpenFile:

private void OpenFile(string fileName)
{
   if(!File.Exists(Helper.GetPath(fileName)))
   {
      MessageBox.Show("Error opening file");
   }
   else
   {
      //Code to handle file opening
   }
}

Ideally where should this function be present? I feel it should be in .xaml.cs because it accesses a MessageBox which comes in the View part. But it also calls my Helper, which is in the model. So I also think it can be in the ViewModel. What is the advantage of having this in the View or in the ViewModel? Can someone help me with some pointers?

Thanks.

One of the advantages of placing it in the view model would be testability. You could write a unit test that checks that the message box is only displayed if the file exists for example (more accurately it would be an integration test if you are hitting the file system).

However, because you are using a message box directly, your test would never complete on a build server because the machine would be waiting for input from the user whilst the message box is displayed.

Therefore, I would work against an abstraction in your view model, so that you can mock the message box during tests.

Why to Jump to WPF for Business Application instead of using Winforms

4 votes

Our team is experienced working on Winforms and ASP.net projects.

As what other programmers in programmers stack exchange recommend me to jump to WPF for our team next projects instead of using WinForms for our Client based business Applications.

Now i am starting to Develop my first project using WPF, its a little bit tricky for me as its my first attempt to use this.

Can you gave much deeper information why we need to jump to WPF instead of using winforms?

I need to convinced our manager that we can dig on WPF for our client based projects.

We are using VS 2008.

  1. Pick up a good MVVM Framework. I personally use Microsoft Prism. For other alternatives, look at this StackOverflow question.

  2. Routed Events are for the view only. For example, if you want to scroll to the end of a multiline textbox when the text changes.

  3. Commands are used to bind events in which the logic resides on the view-model (business logic)... For example, a submit button.

  4. If you have designers on your team, get them to start playing around with Expression Blend and understanding styles/layout. Expression Blend allows you to use sample data to see your applications layout without having to run it all the time.

  5. Understand The difference between ContentControl and ContentPresenter.

  6. Understand how ItemsControls work. There is a difference between SelectedItem, SelectedValue, and SelectedValuePath.

  7. Look at a lot of exmaples online. Dr. Wpf, WPFTutorial.net, Josh Smith on WPF, etc.

  8. If you plan to take advantage of Code UI Testing (to test the actual User Interface), then make sure to name controls that matter (most MVVM tutorials tell you that you shouldn't have to name any controls). If you don't plan on doing Coded UI Testing, then don't name your controls unless you need to reference them from the view itself.

  9. IValueConverter and IMultiValueConverter should only be used to convert properties to view-related items. The most commonly used converter is the BooleanToVisiblity converter.

  10. TargetNullValue, FallbackValue, and StringFormat are important when using binding. Don't make assumptions that the data being bound will always be available and correct.

  11. You will almost always expose ObservableCollection<T> or ReadOnlyObservableCollection<T> from your view-models. Very rarely will you ever return any other type of collection, including an IEnumerable<T>.

  12. Be careful in choosing your BindingMode: OneWay, OneTime, TwoWay, OneWayToSource (WARNING: OneWayToSource is tricky... it still requires a getter because it is not a write-only binding).

  13. A good debugging tool that is free is Snoop. It is similar to a DOM explorer for a running WPF application. A more advanced (and not free) tool that is a bit more powerful is Mole.

That's all I can think of for now... Oh, and if you run into road blocks, StackOverflow is your friend :)

How to get the ScrollViewer's VerticalOffset in dev independent pixels for an ItemsControl with CanContentScroll true

4 votes

I have a listbox with CanContentScroll true, but others that are false.

And i'm writing a behavior that needs to extract the scrollviewer from it and calculate the vertical scroll offset in device independent pixels.

Since the CanContentScroll can be either true or false I sometimes get logical item units while other times physical pixels.

So I need to calculate the pixel values in case CanContentScroll is true.

For an example: when the listbox is scrolled by three items VerticalOffset will give 3. How to convert this 3 to the vertical pixels used by the items (which can vary in size)?

Thanks

You cannot calculate the values in pixels without effectively setting CanContentScroll="False".

To know the size in pixels you would need to create the containers of all the items and sum up the heights of all the containers. To do that you will need to generate all the containers first. Which would mean that you effectively lost virtualization and effectively set CanContentScroll="False". In that case why use CanContentScroll="True" in the first place?

What Nikolay's code tries to do is take on the burden of doing yourself what CanContentScroll="False" does without giving you the smooth scrolling that you would have otherwise gained.

More importantly what problem does the physical offset solve that you cannot solve with the logical offset if you know that CanContentScroll="true" always?

How to get a combobox to appropriately set focus directly after the popup closes

4 votes

When the user is selecting values from a combobox, if they choose a value, the "SelectionChanged" event fires and the new value is set and everything's fine. If, however, they decide not to change the value and click elsewhere on the UI (like a text box they want to edit), they have to click twice - the first click simply closes the combobox popup, and the next click will focus the element they wanted to activate on the first click.

How can I prevent the combobox popup from hijacking the focus target on the first click like that?

I've tried monitoring the ComboBox_LostFocus event, but this fires at the wrong time. When the user clicks the dropdown and the popup list is displayed, the ComboBox_LostFocus event fires - it's losing focus to it's own dropdown list. I don't want to do anything to change that. When the user then clicks away and the popup closes, the ComboBox never regains focus (focus is just 'lost' to everything) and so this event is useless.

I think I might have found a solution. Comboboxes do have a DropDownClosed event - the problem is it isn't a RoutedEvent, so you can't create a style for ComboBoxes and have them all inherit the event via an EventSetter. (You get the error 'DropDownClosed' must be a RoutedEvent registered with a name that ends with the keyword "Event")

However, the Loaded event is a RoutedEvent, so we can hook into that in the style:

<Style x:Key="ComboBoxCellStyle" TargetType="ComboBox">
    <EventSetter Event="Loaded" Handler="ComboBox_Loaded" />
</Style>

Now that we have an event that will always fire before anything else is done with the ComboBox, we can hook into the event we actually care about:

private void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
    ((ComboBox)sender).DropDownClosed -= ComboBox_OnDropDownClosed;
    ((ComboBox)sender).DropDownClosed += new System.EventHandler(ComboBox_OnDropDownClosed);
}

Now that I finally have access to the event that fires when the DropDown is closing, I can perform whatever actions I need to make sure the focus is terminated on the bothersome ComboBox. In my case, the following:

void ComboBox_OnDropDownClosed(object sender, System.EventArgs e)
{
    FrameworkElement visualElement = (FrameworkElement)sender;

    while( visualElement != null && !(visualElement is DataCell) )
        visualElement = (FrameworkElement)visualElement.TemplatedParent;
    if( visualElement is DataCell )
    {
        DataCell dataCell = (DataCell)visualElement;
        dataCell.EndEdit();
        if( !(dataCell.ParentRow is InsertionRow) ) dataCell.ParentRow.EndEdit();
    }
}

I had a ComboBox as the template of a DataCell in a GridView, and this particular problem was preventing the DataRow from ending edit when the user popped open a ComboBox then clicked outside of the grid.

That was my biggest problem with this bug. A secondary problem setting the focus in this event iff the user clicked. The combobox might also have just been closed because the user hit tab or escape though, so we can't just setfocus to the mouse position. We'd need more information on what caused the DropDownClosed event to fire. Probably means hooking into more unrouted events in the _Loaded event handler.

Tab Item and Tab Control Border Style

4 votes

How do I style the Tab Control Border so that the selected Tab Item does not have a line underneath it?

WPF Tab Item

These are my Tab Control and Tab Item styles so far.

<!-- Tab control styling -->
        <Style TargetType="{x:Type TabControl}">
            <Setter Property="Padding" Value="10,5,10,5" />
            <Setter Property="Margin" Value="3.5" />
            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" />
        </Style>
        <!-- Tab item styling -->
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Grid>
                            <Border 
                                 Name="Border"
                                 Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
                                 BorderBrush="Black" 
                                 BorderThickness="1,1,1,0" 
                                 CornerRadius="3,3,0,0"
                                 MinWidth="120">
                                    <ContentPresenter x:Name="ContentSite"
                                        VerticalAlignment="Center"
                                        HorizontalAlignment="Center"
                                        ContentSource="Header"
                                        Margin="12,2,12,2"/>
                            </Border>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsFocused" Value="True" >
                                <Setter Property="Background" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" />
                                <Setter Property="HeaderTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <TextBlock FontWeight="Bold" Text="{Binding}"/>
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="True" >
                                <Setter Property="Background" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" />
                                <Setter Property="HeaderTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <TextBlock FontWeight="Bold" Text="{Binding}"/>
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="True" >
                                <Setter Property="Background" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" />
                                <Setter Property="HeaderTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <TextBlock FontWeight="Bold" Text="{Binding}"/>
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

If I can achieve the look displayed in the screenshot without having to overload the tab item control template then I don't have an issue as the default tab item template doesn't have the line underneath it on the selected tab. I haven't been able to do this so far. Thanks for your help.

The XAML below is how I have overridden the TabControl to solve this problem. The key piece of info is the Margin property of the HeaderPanel. You will see that the bottom margin is -1, which shifts it down just enough to cover up that line.

    <Setter Property="Template">
        <Setter.Value>

            <ControlTemplate TargetType="{x:Type TabControl}">
                <Grid KeyboardNavigation.TabNavigation="Local">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>

                    <TabPanel x:Name="HeaderPanel"
                              Grid.Row="0"
                              Panel.ZIndex="1"
                              Margin="0,0,4,-1"
                              IsItemsHost="True"
                              KeyboardNavigation.TabIndex="1"
                              Background="Transparent" />

                    <Border x:Name="Border"
                            Grid.Row="1"
                            BorderThickness="1"
                            KeyboardNavigation.TabNavigation="Local"
                            KeyboardNavigation.DirectionalNavigation="Contained"
                            KeyboardNavigation.TabIndex="2">

                        <Border.Background>
                            <SolidColorBrush Color="White"/>
                        </Border.Background>

                        <Border.BorderBrush>
                            <SolidColorBrush Color="White"/>
                        </Border.BorderBrush>

                        <ContentPresenter x:Name="PART_SelectedContentHost"
                                          Margin="4"
                                          ContentSource="SelectedContent" />
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

How to get a task NOT to be executed on the UI thread

4 votes

The following code is a simplification of a code in a real application. The problem below is that a long work will be ran in the UI thread, instead of a background thread.

    void Do()
    {
        Debug.Assert(this.Dispatcher.CheckAccess() == true);
        Task.Factory.StartNew(ShortUIWork, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
    }

    void ShortUIWork()
    {
        Debug.Assert(this.Dispatcher.CheckAccess() == true);
        Task.Factory.StartNew(LongWork, TaskCreationOptions.LongRunning);
    }

    void LongWork()
    {
        Debug.Assert(this.Dispatcher.CheckAccess() == false);
        Thread.Sleep(1000);
    }

So Do() is called normally from UI context. And so is ShortUIWork, as defined by the TaskScheduler. However, LongWork ends up called also in UI thread, which, of course, blocks the UI.

How to ensure that a task is not ran in the UI thread?

LongRunning is merely a hint to the TaskScheduler. In the case of the SynchronizationContextTaskScheduler (as returned by TaskScheduler.FromCurrentSynchronizationContext()), it apparently ignores the hint.

On the one hand this seems counterintuitive. After all, if the task is long running, it's unlikely you want it to run on the UI thread. On the other hand, according to MSDN:

LongRunning - Specifies that a task will be a long-running, coarse-grained operation. It provides a hint to the TaskScheduler that oversubscription may be warranted.

Since the UI thread isn't a thread pool thread, no "oversubscription" (thread pool starvation) can occur, so it somewhat makes sense that the hint will have no effect for the SynchronizationContextTaskScheduler.

Regardless, you can work around the issue by switching back to the default task scheduler:

void ShortUIWork()
{
    Debug.Assert(this.Dispatcher.CheckAccess() == true);
    Task.Factory.StartNew(LongWork, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}

How do I actually get the response of an async web request from outside the method?

4 votes

I'm a little confused. I'm trying to post to my web service in an async manner, ideally I want to start the request, show a loading spinner on the UI and then when the async request finishes process the response and either show an error if there is one, or do another operation with the result.

Here is my code, I call the request here and pass some data in.

private void SignInExecute()
{

        if (Username == null || Password == null)
        {
            LoginOutput = "Please provide a username or password.";
        }
        else
        {
            this.webService.SendLoginRequest("http://localhost:3000/client_sessions", "username=" + Username + "&password=" + Password);

        }

}

And here is the actual web request code:

public void SendLoginRequest(string url, string postdata)
{
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

        request.Method = "POST";

        request.ContentType = "application/x-www-form-urlencoded";

        request.Accept = "application/json";

        byte[] byteArray = Encoding.UTF8.GetBytes(postdata);

        request.CookieContainer = new CookieContainer();

        request.ContentLength = byteArray.Length;

        Stream dataStream = request.GetRequestStream();

        dataStream.Write(byteArray, 0, byteArray.Length);

        dataStream.Close();

        ((HttpWebRequest)request).KeepAlive = false;

        request.BeginGetResponse(new AsyncCallback(GetLoginResponseCallback), request);


    }

    private static void GetLoginResponseCallback(IAsyncResult asynchronousResult)
    {
        HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;

        // End the operation
        HttpWebResponse response =  (HttpWebResponse)request.EndGetResponse(asynchronousResult);
        Stream streamResponse = response.GetResponseStream();
        StreamReader streamRead = new StreamReader(streamResponse);
        string responseString = streamRead.ReadToEnd();

        Console.WriteLine(responseString);

        // Close the stream object
        streamResponse.Close();
        streamRead.Close();
        response.Close();
    }

So to sum up. I want to be able to return the response back to the object which originally gave the call for the web request to start. Any help?

You need to tell the BeginGetResponse to go back to the same context in which it was called via SynchronizationContext.Current. Something like this (the code does not have proper error checking, so you should think about that properly) (Also, Platinum Azure is correct that you should use a using to let your streams close properly (and guaranteed):

In your SendLoginRequest:

//Box your object state with the current thread context
object[] boxedItems = new []{request, SynchronizationContext.Current};
request.BeginGetResponse(new AsyncCallback(GetLoginResponseCallback), 
    boxedItems);

The getresponse code:

private static void GetLoginResponseCallback(IAsyncResult asynchronousResult)
{
//MY UPDATE 
    //Unbox your object state with the current thread context
    object[] boxedItems = asynchronousResult.AsyncState as object[];
    HttpWebRequest request = boxedItems[0] as HttpWebRequest;
    SynchronizationContext context = boxedItems[1] as SynchronizationContext;

    // End the operation
    using(HttpWebResponse response =  
        (HttpWebResponse)request.EndGetResponse(asynchronousResult))
    {
        using(Stream streamResponse = response.GetResponseStream())
        {
            using(StreamReader streamRead = new StreamReader(streamResponse))
            {
                string responseString = streamRead.ReadToEnd();

                Console.WriteLine(responseString);
//MY UPDATE
                //Make an asynchronous call back onto the main UI thread 
                //(context.Send for a synchronous call)
                //Pass responseString as your method parameter 
                //If you have more than one object, you will have to box again
                context.Post(UIMethodToCall, responseString);
            }
        }
    }
}

To implement your UI processing

public static void UIMethodCall(object ObjectState)
{
    String response = ObjectState as String;
    label1.Text = String.Format("Output: {0}", response);
    //Or whatever you need to do in the UI...
}

Now, I would test this out first, though. My understanding of Microsoft's implementation of event driven async was that the response was context-aware, and knew which context to return to. So, before jumping to the assumption that you are not on the same context, test it out by trying to update the UI (this will cause a thread context exception if you are not on the calling (UI) thread)

What is the difference between Dispatcher.BeginInvoke and Task.Factory.StartNew

4 votes

In my WPF application I am loading content using Dispatcher.BeginInvoke in the constructor. My question is will it block the UI thread?

Or is it better to use Task.Factory.StartNew and then dispatching things back on UI so that application will load first irrespective of the loading content process time?

Which is better approach and why?

They do two very different things:

  • Task.Factory.StartNew schedules a delegate for execution on a thread pool thread. The current thread continues to run without waiting for a result of this task (async). Typically you would spawn a longer running background task so that the UI is not blocked for too long (not "frozen").

  • Dispatcher.BeginInvoke schedules a delegate for execution on the dispatcher (UI) thread. Typically this is done to update some UI controls with the results of some operation that was executed on a background thread. Essentially you are updating the UI here.

To answer you questions directly:

You should not schedule lengthy operations on the Dispatcher thread, typically you only want to update UI controls here. The code in the delegate will be executed on the UI thread, which is blocked for the time of the execution. Just put a Thread.Sleep(10000) in your current code (that you schedule from the constructor) and you will see the UI will freeze. Use a background task for this - either with a Task or a background worker (both will use a thread pool thread).

Or is it better to use Task.Factory.StartNew and then dispatching things back on UI so that application will load first irrespective of the loading content process time.

Yes!