Solving development problems  |  About this blog

Archive for the ‘wpf’ tag

Silverlight: Equidistant items in a stack panel

This post describes how to align items in a container so the two neighbour items are always aligned with equal distance. Solution should be flexible, meaning that when items are changed or when container is resized items should keep equal distance in between. Reader should have some basic knowledge about C# and XAML for Silverlight.

Ideas

  • using Canvas and positioning items with absolute coordinates – items are always fixed, coordinates need to be calculated, so it is the least flexible approach, no
  • using StackPanel with items that have margin – margins need to be recalculated when an item is added or removed or when container is resized, maybe
  • using Grid with predefined rows and columns – notice predefined, means less flexibility, but offers equal size rows/columns, maybe
  • using a custom control – making Grid more dynamic but extending number of rows/columns when items are added, yes

Custom Control: EqualDistanceStackPanel

As written before, custom control should extend Grid to become more flexible

public class EqualDistanceStackPanel : Grid
{
}

 

EqualDistanceStackPanel should implement ItemsSource and ItemTemplate just like ItemsControl

#region ItemsSource
public IEnumerable ItemsSource
{
  get { return (IEnumerable)GetValue(ItemsSourceProperty); }
  set { SetValue(ItemsSourceProperty, value); }
}

public static readonly DependencyProperty ItemsSourceProperty =
  DependencyProperty.Register("ItemsSource", typeof(IEnumerable),
  typeof(EqualDistanceStackPanel), new PropertyMetadata(ItemsSourceChanged));

private static void ItemsSourceChanged(DependencyObject d,
  DependencyPropertyChangedEventArgs e)
{
  var panel = d as EqualDistanceStackPanel;
  if (panel != null)
  {
    if (e.OldValue != null)
    {
      panel.ClearItems();
    }
    if (e.NewValue != null)
    {
      panel.BindItems(e.NewValue as IEnumerable);
    }
  }
}
#endregion

public DataTemplate ItemTemplate
{
  get;
  set;
}

 

ClearItems method deletes all previous elements from the panel and BindItems attaches fresh controls from item template.

protected void ClearItems()
{
  this.Children.Clear();
}

protected void BindItems(IEnumerable items)
{
  if (this.ItemTemplate == null)
  {
    return;
  }

  //Create and attach children
  foreach (var item in items)
  {
    var element = this.ItemTemplate.LoadContent() as FrameworkElement;
    element.DataContext = item;
    this.Children.Add(element);
  }

  //Realign in container
  Refresh();
}

 

How should the custom control look in XAML? EqualDistanceStackPanel gets a collection of items, e.g. of UIElement type.

<Grid xmlns:c="clr-namespace:Avivo.Controls">
  <c:EqualDistanceStackPanel ItemsSource="{Binding Items}" Orientation="Vertical">
    <c:EqualDistanceStackPanel.ItemTemplate>
      <DataTemplate>
        <ContentPresenter Content="{Binding}" />
      </DataTemplate>
    </c:EqualDistanceStackPanel.ItemTemplate>
  </c:EqualDistanceStackPanel>
</Grid>

 

Example

Ruler has been made to demonstrate the usage of EqualDistanceStackPanel. Numbers are bound to the control and ticks are bound to another control using the same binding collection. Left image represents container height 300px and right when resized to 460px – elements are automatically aligned with equal distance.

Try demo, resize browser to see the effect. This control has been originally developed for custom chart axes in QR Code Statistics application. EqualDistanceStackPanel control is lightweight, works for the statistics application and should be improved for general usage.

Source code

  • Source code, Visual Studio sample Silverlight and web project

References

Written by developer

March 29th, 2011 at 2:00 pm

How to focus window in WPF when it gets out of focus

Sometimes you want to have your WPF application in “kiosk” mode (fullscreen) and you can do this with this code:

Window w = new Window();
w.WindowStyle = WindowStyle.None;
w.WindowState = WindowState.Maximized;
w.TopMost = true;
w.ResizeMode=NoResize;
w.Show();

But, some system message (yellow balloon in system tray shows Taskbar in focus or any other Window system task) can get your application out of focus. In order to get it back to focus use this code:

//Interop.cs
using System.Runtime.InteropServices;
using System.Windows.Interop;

public class Interop
{
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();

public static IntPtr GetWindowHandle(Window window)
{
return new WindowInteropHelper(window).Handle;
}
}

//Somewhere in main window
IntPtr window = Interop.GetWindowHandle(this);
IntPtr focused = Interop.GetForegroundWindow();
if (window != focused)
{
Interop.SetForegroundWindow(window);
}

Written by Avivo

November 9th, 2009 at 11:48 am

Catching WPF Unhandled Exception

You can tell the debbuger to throw that exception.

1. In Visual Studio (checked in 2008) go to Debug/Exceptions.
2. Open tree of ‘Win32 Exceptions’
3. Check ‘Thrown’ checkbox in ‘c0000005 Access violation’ (the forth in my list)
4. Run your project in debug and the exception should be thrown in the line causing it.

Written by Avivo

June 17th, 2009 at 6:49 pm

WPF Performance and Debugging Tools

Performance Profiling Tools for WPF
http://windowsclient.net/wpf/perf/wpf-perf-tool.aspx

Mole debugging tool
http://www.codeproject.com/KB/macros/MoleForVisualStudioEdit.aspx

Snoop tool
http://blois.us/Snoop/

CLR Profile tool
http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=en

WinDebug tool
http://www.microsoft.com/whdc/devtools/debugging/default.mspx


Written by Avivo

June 17th, 2009 at 6:20 pm

Catch Thread Exceptions in WPF

http://www.jimandkatrin.com/codeblog/2008/06/wpf-worker-thread-exceptions.html

What if you want to do global exception handling with worker threads? My scenario involves data methods that may be called synchronously, on the UI thread, or asynchronously on a worker. I would like to use the same global exception handling for both.

The problem with this scenario is that unhandled exceptions in the worker thread may cause the application to terminate; there’s no handler you can use or flag you can set to prevent this.

One way of handling this is explained as a side note in MSDN’s Application.DispatcherUnhandledExceptiondocumentation:

  1. Handle exceptions on the background thread.
  2. Dispatch those exceptions to the main UI thread.
  3. Rethrow them on the main UI thread without handling them to allow DispatcherUnhandledException to be raised.

I guess they thought the code was too obvious to bother providing an example…

That list is mentioned in the MSDN forums, where an example was promised, but not delivered.

try
{
    . . .
}
catch (Exception ex)
{
    . . . 

    // Are we not on the main UI thread?
    if (!Application.Current.Dispatcher.CheckAccess())
    {
        // Unhandled exceptions on worker threads will halt the application. We want to
        // use our global exception handler(s), so dispatch or "forward" to the UI thread.
        Application.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Normal,
            new Action<Exception>(WorkerThreadException), ex);
    }
    else
    {
        throw;  // Already on UI thread; just rethrow the exception to global handlers
    }
}

The WorkerThreadException method simply re-throws the exception on the UI thread, where it is handled by any global exception handlers that have been defined:

private static void WorkerThreadException(Exception ex)
{
    throw ex;
}

Written by Avivo

June 17th, 2009 at 5:36 pm