WPF: MenuButton

i was looking for a Menu-Button (some call it Drop-Down-Button) and found this post: DropDownButtons in WPF.
all credits goes to Andy, i’ve just adapted his code and idea.
here is my version:

public class MenuButton : ToggleButton
{
    public enum Placement { Bottom, Right }
    public Placement MenuPlacement { private get; set; }

    #region DropDown (DependencyProperty)

    public ContextMenu Menu
    {
        get { return (ContextMenu)GetValue(MenuProperty); }
        set { SetValue(MenuProperty, value); }
    }
    public static readonly DependencyProperty MenuProperty =
        DependencyProperty.Register("Menu", typeof(ContextMenu), typeof(MenuButton),
            new PropertyMetadata(null, OnMenuChanged)
            );

    private static void OnMenuChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        ((MenuButton)sender).OnMenuChanged(e);
    }

    private void OnMenuChanged(DependencyPropertyChangedEventArgs e)
    {
        if (Menu != null)
        {
            Menu.PlacementTarget = this;

            switch (MenuPlacement)
            {
                default:
                case Placement.Bottom:
                    Menu.Placement = PlacementMode.Bottom;
                    break;
                case Placement.Right:
                    Menu.Placement = PlacementMode.Right;
                    break;
            }

            this.Checked += new RoutedEventHandler((a, b) => { Menu.IsOpen = true; });
            this.Unchecked += new RoutedEventHandler((a, b) => { Menu.IsOpen = false; });
            Menu.Closed += new RoutedEventHandler((a, b) => { this.IsChecked = false; });
        }
    }

    #endregion

    #region MenuSource (DependencyProperty)

    public IEnumerable MenuSource
    {
        get { return (IEnumerable)GetValue(MenuSourceProperty); }
        set { SetValue(MenuSourceProperty, value); }
    }
    public static readonly DependencyProperty MenuSourceProperty =
        DependencyProperty.Register("MenuSource", typeof(IEnumerable), typeof(MenuButton),
            new PropertyMetadata(null, OnMenuSourceChanged)
            );

    private static void OnMenuSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        ((MenuButton)sender).OnMenuSourceChanged(e);
    }

    private void OnMenuSourceChanged(DependencyPropertyChangedEventArgs e)
    {
        if (Menu == null)
            Menu = new ContextMenu();

        Menu.ItemsSource = e.NewValue as IEnumerable;
    }

    #endregion

}

WPF: DataGrid with integrated field (column) chooser

following a discussion in the comments of this post
this is the WPF version of a DataGrid control with integrated columns chooser that opens when right-clicking one of the headers.
(see Silverlight demo)
full source code over here

this is how it look like:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace WPF_DataGridWithColumnChooser.Controls
{
    public class DataGridExtended : DataGrid
    {
        public DataGridExtended()
            : base()
        {
            theContextMenu = new ContextMenu();
            this.Columns.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Columns_CollectionChanged);
        }

        private ContextMenu theContextMenu; //context menu for the field chooser.
        private string AllColumnsHeaders { get; set; }
        private bool oneTime = true;

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (oneTime)// do this only once.
            {
                oneTime = false;
                var headersPresenter = FindChild(this);
                // attach the context menu.
                ContextMenuService.SetContextMenu(headersPresenter, theContextMenu);

                // update VisibleColumns as necessary.
                if (String.IsNullOrEmpty(VisibleColumns))
                {
                    VisibleColumns = AllColumnsHeaders;
                }
                else
                {
                    string s = VisibleColumns;
                    VisibleColumns = null;
                    VisibleColumns = s;
                }
            }
            return base.ArrangeOverride(finalSize);
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            MenuItem mi = sender as MenuItem;
            Image icon = (Image)mi.Icon;
            List splited = VisibleColumns.Split(';').ToList();
            string colName = mi.Header.ToString();

            // remove empty items.
            for (int i = 0; i  1)
                {
                    splited.Remove(colName);
                }
            }

            // update the VisibleColumns.
            string build = "";
            foreach (string name in splited)
            {
                build = string.Format("{0};{1}", name, build);
            }
            VisibleColumns = build;
        }

        private void Columns_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {

            DataGridColumn col = e.NewItems[0] as DataGridColumn;

            // keep a list of all clomuns headers for later use.
            AllColumnsHeaders = String.Format("{0};{1}", col.Header.ToString(), AllColumnsHeaders);

            // make a new menu item and add it to the context menu.
            MenuItem menuItem = new MenuItem();
            Image img;
            menuItem.Click += new RoutedEventHandler(MenuItem_Click);
            menuItem.Header = col.Header.ToString();
            img = new Image();
            img.Source = Application.Current.Resources["Vmark"] as ImageSource;
            menuItem.Icon = img;
            theContextMenu.Items.Add(menuItem);

        }

        #region VisibleColumns (DependencyProperty)

        /// <summary>
        /// Gets or sets a value indicating the names of columns (as they appear in the column header) to be visible, seperated by a semicolon.
        /// columns that whose name is not here will be hidden.
        /// </summary>
        public string VisibleColumns
        {
            get { return (string)GetValue(VisibleColumnsProperty); }
            set { SetValue(VisibleColumnsProperty, value); }
        }

        public static readonly DependencyProperty VisibleColumnsProperty =
            DependencyProperty.Register(
                "VisibleColumns",
                typeof(string),
                typeof(DataGridExtended),
                new PropertyMetadata("", new PropertyChangedCallback(OnVisibleColumnsChanged))
                );

        private static void OnVisibleColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGridExtended dg = (DataGridExtended)d;
            dg.VisibleColumnsChanged(e);

        }

        private void VisibleColumnsChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
            {
                string[] showTheseColumns = e.NewValue.ToString().Split(';');
                string colName;

                // update the columns visibility.
                foreach (DataGridColumn col in this.Columns)
                {
                    colName = col.Header.ToString();

                    if (showTheseColumns.Contains(colName))
                        col.Visibility = Visibility.Visible;
                    else
                        col.Visibility = Visibility.Collapsed;
                }

                // update the context menu items.
                if (theContextMenu != null)
                {
                    foreach (MenuItem menuItem in theContextMenu.Items)
                    {
                        colName = menuItem.Header.ToString();
                        if (showTheseColumns.Contains(colName))
                            ((Image)menuItem.Icon).Visibility = Visibility.Visible;
                        else
                            ((Image)menuItem.Icon).Visibility = Visibility.Collapsed;
                    }
                }
            }
        }

        #endregion

        public static T FindChild(DependencyObject depObj) where T : DependencyObject
        {
            // Confirm obj is valid. 
            if (depObj == null) return null;

            // success case
            if (depObj is T)
                return depObj as T;

            for (int i = 0; i &lt; VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);

                T obj = FindChild(child);

                if (obj != null)
                    return obj;
            }

            return null;
        }
    }

}

Silverlight: toggle button bar

I have seen this asked several times: how to make a toggle button bar in Silverlight?
Some might call it toggle button group.

I have simply taken the ToggleButton template and dressed it on a RadioButton, with few minor changes like padding and corner radius.

Here is how it looks
Here is the source

Silverlight: DataGrid with integrated field (column) chooser

Not much to say here, it speaks for itself.

Right click on a column header to open the field (columns) chooser and show/hide columns.

The VisibleColumns property is always up-to-date and can be binded TwoWay, in my case I am saving it to the user preferences for consistency.

Take a look at the code to see how it’s done.

Notice: ContextMenu causes memory leak! http://silverlight.codeplex.com/workitem/7089. as long as you don’t need to remove the DataGrid you are OK.

Demo is Here
Source is here

the WPF version is over here

Silverlight: GridSplitter with a collapse button – BEST

I don’t remember where I took this control from.
It is not my work so I cannot take credit for it.
I have only fixed some stuff and made some changes to the animation.
This is by far the BEST version of this control! Use this one!
All credits goes to the anonymous developer who made it.
it should go into the Toolkit.

Demo is here
source is here

Silverlight: double click Trigger & call method Action

There are many different ways to implement double click in Silverlight, I chose to write it as a Trigger so it can be used anywhere and easily.

Of course you can write your own Action to use with that Trigger, but I wanted a most generic Action that will call a method and also could be used anywhere and easily.

The following Trigger (DoubleClick) & Action (InvokeMethodAction) classes act like any other event & handler. They can be used on any UIElement.

DoubleClick:

public class DoubleClick : TriggerBase<UIElement>
{
    private readonly DispatcherTimer _timer;
    private Point _clickPosition;

    public DoubleClick()
    {
        _timer = new DispatcherTimer
        {
            Interval = new TimeSpan(0, 0, 0, 0, 300)
        };

        _timer.Tick += OnTimerTick;
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.MouseLeftButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
    }

    void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        UIElement element = sender as UIElement;

        if (_timer.IsEnabled)
        {
            _timer.Stop();
            Point position = e.GetPosition(element);

            if (Math.Abs(_clickPosition.X - position.X) < 1 && Math.Abs(_clickPosition.Y - position.Y) < 1)
            {
                InvokeActions(null);
            }
        }
        else
        {
            _timer.Start();
            _clickPosition = e.GetPosition(element);
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        AssociatedObject.MouseLeftButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
        if (_timer.IsEnabled)
            _timer.Stop();
    }

    private void OnTimerTick(object sender, EventArgs e)
    {
        _timer.Stop();
    }
}

InvokeMethodAction:

public class InvokeMethodAction : TargetedTriggerAction<UIElement>
{
    protected override void Invoke(object parameter)
    {
        if (MethodToInvoke != null)
        {
            MethodToInvoke(Target, null);
        }
    }

    public delegate void Handler(object sender, RoutedEventArgs e);
    public event Handler MethodToInvoke;

}

Download sample project here.

Follow

Get every new post delivered to your Inbox.