Best wpf questions in November 2011

How to avoid mouse move on Touch

13 votes

I have a WPF application that is capable of being used both with a mouse and using Touch. I disable all windows "enhancements" to just have touch events :

Stylus.IsPressAndHoldEnabled="False"
Stylus.IsTapFeedbackEnabled="False"
Stylus.IsTouchFeedbackEnabled="False"
Stylus.IsFlicksEnabled="False"

The result is that a click behave like I want except on two points :

  • The small "touch" cursor (little white star) appears where clicked an when dragging.
    Completely useless as the user finger is already at this location no feedback is required (Except my element potentially changing color if actionable).
  • Elements stay in the "Hover" state after the movement / Click ends.

Both are the consequences of the fact that while windows transmit correctly touch events, he still move the mouse to the last main-touch-event.

I don't want windows to move the mouse at all when I use touch inside my application. Is there a way to completely avoid that?

Notes:

  • Handling touch events change nothing to this.
  • Using SetCursorPos to move the mouse away make the cursor blink and isn't really user-friendly.
  • Disabling the touch panel to act as an input device completely disable all events (And I also prefer an application-local solution, not system wide).
  • I don't care if the solution involve COM/PInvoke or is provided in C/C++ i'll translate.
  • If it is necessary to patch/hook some windows dlls so be it, the software will run on a dedicated device anyway.
  • I'm investigating the surface SDK but I doubt that it'll show any solution. As a surface is a pure-touch device there is no risk of bad interaction with the mouse.

Here is the best solution I found from now. Don't hesitate to post your own, especially if it is better.

Using SetWindowsHookEx low level mouse event catching (WH_MOUSE_LL) and the fact that all events converted from Touch to Mouse are marked as such (The MOUSEEVENTF_FROMTOUCH flag is set in the event's ExtraInfo, see Microsoft's FAQ) I was able to Globally remove all mouse events comming from the touch panel.

It isn't an ideal solution but it'll do for now in my application when it is running fullscreen (99% of the time as it is a dedicated hardware device).

The second step also good only in fullscreen (That i won't provide code for as it is pretty simple) is just moving the mouse to "safe" position like the bottom right of the screen with SetCursorPos.

If you need the code it is in a Gist on Github and i'll post the current version at the end of this article. To use it :

// As long as the instance is alive the conversion won't occur
var disableTouchMouse = new DisableTouchConversionToMouse();

// To let the conversion happen again, Dispose the class.
disableTouchMouse.Dispose();

Full source code of the class :

namespace BlackFox
{
    using System;
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Security;

    /// <summary>
    /// As long as this object exists all mouse events created from a touch event for legacy support will be disabled.
    /// </summary>
    class DisableTouchConversionToMouse : IDisposable
    {
        static readonly LowLevelMouseProc hookCallback = HookCallback;
        static IntPtr hookId = IntPtr.Zero;

        public DisableTouchConversionToMouse()
        {
            hookId = SetHook(hookCallback);
        }

        static IntPtr SetHook(LowLevelMouseProc proc)
        {
            var moduleHandle = UnsafeNativeMethods.GetModuleHandle(null);

            var setHookResult = UnsafeNativeMethods.SetWindowsHookEx(WH_MOUSE_LL, proc, moduleHandle, 0);
            if (setHookResult == IntPtr.Zero)
            {
                throw new Win32Exception();
            }
            return setHookResult;
        }

        delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

        static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                var info = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));

                var extraInfo = (uint)info.dwExtraInfo.ToInt32();
                if ((extraInfo & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)
                {
                    return new IntPtr(1);
                }
            }

            return UnsafeNativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam);
        }

        bool disposed;

        public void Dispose()
        {
            if (disposed) return;

            UnsafeNativeMethods.UnhookWindowsHookEx(hookId);
            disposed = true;
            GC.SuppressFinalize(this);
        }

        ~DisableTouchConversionToMouse()
        {
            Dispose();
        }

        #region Interop

        // ReSharper disable InconsistentNaming
        // ReSharper disable MemberCanBePrivate.Local
        // ReSharper disable FieldCanBeMadeReadOnly.Local

        const uint MOUSEEVENTF_FROMTOUCH = 0xFF515700;
        const int WH_MOUSE_LL = 14;

        [StructLayout(LayoutKind.Sequential)]
        struct POINT
        {

            public int x;
            public int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public uint mouseData;
            public uint flags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [SuppressUnmanagedCodeSecurity]
        static class UnsafeNativeMethods
        {
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod,
                uint dwThreadId);

            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool UnhookWindowsHookEx(IntPtr hhk);

            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
                IntPtr wParam, IntPtr lParam);

            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern IntPtr GetModuleHandle(string lpModuleName);
        }

        // ReSharper restore InconsistentNaming
        // ReSharper restore FieldCanBeMadeReadOnly.Local
        // ReSharper restore MemberCanBePrivate.Local

        #endregion
    }
}

How System.Timers.Timer behave in WPF application, after Hibernate, and Sleep?

13 votes

I'm using System.Timers.Timer in my WPF application. I want to understand how Timer does behave, after Computer is hibernated, and sleep. I'm getting some weird issues with my application, after computer is getting resumed from hibernate.

How should I handle timers, and how do they behave when computer is in hibernate/sleep mode?

I have a midnight timer which should work each midnight to reset the default values on UI.

Here is the code that creates the timer:

private void ResetMidnightTimer() 
        { 
            // kill the old timer
            DisposeMidnightTimer();

            _midnightTimer = new Timer();
            // scheduling the timer to elapse 1 minute after midnight
            _midnightTimer.Interval = (DateTime.Today.AddDays(1).AddMinutes(1) - DateTime.Now).TotalMilliseconds;
            _midnightTimer.Elapsed += (_, __) => UpdateRecommendedCollectingTime();
            _midnightTimer.Enabled = true;
            _midnightTimer.Start();
        }

On UI page's contructor, I call the method which calls ResestMidnightTimer() and creates the timer de facto. After that the timer just waits for the night.

When the night time (actually it is the 12:01 AM) comes, the timer works, resets the default values as expected and then disposes existing timer. Finally it creates a new midnight timer for next day. But if I try to hibernate the computer during that day, the midnight timer won't work and won't reset the default values.

Is that because while hibernating it just postpones the event handling by the same amount of time it was hibernated?

This depends on how you are using your timers. If you are using them to initiate some event that occurs infrequently (greater than a couple minutes) then you will probably see some 'weird' behavior. Since you don't specify what that 'weird' behavior is, I'm going to assume that your program's timer goes off later than it should.

Explanation: The problem with going to sleep/hibernating is that all programs are suspended. This means that your Timers are not being updated and thus when you sleep/hibernate and come back, it is as if you were frozen for that period of time that you were sleeping/hibernating. This means if you have a timer set to go off in an hour and your computer goes to sleep at the 15 minute mark, once it wakes up it will have another 45 minutes to go, regardless of how long the computer was sleeping.

Solution: One fix would be to keep a DateTime around of the last time the event occurred. Then, have a timer go off periodically (every 10 seconds or 10 minutes, depending on the precision desired) and check the DateTime of the last execution. If the difference between now and the last execution time is greater than or equal to the interval desired, THEN you run execution.

This will fix it so that if an event 'should have' occurred during sleeping/hibernating, it will start the moment you return from sleeping/hibernating.

Update: The solution presented above will work and I'll fill in a couple of details to help you implement it.

  • Instead of creating/disposing of new Timers, create ONE timer to use that is RECURRING (the AutoReset property is set to true)

  • The interval of the single timer should NOT be set according to the next time the event should occur. Instead, it should be set to a value you choose that will represent the polling frequency (how often it checks to see if the 'event' should run). The choice should be a balance of efficiency and precision. If you NEED it to run REALLY close to 12:01 AM then you set the interval to around 5-10 seconds. If it is less important that it be at exactly 12:01 AM, you can increase the interval to something like 1-10 minutes.

  • You need to keep around a DateTime of when the last execution occurred OR when the next execution should happen. I would prefer 'when the next execution should happen' so that you aren't doing (LastExecutionTime + EventInterval) each time the timer elapses, you'll just be comparing the current time and the time the event should occur.

  • Once the timer elapses and the event SHOULD occur (somewhere around 12:01 AM), you should update the stored DateTime and then run the code you want run at 12:01 AM.

Sleep vs. Hibernate Clarification: The main difference between sleep and hibernate is that in sleep, everything is kept in RAM whereas hibernate saves the current state to disk. The main advantage of hibernate is that the RAM no longer needs power and thus expends less energy. This is why it is recommended to use hibernate over sleep when dealing with laptops or other devices using a finite amount of energy.

That said, there is no difference in the execution of programs as they are being suspended in either case. Unfortunately, the System.Timers.Timer does not 'wake up' a computer and so you can't enforce your code to be run at ~12:01 AM.

I believe there are OTHER ways to 'wake up' a computer but unless you go that route the best you can do is run your 'event' during the next 'polling event' of your timer after it comes out of sleep/hibernate.

using keyword takes less space?

12 votes

Is it true that if i use the following, it will take less resources and the cleanup will be faster?

 using (TextReader readLogs = File.OpenText("C:\\FlashAuto\\Temp\\log.txt"))
 {
      //my stuff
 }

as compared to:

 TextReader readLogs = new StreamReader("C:\\FlashAuto\\Temp\\log.txt");
 //my stuff
readLogs.Close();
readLogs.Dispose();

The difference between those examples isn't performance, but exception safety. using creates a try...finally block in the background.

A using statement of the form:

using (ResourceType resource = expression) embedded-statement 

corresponds to the expansion:

{ 
   ResourceType resource = expression; 
   try {     
     embedded-statement 
   } 
   finally { 
     // Dispose of resource 
   } 
}

For reference type the disposing happens via:

finally {  
  if (resource != null) ((System.IDisposable)resource).Dispose(); 
}

From ECMA-344 C# Language Specification 4th Edition


You also don't need to call both Close and Dispose. Those functions are equivalent.

Wait task for x amount of time and report progress

8 votes

I need a better design for sleeping Task than Thread.Sleep, I'm using the Task class.

In my wpf app i run a Task, this task runs another couple of tasks, each of this tasks first login to and Internet website, after they login they need to wait couple of seconds and inform the user when they will proceed further and this is my problem, because with Thread.Sleep i can't report the progress.

There are more functions than login, it's about 5-6, all of them request an Internet resource, and between them there need to be a sleep time with remaining time report send do gui, this 5-6 function are all in one Task, but there could be many tasks.

What i need is to make the task wait, but also allow it to send updates on the remaining time to proceed to the GUI.

Do you have any ideas for this problem, how to make it better, maybe you have some design patterns already for such problem?

I have heard also that using Thread.Sleep is a poor design practice.

EDIT: No one knows ? Whats with some kind of self contained timer with thread wait like waithandle, autoresetevent, anybody?

Forget using Thread.Sleep. Instead, run your task in a background thread and use a WaitHandle with an AutoResetEvent. (Links: WaitHandle/WaitOne / AutoReset)

Your background thread can send updates to UI with async delegates, but the calling thread will wait it until either thing happens:

1) Your thread reports it has completed its task by using yourwaithandle.Set();

or

2) the waiting thread timeouts (timeout value is set as parameter to WaitOne() -method).

XAML Button not garbage collected after eliminating references

8 votes

I wrote a test program wherein a single Button is defined in XAML as the content of a Window. Upon the window's loading, the Button is programmatically replaced as the window's content, and the field referring to it is also replaced, both by another Button which I created programmatically. I thereafter track both Button objects using weak references, and poll at 1/10th second intervals the IsAlive property of each. Before the first check of IsAlive in the first call to the polling method, I wipe out rooting references to the programmatically-defined Button as well.

The expectation in running this code would be that, despite nondeterminism in the timing of C# garbage collection, both Button objects would eventually be reported as garbage collected. Although the programmatically-defined Button shows this behavior, typically within a 1/2 minute, the XAML Button is never collected. I've left the program running for more than ten minutes seeing this behavior.

Can anyone tell me why the XAML Button object isn't collected? In particular, I'd like to know where the garbage collection-blocking reference is, whether it is in my code or it is in the WPF implementation. Perhaps it's in a XAML loading object. Am I looking at some sort of memory leak?

The program described above is included below for reference.

MainWindow.xaml :

<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="300" Height="150" Loaded="Window_Loaded">
    <Button Name="btn" />
</Window>

MainWindow.xaml.cs :

namespace Test {
    public partial class MainWindow : System.Windows.Window {

        private System.WeakReference wr_xamlBtn, wr_programmaticBtn;

        public MainWindow() {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, System.Windows.RoutedEventArgs e) {

            // Immediately upon the window's loading, create a weak reference to the
            //  button %btn defined in XAML.
            wr_xamlBtn = new System.WeakReference(btn);

            // Replace references in %btn and this.Content to the XAML button with
            //  references to a programmatically-defined button. This would be
            //  expected to free the XAML button for garbage collection.
            btn = new System.Windows.Controls.Button();
            Content = btn;

            // Create a weak reference to the programmatically-defined button, so that
            //  when (strong) references to it are removed, it will be eligible for
            //  garbage collection.
            wr_programmaticBtn = new System.WeakReference(btn);

            // Provides a polling mechanism to see whether either the XAML button or
            //  the programmatically-defined button has been collected.
            var dt = new System.Windows.Threading.DispatcherTimer();
            dt.Tick += Poll;
            dt.Interval = System.TimeSpan.FromMilliseconds(100);
            dt.Start();
        }

        void Poll(object sender, System.EventArgs e) {

            // If the programmatically-defined button hasn't had its references
            //  removed yet, this does so. This makes it eligible for garbage
            //  collection.
            if (btn != null)
                Content = btn = null;

            // Uses the console to show a timestamp and the state of collection of the
            //  XAML button and the programmatically-defined button.
            System.Console.WriteLine(
                string.Format(
                    "XAML button {0}, Programmatically-defined button {1} @ {2}",
                    wr_xamlBtn.IsAlive ? "Alive" : "Collected",
                    wr_programmaticBtn.IsAlive ? "Alive" : "Collected",
                    System.DateTimeOffset.Now));
        }
    }
}

App.xaml :

<Application x:Class="Test.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml" />

The button is not collected because it was strongly referenced within the Window namescope:

MemProfiler snapshot

But it shouldn't be recognized as memory leak, because you should reregister your new button within the scope:

//...
INameScope scope = NameScope.GetNameScope(this);
scope.UnregisterName("btn");
btn = new System.Windows.Controls.Button();
Content = btn;
scope.RegisterName("btn", btn);
//...

Grid inside a StackPanel: why do auto and * behave strangely?

8 votes

My google and stackoverflow search-fu have failed me, so I present to the community this question.

(This is all generated using VS2010 and .NET 4.0, in a blank default WPF Solution)

Consider the following XAML:

<StackPanel Orientation="Horizontal">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Border Name="aborder" Grid.Column="0" Grid.ColumnSpan="2" 
                    Background="Red" Width="200"/>
        <Border Name="aborder2" Background="Green"/>

    </Grid>
</StackPanel>

What would you predict the width of "aborder2" to be?

If you guessed "20 pixels", you would be wrong. The correct answer is 110 pixels.

Consider this XAML:

    <StackPanel Orientation="Horizontal">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <Border Name="aborder" Grid.Column="0" Grid.ColumnSpan="2" 
                    Background="Red" Width="200"/>
        <Border Name="aborder2" Background="Green"/>

    </Grid>
</StackPanel>

What would you predict the width of "aborder2" to be?

If you guessed either 20 pixels or 110 pixels, you would be wrong. The correct answer is 200 pixels.

I cannot figure this out and it's driving me insane. It seems like the answer should be obvious; clearly there's some interaction between an auto-filling grid column and the stackpanel that causes the grid to freak out. But it just doesn't seem to make sense - whatever rules are governing this behavior seem to be arbitrary. Why 110 pixels? Why not 109 pixels or 100 pixels? I would understand if the auto-sized column failed to expand fully or something, but to have the fixed-width column randomly ignore its width has left me a burnt out shell of a developer.

Any help or guiding lights would be much appreciated!

I have no idea why the first example isn't rendering correctly

The 2nd is because Auto means "the same size as the contents", but you have nothing in Column2 so Column2 is getting rendered at 0px. You have something in Column1 which spans 2 cells, but since Column2 is rendered at 0 px it means Column1 is stretched to 200 px. By default, Grid's expand their children to fill all available space in the Cell, so this is making aborder2 stretch to 200px instead of 20.

I think the first example might be a similar situation, where Column2 is rendering at 0px because it has no content, however I am not sure why it is setting aborder2 to a width of 110. The 110 seems to come from (GridWidth / TotalColumns) + (1stColumnWidth / TotalColumns * NumberOfStarColumns), so I think it's a bug.

As a side note, you can set a Column1's MaxWidth="20" to force Column1 to always render as 20px

Moving To Next Control On Enter Key Press In WPF

8 votes

I want to move to the next control when i press the enter key instead of tab key in wpf mvvm concept.. How can i achieve these..

Below is an attached property that I've used for just this.

First, example usage:

<TextBox Width="100"
         Text="{Binding Name, Mode=TwoWay}"
         UI:FocusAdvancement.AdvancesByEnterKey="True" />

(UI is the namespace alias for where I've defined the following.)

The attached property:

public static class FocusAdvancement
{
    public static bool GetAdvancesByEnterKey(DependencyObject obj)
    {
        return (bool)obj.GetValue(AdvancesByEnterKeyProperty);
    }

    public static void SetAdvancesByEnterKey(DependencyObject obj, bool value)
    {
        obj.SetValue(AdvancesByEnterKeyProperty, value);
    }

    public static readonly DependencyProperty AdvancesByEnterKeyProperty =
        DependencyProperty.RegisterAttached("AdvancesByEnterKey", typeof(bool), typeof(FocusAdvancement), 
        new UIPropertyMetadata(OnAdvancesByEnterKeyPropertyChanged));

    static void OnAdvancesByEnterKeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var element = d as UIElement;
        if(element == null) return;

        if ((bool)e.NewValue) element.KeyDown += Keydown;
        else element.KeyDown -= Keydown;
    }

    static void Keydown(object sender, KeyEventArgs e)
    {
        if(!e.Key.Equals(Key.Enter)) return;

        var element = sender as UIElement;
        if(element != null) element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    }
}

You also said "instead of tab," so I'm wondering if you want to suppress the ability to use tab in the usual way. I'd advise against it, as it is a common, well known paradigm, but if that is the case, you can add a PreviewKeyDown handler in the attached property, check for the tab key, and set Handled = true for the event args.

Is there a way to use an Australian English dictionary in WPF

7 votes

So In WPF I can declare a Rich Text Box like so

<RichTextBox Text="{Binding Text}" SpellCheck.IsEnabled="True" />

and through some miracle little wibbly lines appear under misspelt words.

But the dialect used is an American that has all kinds of differences that are unacceptable for an Australian audience.

I know I can do this...

<RichTextBox Text="{Binding Text}" SpellCheck.IsEnabled="True" >
  <SpellCheck.CustomDictionaries>
    <!-- customwords.lex is included as a content file-->
    <sys:Uri>pack://application:,,,/customwords.lex</sys:Uri>
  </SpellCheck.CustomDictionaries>
</RichTextBox>

and fill customwords.lex with the words that are different like so.

#LID 1033
colour
summarising
Summarise
Organisation
maximise
etc...

Frankly it is a little onerous for me to go out and fill the custom dictionary with all the extra different words and it still won't highlight the Americanisms which wrong in an Australian context.

I looked around for .Net Language packs and if I wanted just about any other language than a dialect of English I think I'd be alright but there is no English (Australian or UK) that I can use.

Do I just turn off spell checking? or is there a way to get the right Dictionary in there.

I found the solution and created a style that achieves what I want. Now all RichTextBoxes are spell checked appropriately.

<Style TargetType="RichTextBox">
    <Setter Property="SpellCheck.IsEnabled"  Value="True" />
    <Setter Property="Language"  Value="en-au" />
</Style>

Problems with Arrange/Measure - Is Layout broken in WPF?

6 votes

I am trying to make what I thought would be a simple Panel in WPF, which has the following properties:

  • If the combined heights of the children are less than the available height, then all children are displayed at their desired height.

  • If the combined heights of the children are greater than the available height, all children are reduced by the same percentage height in order to fit.

My panel looks like this:

public class MyStackPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        Size requiredSize = new Size();

        foreach (UIElement e in InternalChildren)
        {
            e.Measure(availableSize);
            requiredSize.Height += e.DesiredSize.Height;
            requiredSize.Width = Math.Max(requiredSize.Width, e.DesiredSize.Width);
        }

        return new Size(
            Math.Min(availableSize.Width, requiredSize.Width),
            Math.Min(availableSize.Height, requiredSize.Height));
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        double requiredHeight = 0;

        foreach (UIElement e in InternalChildren)
        {
            requiredHeight += e.DesiredSize.Height;
        }

        double scale = 1;

        if (requiredHeight > finalSize.Height)
        {
            scale = finalSize.Height / requiredHeight;
        }

        double y = 0;

        foreach (UIElement e in InternalChildren)
        {
            double height = e.DesiredSize.Height * scale;
            e.Arrange(new Rect(0, y, finalSize.Width, height));
            y += height;
        }

        return finalSize;
    }
}

My test XAML looks like this:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="300" Width="300">
    <Window.Resources>
        <x:Array x:Key="Items" Type="{x:Type sys:String}">
            <sys:String>Item1</sys:String>
            <sys:String>Item2</sys:String>
            <sys:String>Item3</sys:String>
            <sys:String>Item4</sys:String>
        </x:Array>
    </Window.Resources>
    <local:MyStackPanel>
        <ListBox ItemsSource="{StaticResource Items}"/>
        <ListBox ItemsSource="{StaticResource Items}"/>
        <ListBox ItemsSource="{StaticResource Items}"/>
        <ListBox ItemsSource="{StaticResource Items}"/>
        <ListBox ItemsSource="{StaticResource Items}"/>
    </local:MyStackPanel>
</Window>

But the output looks like this:

Layout Problem

As you can see, the items are clipping - the list boxes should be displaying scroll bars. The child items are not respecting the size given to them in the arrange pass.

From my investigations it seems that you cannot give a smaller size to a control in the arrange pass than you gave in the measure pass.

However, I cannot do this because I need the results of measure pass to know what size to give to the children in the arrange pass.

It seems like a chicken and egg situation. Is layout in WPF broken? Surely the measure pass should be just that, a measure pass?

The problem in your case is that you pass all the available space to each child to its Measure call (e.Measure(availableSize)). But you need to pass only the portion of the space that you actually going to give them. Like this:

protected override Size MeasureOverride(Size availableSize)
{
    Size requiredSize = new Size();

    var itemAvailableSize = new Size(availableSize.Width, availableSize.Height / InternalChildren.Count);

    foreach (UIElement e in InternalChildren)
    {
        e.Measure(itemAvailableSize);
        requiredSize.Height += e.DesiredSize.Height;
        requiredSize.Width = Math.Max(requiredSize.Width, e.DesiredSize.Width);
    }

    return new Size(
        Math.Min(availableSize.Width, requiredSize.Width),
        Math.Min(availableSize.Height, requiredSize.Height));
}

Update:

In case when the size that you are planning to give each individual item is not easily calculated based on availableSize and depends on other items desired size, you can do the first round of measuring on all items passing double.PositiveInfinity as Height. After that you will know how big each items wants to be and you can calculate how much space you are actually going to give to each item. Then you need to call Measure with the calculated space once again.

Here is an example:

protected override Size MeasureOverride(Size availableSize)
{
    var requiredSize = new Size();

    double allItemsHeight = 0;

    foreach (UIElement e in InternalChildren)
    {
        e.Measure(new Size(availableSize.Width, double.PositiveInfinity));
        allItemsHeight += e.DesiredSize.Height;
    }

    double scale = 1;

    if (allItemsHeight > availableSize.Height)
    {
        scale = availableSize.Height / allItemsHeight;
    }

    foreach (UIElement e in InternalChildren)
    {
        double height = e.DesiredSize.Height * scale;

        e.Measure(new Size(availableSize.Width, height));

        requiredSize.Height += e.DesiredSize.Height;
        requiredSize.Width = Math.Max(requiredSize.Width, e.DesiredSize.Width);
    }

    return new Size(
        Math.Min(availableSize.Width, requiredSize.Width),
        Math.Min(availableSize.Height, requiredSize.Height));
}

Designing a GUI application: one VS multpile screens

6 votes

we are creating an application with the following GUI outline: enter image description here

The "stuff to show for step i" changes dramatically. Would it be better to design i separate screens, each with its own controls, or put it all on a single screen and toggle the visability of the components?

I am looking for maintainability (I will probably need to hand the screen to a designer to improve my (bad) graphic designer).

In my opinion it is better to have separate screen if only for maintainability. Separate screens will allow each step to evolve independently form the other with minimal dependencies as well as different people to work concurrently on the design and development of the different screens

WCF dataservice security in a WPF application

5 votes

I'm working on a solution where I have a WPF project that is using a WCF DataService which is located in another ASP .NET project to access the data.
I need to provide a level of security which ensures that only authenticated users can access the service. Having surfed the net I've broken my head trying to accomplish that. What is the proper way to implement that?

I did this in the past where the WCF's Login method would create a user object, assign the user object a Token (in my case, it was a GUID), and store it internally on the WCF server in an AuthenticatedUsers list.

Any other WCF call required the token as a parameter. It would check if a user existed in the AuthenticatedUsers list with that token, and would return an error if the no User with that token existed. An added benefit is I would always know who made the WCF call without needing them to pass in a User Id.

I also stored a LastActivity DateTime with the User objects on the server. Each WCF call would refresh this value, and providing the AuthenticatedUsers list on the WCF server had at least one value, a Timer ran on the server which would check the AuthenticatedUsers LastActivity value and delete the user if they had been inactive for over 20 minutes.

Wiring up the MVVM View and ViewModel using Declarative DataContext for Design-Time and Data Template for Runtime?

5 votes

Is it possible to wire up the View and ViewModel using both a Declarative DataContext and a Data Template?

Goal: I want to wire Views with a one ViewModel for design-time and another at run-time. Currently, using a Declarative DataContext for a design-time VM and a Data-Template-specified VM for runtime doesn't behave as expected.

Background - There are a variety of ways to wire up a View and ViewModel including the following:

A.) Declaratively specify the ViewModel DataContext within the View’s XAML. This technique is useful at Design-Time using the parameter-less constructor to pass in dummy data.

<UserControl.DataContext>
    <my: BrowseAssetsViewModel />
</UserControl.DataContext>

B.) Programmatically specify the ViewModel, View and DataContext.

// …Setup code
BrowseAssetsViewModel viewModel = new BrowseAssetsViewModel(assetRegistry, domains);
BrowseAssetsView view = new BrowseAssetsView();
view.DataContext = viewModel;

When Approach B is used in combination with Approach A, at run-time WPF overrides the default DataContext specified in Approach A using the version of the ViewModel with the parameterized constructor specified in Approach B.

C.) Define a Data Template for the View-ViewModel association By associating a View and ViewModel in App.XAML Application.Resources, WPF can wire up the correct View based on a ViewModel’s type.

<DataTemplate DataType="{x:Type vm: BrowseAssetsViewModel }">
    <vw: BrowseAssetsView />
</DataTemplate>

If a ViewModel property were bound to a ContentPresenter control, WPF would wire-up the corresponding View (based on the ViewModel’s type) and place it within the ContentPresenter. This is useful in the “ViewModel-first” scenario where the ViewModel is presented and WPF resolves and wires the correct View by inspecting the presented ViewModel’s type.

Problem - When using this Approach C in combination with Approach A, WPF resolves the correct View but it seems to then re-query the View, calling the declaratively specified ViewModel via the parameter-less constructor (Approach A), thus overriding the existing ViewModel property!

Question - Is there a way to use these techniques (C and A) together without A inadvertently overwriting the C ViewModel property?

You can specify that the DataContext is in case A set only only at design time, like so:

<UserControl ...
    d:DataContext="{d:DesignInstance my:BrowseAssetsViewModel}"
>

For details, see Using a DesignInstance... on MSDN.

ComboBox ItemTemplate only working in dropdown

5 votes

I am trying to show a ComboBox whose ItemsSource is a collection of Controls (it is part of a PropertyGrid, the ComboBox should display the names of the controls, and the user should be able to select one of the controls). Here is an extremely simplified reproduction of the problem:

<ComboBox ItemsSource="{Binding GroupBoxes}" SelectedValue="{Binding SelectedGroupBox}">
  <ComboBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Name}"/>
    </DataTemplate>
  </ComboBox.ItemTemplate>          
</ComboBox>

GroupBoxes and SelectedGroupBox are DependencyProperties of type ObservableCollection and GroupBox.

The Bindings work - the control names are displayed in the ComboBox-DropDown, and if I select a different item I can see that the SelectedGroupBox property is updated correctly. The problem: the selected item is never displayed in the ComboBox. Setting the SelectedGroupBox property from code also works as expected - the ComboBox raises SelectionChanged and its SelectedValue is correct, but it still doesn't display the current value.

If I do the exact same thing with any other type of class, everything works as expected.

Searching for an answer I came across many posts from people having similar sounding problems, but almost all of them were Binding proplems which is not the case here.

Edit:

To simplify trying it out, here's the code behind. Just drop the above XAML in a new Window, and the code below in the code behind.

public MainWindow() {
    InitializeComponent();
    this.DataContext = this;
    this.GroupBoxes = new ObservableCollection<GroupBox>();
    this.GroupBoxes.Add(new GroupBox() { Name = "AAA", Header = "AAA", Height = 100, Background = Brushes.Purple });
    this.GroupBoxes.Add(new GroupBox() { Name = "BBB", Header = "BBB", Height = 100, Background = Brushes.Purple });
    this.GroupBoxes.Add(new GroupBox() { Name = "CCC", Header = "CCC", Height = 100, Background = Brushes.Purple });
    this.GroupBoxes.Add(new GroupBox() { Name = "DDD", Header = "DDD", Height = 100, Background = Brushes.Purple });
    this.GroupBoxes.Add(new GroupBox() { Name = "EEE", Header = "EEE", Height = 100, Background = Brushes.Purple });
}

#region GroupBoxesProperty

public static readonly DependencyProperty GroupBoxesProperty = DependencyProperty.Register(
    "GroupBoxes", typeof(ObservableCollection<GroupBox>), typeof(MainWindow)
);

public ObservableCollection<GroupBox> GroupBoxes {
    get { return (ObservableCollection<GroupBox>)GetValue(GroupBoxesProperty); }
    set { SetValue(GroupBoxesProperty, value); }
}

#endregion

#region SelectedGroupBoxProperty

public static readonly DependencyProperty SelectedGroupBoxProperty = DependencyProperty.Register(
    "SelectedGroupBox", typeof(GroupBox), typeof(MainWindow),
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => (s as MainWindow).OnSelectedGroupBoxChanged())
);

public GroupBox SelectedGroupBox {
    get { return (GroupBox)GetValue(SelectedGroupBoxProperty); }
    set { SetValue(SelectedGroupBoxProperty, value); }
}

void OnSelectedGroupBoxChanged() {
    Console.WriteLine("selection is now " + this.SelectedGroupBox.Name);
}

#endregion

The ComboBox, for some very complex reasons exposes a read-only property called SelectionBoxItem. The content presenter in the ComboBox template binds on this property. It is the SelectionBoxItem that exposes the string representation of non-UI elements allowing you to see the selected value. The use of this property is what prevents the content presenter from using data templates. This is why the template applies to the drop down but not the selected item. Here is the part of the default ComboBox template causing the issue:

<ContentPresenter IsHitTestVisible="false"
    Margin="8,1,1,1"
    Content="{TemplateBinding SelectionBoxItem}"
    ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
    ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>

You can however create your own ComboBox style that overrides the default ContentPresenter and uses the SelectedItem instead of SelectionBoxItem and ItemTemplate instead of SelectionItemBoxTemplate. This will resolve the issue.

Binding to a 2nd properties if the 1st one is "undefined"

5 votes

I won't copy/paste my whole xaml file. It will be too long to explain it but here is what is interesting : I got a Binding of a Property "Name"

<TextBlock Text="{Binding Name}"/>

The thing is that sometimes, my item doesn't have a "Name" property. It doesn't crash but I simply got an empty Text in my TextBlock

What I would to do, if Name is empty, is to be binded to "nothing", just {Binding}. This will display my Object name and it will be perfect !

Thanks in advance for any help, and sorry if it is a noobie question :(

What you want here is a PriorityBinding.

In particular, it would look something like (exact syntax may need some verification):

         <TextBlock>
            <TextBlock.Text>
                <PriorityBinding>
                    <Binding Path="Name"/>
                    <Binding />
                </PriorityBinding>
            </TextBlock.Text>
         </TextBlock>

Note that this specifically falls back when the Name property is not available on the object being bound; if the Name property has an empty string value, I believe it will still use that empty value.

What parameters should I pass to my ViewModel's constructor?

5 votes

I'm pretty novice to WPF/MVVM and trying to understand this pattern. I'm exploring this MVVM application http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

Author created Customer class which is stored in Model folder and CustomerRepository class which is stored in DataAccess folder

CustomerRepository contains methods that 'do stuff', for example static List<Customer> LoadCustomers(string customerDataFile) I.e. we can't say that CustomerRepository is pure model file, it's also kind of utility file.

From another hand CustomerRepository stores important data readonly List<Customer> _customers; and we know that we should store such kind of data in model!

Well I would say that CustomerRepository is mixing things - it's a model file that contains some utility methods inside it.

The problem is that CustomerRepository instance is passed to ViewModel public AllCustomersViewModel(CustomerRepository customerRepository). Now viewModel contains something that it shouldn't, in particular it can force CustomerRepository to reload stuff etc.

In my opinion this is agains MVVM pattern, I think that ViewModel should only contain references to model files all utility classes and methods to manipulate model files should be in other places.

Am I right or wrong? Is it ok to pass class that offers some services on model (can reload/refhresh model etc.) to ViewModel? I.e. where should be so-called service layer, is it ok to have it in ViewModel?

AFAIK, there are two widespreas treatments of the MVVM pattern.

The first, which you seem to be more familiar with, includes 4 components: View, Model, ViewModel and Controller. Here, ViewModel contains only UI logic and exposes events to Controller which serves for synchronization between ViewModel and Model.

The second, which is used in the article, simply merges ViewModel and Controller into ViewModel. BTW, Martin Fowler describes this case: http://martinfowler.com/eaaDev/PresentationModel.html

The choice depends on personal preferences as I see it.

4 votes

Consider this example:

Private Sub Button_Click(
    sender As Button, e As RoutedEventArgs) Handles btn.Click

  sender.IsEnabled = False

  Thread.Sleep(5000)

  sender.IsEnabled = True
End Sub

In my scenario the Button_Click is a command delegate in the VM, and the Thread.Sleep is some long-running process (about 2-10 seconds).

I want, that when the user calls the command, it should immediately update the UI disabling the button so the user cannot execute it while it's running, then execute that operation, then, when operation completed, unblock the button.

I tried wrapping the middle line like the following:

Dispatcher.BeginInvoke(Sub() Thread.Sleep(5000))

But it didn't do the job.
What's the best way to do it?

Instead of creating a thread of your own you can also use the BackgroundWorker Control. By calling the Method "RunWorkerAsync" the DoWork Event get's called in another Thread.

By Calling the Method "CancelAsync" form your UI thread you can set the Backgroundworker to "Cancellation Pending" (Property of the Control "CancellationPending" is then true). In your long running background thread you can check for that property (e.g. if you have a loop: exit the loop as soon as CancellationPending is true). This is a quite nice feature to safely abort the thread.

In addition with the Backgroundworker you can also report the progress of the thread (e.g. for use in a ProgressBar)

Example:

Public Class Form1

   Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load

      '** Set to true if you want the ReportProgress Event
      BackgroundWorker1.WorkerReportsProgress = True
      BackgroundWorker1.WorkerSupportsCancellation = True
   End Sub

   Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

      Dim i As Integer
      Dim n As Integer = 100
      Dim iLastPerc As Integer


      While Not BackgroundWorker1.CancellationPending AndAlso i < n

         '** Do your time consuming actions here
         Threading.Thread.Sleep(500)

         If Math.Floor((i / n) * 100) > iLastPerc Then
            '** If the Progress has changed. Report
            iLastPerc = CInt(Math.Floor((i / n) * 100))
            BackgroundWorker1.ReportProgress(iLastPerc)
         End If

         i += 1
      End While

   End Sub

   Private Sub btnStart_Click(sender As System.Object, e As System.EventArgs) Handles btnStart.Click

      '** Run the Backgroundworker
      BackgroundWorker1.RunWorkerAsync()

   End Sub

   Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged

      '** Update the ProgressBar
      ProgressBar1.Value = e.ProgressPercentage

   End Sub

   Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted

      '** Worker is done. Check for Exceptions or evaluate the Result Object if you like

   End Sub

   Private Sub btnCancel_Click(sender As System.Object, e As System.EventArgs) Handles btnCancel.Click

      '** Cancel the worker
      BackgroundWorker1.CancelAsync()

      MsgBox("Finished!")

   End Sub
End Class

In reference to your question the code should be:

Private Sub btn_Click(sender As Button, e As RoutedEventArgs) Handles btn.Click
  sender.IsEnabled = False
  Using bw As New BackgroundWorker()
    AddHandler bw.DoWork, Sub(s, ea) Thread.Sleep(5000)
    AddHandler bw.RunWorkerCompleted, Sub(s, ea) sender.IsEnabled = True
    bw.RunWorkerAsync()
  End Using
End Sub