Silverlight datagrid double click behavior

by dsoltesz 19. February 2010 16:56 >

I wanted to allow users to be able to double click on a grid row and have some functionality performed.  At first I was using a double click manager class from http://weblogs.asp.net/aboschin/archive/2008/03/17/silverlight-2-0-a-double-click-manager.aspx 

I was typing same code through out my app to attach the double click code to my datagrids.  I decided to refactor this functionality into a behavior.

Here is double click manager class

/// <summary>

/// Class to attach mouse click events to UIElements

/// </summary>

    public class MouseClickManager

    {

        #region Private members

        private event MouseButtonEventHandler _click;

        private event MouseButtonEventHandler _doubleClick;

        #endregion

        #region Constructor

        /// <summary>

        /// Initializes a new instance of the <see cref="MouseClickManager"/> class.

        /// </summary>

        /// <param name="control">The control.</param>

        public MouseClickManager(int doubleClickTimeout)

        {

            this.Clicked = false;

            this.DoubleClickTimeout = doubleClickTimeout;

        }

        #endregion

        #region Events

        public event MouseButtonEventHandler Click

        {

            add { _click += value; }

            remove { _click -= value; }

        }

        public event MouseButtonEventHandler DoubleClick

        {

            add { _doubleClick += value; }

            remove { _doubleClick -= value; }

        }

        /// <summary>

        /// Called when [click].

        /// </summary>

        /// <param name="sender">The sender.</param>

        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>

        private void OnClick(object sender, MouseButtonEventArgs e)

        {

            if (_click != null)

            {

                Debug.Assert(sender is Control);

                (sender as Control).Dispatcher.BeginInvoke(_click, sender, e);

            }

        }

        /// <summary>

        /// Called when [double click].

        /// </summary>

        /// <param name="sender">The sender.</param>

        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>

        private void OnDoubleClick(object sender, MouseButtonEventArgs e)

        {

            if (_doubleClick != null)

            {

                _doubleClick(sender, e);

            }

        }

        /// <summary>

        /// Handles the click.

        /// </summary>

        /// <param name="sender">The sender.</param>

        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>

        public void HandleClick(object sender, MouseButtonEventArgs e)

        {

            lock (this)

            {

                if (this.Clicked)

                {

                    this.Clicked = false;

                    OnDoubleClick(sender, e);

                }

                else

                {

                    this.Clicked = true;

                    ParameterizedThreadStart threadStart = new ParameterizedThreadStart(ResetThread);

                    Thread thread = new Thread(threadStart);

                    thread.Start(e);

                }

            }

        }

        #endregion

        #region Properties

        /// <summary>

        /// Gets or sets a value indicating whether this <see cref="MouseClickManager"/> is clicked.

        /// </summary>

        /// <value><c>true</c> if clicked; otherwise, <c>false</c>.</value>

        private bool Clicked { get; set; }

        /// <summary>

        /// Gets or sets the timeout.

        /// </summary>

        /// <value>The timeout.</value>

        public int DoubleClickTimeout { get; set; }

        #endregion

        #region Methods

        #region Private

        /// <summary>

        /// Resets the thread.

        /// </summary>

        /// <param name="state">The state.</param>

        private void ResetThread(object state)

        {

            Thread.Sleep(this.DoubleClickTimeout);

 

            lock (this)

            {

                if (this.Clicked)

                {

                    this.Clicked = false;

                    OnClick(this, (MouseButtonEventArgs)state);

                }

            }

        }

        #endregion

        #endregion

    }

I then used that class to create my datagrid double click behavior

public class DataGridDoubleClickBehavior : Behavior<DataGrid>

    {

        private readonly MouseClickManager _gridClickManager;

        public event EventHandler<MouseButtonEventArgs> DoubleClick;

        public DataGridDoubleClickBehavior()

        {

            _gridClickManager = new MouseClickManager(300);

            _gridClickManager.DoubleClick += new MouseButtonEventHandler(_gridClickManager_DoubleClick);

        }

        protected override void OnAttached()

        {

            base.OnAttached();

            AssociatedObject.LoadingRow += OnLoadingRow;

            AssociatedObject.UnloadingRow += OnUnloadingRow;

        }

        void OnUnloadingRow(object sender, DataGridRowEventArgs e)

        {

            //row is no longer visible so remove double click event otherwise

            //row events will miss fire

            e.Row.MouseLeftButtonUp -= _gridClickManager.HandleClick;

        }

        void OnLoadingRow(object sender, DataGridRowEventArgs e)

        {

            //row is visible in grid, wire up double click event

            e.Row.MouseLeftButtonUp += _gridClickManager.HandleClick;

        }

        protected override void OnDetaching()

        {

            base.OnDetaching();

            AssociatedObject.LoadingRow -= OnLoadingRow;

            AssociatedObject.UnloadingRow -= OnUnloadingRow;

        }

        void _gridClickManager_DoubleClick(object sender, MouseButtonEventArgs e)

        {

            if (DoubleClick != null)

                DoubleClick(sender, e);

        }

    }

Once the behavior is created we can now add to our datagrid

  1. add a reference to System.Windows.Interactivity
  2. In your xaml code add
    1. xmlns

      :i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    2. xmlns

      :behaviors="clr-namespace:MyApp.Behaviors;assembly=MyApp"
    3. <data:DataGrid x:Name="myDataGrid">

      <i:Interaction.Behaviors>

                  <behaviors:DataGridDoubleClickBehavior DoubleClick="myDataGrid_DoubleClick"/>

            </i:Interaction.Behaviors>

      </data:DataGrid>

In your code behind, handle the double click event

private void MyDatagrid_DoubleClick(object sender, MouseButtonEventArgs e)

{

      //do something      

}

That's it, now you have double click events for your data grid

Tags: , , , ,

.NET | c# | silverlight | behaviors

about the author

My name is Dan Soltesz, and I"m a consultant specializing in Microsoft technologies

  • Silverlight 2.0,3.0,4.0,5.0
  • Windows Phone 7,8
  • Windows 8
  • WPF
  • MVC / SPA
  • ASP.NET 2.0,3.0,3.5,4.0
  • WCF, WCF Ria Services
  • Entity Framework / EF Code First
  • C#
  • MVVM, Repository Pattern

to name a few.  On this site you will find links to sites/blogs that I read and my own attempt at writing some blogs that may help others as well as a few miscellaneous items.  If there is something that you need to know about me and cannot find on this site, please feel free to contact me.

page list

sponsors

month list

recentcomments

Comment RSS