Wpf 使用VirtualToggleButtona和PreviewMouseDown查看树视图。古怪的行为

Wpf 使用VirtualToggleButtona和PreviewMouseDown查看树视图。古怪的行为,wpf,Wpf,读过之后,我决定使用VirtualToggleButton,并添加了另外两个布尔属性SuppressKeyboard和SuppressMouse来定义e.Handle是否应设置为True 以下是已更改VTB的代码: public static class VirtualToggleButton { #region attached properties #region IsChecked /// <summary>

读过之后,我决定使用VirtualToggleButton,并添加了另外两个布尔属性SuppressKeyboard和SuppressMouse来定义e.Handle是否应设置为True

以下是已更改VTB的代码:

public static class VirtualToggleButton
    {
        #region attached properties

        #region IsChecked

        /// <summary>
        /// IsChecked Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.RegisterAttached("IsChecked", typeof(Nullable<bool>), typeof(VirtualToggleButton),
                new FrameworkPropertyMetadata((Nullable<bool>)false,
                    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
                    new PropertyChangedCallback(OnIsCheckedChanged)));

        /// <summary>
        /// Gets the IsChecked property.  This dependency property 
        /// indicates whether the toggle button is checked.
        /// </summary>
        public static Nullable<bool> GetIsChecked(DependencyObject d)
        {
            return (Nullable<bool>)d.GetValue(IsCheckedProperty);
        }

        /// <summary>
        /// Sets the IsChecked property.  This dependency property 
        /// indicates whether the toggle button is checked.
        /// </summary>
        public static void SetIsChecked(DependencyObject d, Nullable<bool> value)
        {
            d.SetValue(IsCheckedProperty, value);
        }

        /// <summary>
        /// Handles changes to the IsChecked property.
        /// </summary>
        private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var pseudobutton = d as UIElement;
            if (pseudobutton != null)
            {
                var newValue = (Nullable<bool>)e.NewValue;
                if (newValue == true)
                {
                    RaiseCheckedEvent(pseudobutton);
                }
                else if (newValue == false)
                {
                    RaiseUncheckedEvent(pseudobutton);
                }
                else
                {
                    RaiseIndeterminateEvent(pseudobutton);
                }
            }
        }

        #endregion

        #region IsThreeState

        /// <summary>
        /// IsThreeState Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty IsThreeStateProperty =
            DependencyProperty.RegisterAttached("IsThreeState", typeof(bool), typeof(VirtualToggleButton),
                new FrameworkPropertyMetadata((bool)false));

        /// <summary>
        /// Gets the IsThreeState property.  This dependency property 
        /// indicates whether the control supports two or three states.  
        /// IsChecked can be set to null as a third state when IsThreeState is true.
        /// </summary>
        public static bool GetIsThreeState(DependencyObject d)
        {
            return (bool)d.GetValue(IsThreeStateProperty);
        }

        /// <summary>
        /// Sets the IsThreeState property.  This dependency property 
        /// indicates whether the control supports two or three states. 
        /// IsChecked can be set to null as a third state when IsThreeState is true.
        /// </summary>
        public static void SetIsThreeState(DependencyObject d, bool value)
        {
            d.SetValue(IsThreeStateProperty, value);
        }

        #endregion

        #region IsVirtualToggleButton

        /// <summary>
        /// IsVirtualToggleButton Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty IsVirtualToggleButtonProperty =
            DependencyProperty.RegisterAttached("IsVirtualToggleButton", typeof(bool), typeof(VirtualToggleButton),
                new FrameworkPropertyMetadata((bool)false,
                    new PropertyChangedCallback(OnIsVirtualToggleButtonChanged)));

        /// <summary>
        /// Gets the IsVirtualToggleButton property.  This dependency property 
        /// indicates whether the object to which the property is attached is treated as a VirtualToggleButton.  
        /// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would.
        /// </summary>
        public static bool GetIsVirtualToggleButton(DependencyObject d)
        {
            return (bool)d.GetValue(IsVirtualToggleButtonProperty);
        }

        /// <summary>
        /// Sets the IsVirtualToggleButton property.  This dependency property 
        /// indicates whether the object to which the property is attached is treated as a VirtualToggleButton.  
        /// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would.
        /// </summary>
        public static void SetIsVirtualToggleButton(DependencyObject d, bool value)
        {
            d.SetValue(IsVirtualToggleButtonProperty, value);
        }

        /// <summary>
        /// Handles changes to the IsVirtualToggleButton property.
        /// </summary>
        private static void OnIsVirtualToggleButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = d as IInputElement;
            if (element != null)
            {
                if ((bool)e.NewValue)
                {
                    element.AddHandler(Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(OnPreviewMouseLeftButtonDown));
                    element.PreviewKeyDown += OnPreviewKeyDown;
                }
                else
                {
                    element.RemoveHandler(Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(OnPreviewMouseLeftButtonDown));
                    element.PreviewKeyDown -= OnPreviewKeyDown;
                }
            }
        }

        #endregion

        #region SuppressKeyboard

        public static readonly DependencyProperty SuppressKeyboardProperty =
            DependencyProperty.RegisterAttached("SuppressKeyboard", typeof (bool), typeof (VirtualToggleButton),
                                                new FrameworkPropertyMetadata(false));

        public static bool GetSuppressKeyboard(DependencyObject d)
        {
            return (bool)d.GetValue(SuppressKeyboardProperty);
        }

        public static void SetSuppressKeyboard(DependencyObject d, bool value)
        {
            d.SetValue(SuppressKeyboardProperty, value);
        }

        #endregion

        #region SuppressMouse

        public static readonly DependencyProperty SuppressMouseProperty =
            DependencyProperty.RegisterAttached("SuppressMouse", typeof(bool), typeof(VirtualToggleButton),
                                                new FrameworkPropertyMetadata(false));

        public static bool GetSuppressMouse(DependencyObject d)
        {
            return (bool)d.GetValue(SuppressMouseProperty);
        }

        public static void SetSuppressMouse(DependencyObject d, bool value)
        {
            d.SetValue(SuppressKeyboardProperty, value);
        }

        #endregion

        #endregion

        #region routed events

        #region Checked

        /// <summary>
        /// A static helper method to raise the Checked event on a target element.
        /// </summary>
        /// <param name="target">UIElement or ContentElement on which to raise the event</param>
        internal static RoutedEventArgs RaiseCheckedEvent(UIElement target)
        {
            if (target == null) 
                return null;

            var args = new RoutedEventArgs {RoutedEvent = ToggleButton.CheckedEvent};
            RaiseEvent(target, args);
            return args;
        }

        #endregion

        #region Unchecked

        /// <summary>
        /// A static helper method to raise the Unchecked event on a target element.
        /// </summary>
        /// <param name="target">UIElement or ContentElement on which to raise the event</param>
        internal static RoutedEventArgs RaiseUncheckedEvent(UIElement target)
        {
            if (target == null) return null;

            RoutedEventArgs args = new RoutedEventArgs();
            args.RoutedEvent = ToggleButton.UncheckedEvent;
            RaiseEvent(target, args);
            return args;
        }

        #endregion

        #region Indeterminate

        /// <summary>
        /// A static helper method to raise the Indeterminate event on a target element.
        /// </summary>
        /// <param name="target">UIElement or ContentElement on which to raise the event</param>
        internal static RoutedEventArgs RaiseIndeterminateEvent(UIElement target)
        {
            if (target == null) return null;

            RoutedEventArgs args = new RoutedEventArgs();
            args.RoutedEvent = ToggleButton.IndeterminateEvent;
            RaiseEvent(target, args);
            return args;
        }

        #endregion

        #endregion

        #region private methods

        private static void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Left && e.LeftButton == MouseButtonState.Pressed)
            {
                UpdateIsChecked(sender as DependencyObject);

                var dob = sender as DependencyObject;
                var suppress = dob != null && GetSuppressMouse(dob);
                e.Handled = suppress;
            }
        }

        private static void OnPreviewKeyDown(object sender, KeyEventArgs e)
        {
            var dob = sender as DependencyObject;
            var suppress = dob != null && GetSuppressKeyboard(dob);

            if (e.OriginalSource == sender)
            {
                if (e.Key == Key.Space)
                {
                    // ignore alt+space which invokes the system menu
                    if ((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt) 
                        return;

                    UpdateIsChecked(sender as DependencyObject);
                    e.Handled = suppress;
                }
                else if (e.Key == Key.Enter && (bool)(sender as DependencyObject).GetValue(KeyboardNavigation.AcceptsReturnProperty))
                {
                    UpdateIsChecked(sender as DependencyObject);
                    e.Handled = suppress;
                }
            }
        }

        private static void UpdateIsChecked(DependencyObject d)
        {
            Nullable<bool> isChecked = GetIsChecked(d);
            if (isChecked == true)
            {
                SetIsChecked(d, GetIsThreeState(d) ? (Nullable<bool>)null : (Nullable<bool>)false);
            }
            else
            {
                SetIsChecked(d, isChecked.HasValue);
            }
        }

        private static void RaiseEvent(DependencyObject target, RoutedEventArgs args)
        {
            if (target is UIElement)
            {
                (target as UIElement).RaiseEvent(args);
            }
            else if (target is ContentElement)
            {
                (target as ContentElement).RaiseEvent(args);
            }
        }

        #endregion
    }
公共静态类VirtualToggleButton
{
#区域附着属性
#检查区域
/// 
///已检查附加的依赖项属性
/// 
公共静态只读从属属性是检查属性=
DependencyProperty.RegisterAttached(“IsChecked”)、typeof(可空)、typeof(VirtualToggleButton),
新FrameworkPropertyMetadata((可空)false,
FrameworkPropertyMetadataOptions.BindsTwoWay默认为| FrameworkPropertyMetadataOptions.Journal,
新财产变更回拨(OnIsCheckedChanged));
/// 
///获取IsChecked属性。此依赖项属性
///指示是否选中切换按钮。
/// 
公共静态可空GetIsChecked(DependencyObject d)
{
返回(可空)d.GetValue(IsCheckedProperty);
}
/// 
///设置IsChecked属性。此依赖项属性
///指示是否选中切换按钮。
/// 
公共静态void SetIsChecked(DependencyObject d,可空值)
{
d、 设置值(IsCheckedProperty,value);
}
/// 
///处理对IsChecked属性的更改。
/// 
私有静态void OnIsCheckedChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var pseudobutton=d作为UIElement;
if(伪按钮!=null)
{
var newValue=(可空)e.newValue;
if(newValue==true)
{
RAISECECKEDEVENT(伪按钮);
}
else if(newValue==false)
{
升起检查按钮(伪按钮);
}
其他的
{
RASEINDETERMINATEEVENT(伪按钮);
}
}
}
#端区
#第三产业区
/// 
///IsThrestate附加的依赖项属性
/// 
public static readonly dependencProperty是三重属性=
DependencyProperty.RegisterAttached(“IsThrestate”)、typeof(bool)、typeof(VirtualToggleButton),
新的FrameworkPropertyMetadata((bool)false));
/// 
///获取IsThrestate属性。此依赖项属性
///指示控件是否支持两种或三种状态。
///IsThrestate为true时,可以将IsChecked设置为null作为第三种状态。
/// 
公共静态bool getIsThrestate(DependencyObject d)
{
返回(bool)d.GetValue(IsThrestateProperty);
}
/// 
///设置IsThrestate属性。此依赖项属性
///指示控件是否支持两种或三种状态。
///IsThrestate为true时,可以将IsChecked设置为null作为第三种状态。
/// 
公共静态void setIsThrestate(DependencyObject d,布尔值)
{
d、 设置值(IsThrestateProperty,值);
}
#端区
#区域为虚拟连接按钮
/// 
///IsVirtualToggleButton附加的依赖项属性
/// 
公共静态只读从属属性IsVirtualToggleButtonProperty=
DependencyProperty.RegisterAttached(“IsVirtualToggleButton”)、typeof(bool)、typeof(VirtualToggleButton),
新的FrameworkPropertyMetadata((bool)false,
新属性ChangedCallback(OnIsVirtualToggleButtonChanged));
/// 
///获取IsVirtualToggleButton属性。此依赖项属性
///指示属性所附加到的对象是否被视为VirtualToggleButton。
///如果为true,对象将以与切换按钮相同的方式响应键盘和鼠标输入。
/// 
公共静态布尔GetIsVirtualToggleButton(DependencyObject d)
{
返回(bool)d.GetValue(IsVirtualToggleButtonProperty);
}
/// 
///设置IsVirtualToggleButton属性。此依赖项属性
///指示属性所附加到的对象是否被视为VirtualToggleButton。
///如果为true,对象将以与切换按钮相同的方式响应键盘和鼠标输入。
/// 
公共静态void SetIsVirtualToggleButton(DependencyObject d,布尔值)
{
d、 SetValue(IsVirtualToggleButtonProperty,值);
}
/// 
///处理对IsVirtualToggleButton属性的更改。
/// 
私有静态void OnIsVirtualToggleButtonChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var元素=d作为IIInputElement;
if(元素!=null)
{
if((bool)e.NewValue)
{
AddHandler(Mouse.PreviewMouseDownEvent,新的MouseButtonEventHandler(OnPreviewMouseLeftButtonDown));
element.PreviewKeyDown+=OnPreviewKeyDown;
}
其他的
{
RemoveHandler(Mouse.PreviewMouseDownEvent,新的MouseButtonEventHandler(OnPreviewMouseLeftButtonDown));
element.PreviewKeyDown-=OnPreviewKeyDown;
}
}
}
#端区
#区域抑制键盘
公共静态只读从属属性SuppressKeyboardProperty=
DependencyProperty.RegisterAttached(“SuppressKeyboard”、typeof(bool)、typeof(VirtualToggleButton)
<TreeView>
            <TreeView.Resources>
                <Style TargetType="TreeViewItem">
                    <Setter Property="IsExpanded" Value="True"/>
                    <Setter Property="cl:VirtualToggleButton.IsVirtualToggleButton" Value="True"/>
                    <Setter Property="cl:VirtualToggleButton.SuppressKeyboard" Value="True"/>
                    <!--<Setter Property="cl:VirtualToggleButton.SuppressMouse" Value="True"/>-->
                </Style>
            </TreeView.Resources>

            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Softwares}">
                    <TextBlock Text="{Binding Name}"/>
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <CheckBox Focusable="False" 
                                          IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeViewItem}}
                                                                    , Path=(cl:VirtualToggleButton.IsChecked), Mode=OneWay}"/>
                                <TextBlock Text="{Binding Name}" Height="Auto"/>
                            </StackPanel>
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>

        </TreeView>
public static class VirtualToggleButton
    {
        #region attached properties

        #region IsChecked

        public static readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.RegisterAttached("IsChecked", typeof(Nullable<bool>), typeof(VirtualToggleButton),
                new FrameworkPropertyMetadata((Nullable<bool>)false,
                    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
                    new PropertyChangedCallback(OnIsCheckedChanged)));

        /// <summary>
        /// Gets the IsChecked property.  This dependency property 
        /// indicates whether the toggle button is checked.
        /// </summary>
        public static Nullable<bool> GetIsChecked(DependencyObject d)
        {
            return (Nullable<bool>)d.GetValue(IsCheckedProperty);
        }

        /// <summary>
        /// Sets the IsChecked property.  This dependency property 
        /// indicates whether the toggle button is checked.
        /// </summary>
        public static void SetIsChecked(DependencyObject d, Nullable<bool> value)
        {
            d.SetValue(IsCheckedProperty, value);
        }

        /// <summary>
        /// Handles changes to the IsChecked property.
        /// </summary>
        private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var pseudobutton = d as UIElement;
            if (pseudobutton != null)
            {
                var newValue = (Nullable<bool>)e.NewValue;
                if (newValue == true)
                {
                    RaiseCheckedEvent(pseudobutton);
                }
                else if (newValue == false)
                {
                    RaiseUncheckedEvent(pseudobutton);
                }
                else
                {
                    RaiseIndeterminateEvent(pseudobutton);
                }
            }
        }

        #endregion

        #region IsThreeState

        /// <summary>
        /// IsThreeState Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty IsThreeStateProperty =
            DependencyProperty.RegisterAttached("IsThreeState", typeof(bool), typeof(VirtualToggleButton),
                new FrameworkPropertyMetadata((bool)false));

        /// <summary>
        /// Gets the IsThreeState property.  This dependency property 
        /// indicates whether the control supports two or three states.  
        /// IsChecked can be set to null as a third state when IsThreeState is true.
        /// </summary>
        public static bool GetIsThreeState(DependencyObject d)
        {
            return (bool)d.GetValue(IsThreeStateProperty);
        }

        /// <summary>
        /// Sets the IsThreeState property.  This dependency property 
        /// indicates whether the control supports two or three states. 
        /// IsChecked can be set to null as a third state when IsThreeState is true.
        /// </summary>
        public static void SetIsThreeState(DependencyObject d, bool value)
        {
            d.SetValue(IsThreeStateProperty, value);
        }

        #endregion

        #region IsVirtualToggleButton

        /// <summary>
        /// IsVirtualToggleButton Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty IsVirtualToggleButtonProperty =
            DependencyProperty.RegisterAttached("IsVirtualToggleButton", typeof(bool), typeof(VirtualToggleButton),
                new FrameworkPropertyMetadata((bool)false,
                    new PropertyChangedCallback(OnIsVirtualToggleButtonChanged)));

        /// <summary>
        /// Gets the IsVirtualToggleButton property.  This dependency property 
        /// indicates whether the object to which the property is attached is treated as a VirtualToggleButton.  
        /// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would.
        /// </summary>
        public static bool GetIsVirtualToggleButton(DependencyObject d)
        {
            return (bool)d.GetValue(IsVirtualToggleButtonProperty);
        }

        /// <summary>
        /// Sets the IsVirtualToggleButton property.  This dependency property 
        /// indicates whether the object to which the property is attached is treated as a VirtualToggleButton.  
        /// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would.
        /// </summary>
        public static void SetIsVirtualToggleButton(DependencyObject d, bool value)
        {
            d.SetValue(IsVirtualToggleButtonProperty, value);
        }

        /// <summary>
        /// Handles changes to the IsVirtualToggleButton property.
        /// </summary>
        private static void OnIsVirtualToggleButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = d as IInputElement;
            if (element != null)
            {
                if ((bool)e.NewValue)
                {
                    element.AddHandler(Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(OnPrevieMouseLeftButtonDown));
                    element.PreviewKeyDown += OnPreviewKeyDown;
                }
                else
                {
                    element.RemoveHandler(Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(OnPrevieMouseLeftButtonDown));
                    element.PreviewKeyDown -= OnPreviewKeyDown;
                }
            }
        }

        #endregion

        #region SuppressKeyboard

        public static readonly DependencyProperty SuppressKeyboardProperty =
            DependencyProperty.RegisterAttached("SuppressKeyboard", typeof(bool), typeof(VirtualToggleButton),
                                                new FrameworkPropertyMetadata(false));

        public static bool GetSuppressKeyboard(DependencyObject d)
        {
            return (bool)d.GetValue(SuppressKeyboardProperty);
        }

        public static void SetSuppressKeyboard(DependencyObject d, bool value)
        {
            d.SetValue(SuppressKeyboardProperty, value);
        }

        #endregion

        #region SuppressMouse

        public static readonly DependencyProperty SuppressMouseProperty =
            DependencyProperty.RegisterAttached("SuppressMouse", typeof(bool), typeof(VirtualToggleButton),
                                                new FrameworkPropertyMetadata(false));

        public static bool GetSuppressMouse(DependencyObject d)
        {
            return (bool)d.GetValue(SuppressMouseProperty);
        }

        public static void SetSuppressMouse(DependencyObject d, bool value)
        {
            d.SetValue(SuppressKeyboardProperty, value);
        }

        #endregion

        #region IsToggledByMouse

        public static readonly DependencyProperty IsToggledByMouseProperty =
            DependencyProperty.RegisterAttached("IsToggledByMouse", typeof(bool), typeof(VirtualToggleButton),
                                                new FrameworkPropertyMetadata(true));

        public static bool GetIsToggledByMouse(DependencyObject d)
        {
            return (bool)d.GetValue(IsToggledByMouseProperty);
        }

        public static void SetIsToggledByMouse(DependencyObject d, bool value)
        {
            d.SetValue(IsToggledByMouseProperty, value);
        }

        #endregion

        #region IsToogledByKeyboard

        public static readonly DependencyProperty IsToggledByKeyboardProperty =
            DependencyProperty.RegisterAttached("IsToggledByKeyboard", typeof(bool), typeof(VirtualToggleButton),
                                                new FrameworkPropertyMetadata(true));

        public static bool GetIsToggledByKeyboard(DependencyObject d)
        {
            return (bool)d.GetValue(IsToggledByKeyboardProperty);
        }

        public static void SetIsToggledByKeyboard(DependencyObject d, bool value)
        {
            d.SetValue(IsToggledByKeyboardProperty, value);
        }

        #endregion

        #endregion

        #region routed events

        #region Checked

        internal static RoutedEventArgs RaiseCheckedEvent(UIElement target)
        {
            if (target == null)
                return null;

            var args = new RoutedEventArgs { RoutedEvent = ToggleButton.CheckedEvent };
            RaiseEvent(target, args);
            return args;
        }

        #endregion

        #region Unchecked

        /// <summary>
        /// A static helper method to raise the Unchecked event on a target element.
        /// </summary>
        /// <param name="target">UIElement or ContentElement on which to raise the event</param>
        internal static RoutedEventArgs RaiseUncheckedEvent(UIElement target)
        {
            if (target == null) return null;

            RoutedEventArgs args = new RoutedEventArgs();
            args.RoutedEvent = ToggleButton.UncheckedEvent;
            RaiseEvent(target, args);
            return args;
        }

        #endregion

        #region Indeterminate

        /// <summary>
        /// A static helper method to raise the Indeterminate event on a target element.
        /// </summary>
        /// <param name="target">UIElement or ContentElement on which to raise the event</param>
        internal static RoutedEventArgs RaiseIndeterminateEvent(UIElement target)
        {
            if (target == null) return null;

            RoutedEventArgs args = new RoutedEventArgs();
            args.RoutedEvent = ToggleButton.IndeterminateEvent;
            RaiseEvent(target, args);
            return args;
        }

        #endregion

        #endregion

        #region private methods

        private static void OnPrevieMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Looking for the logically closest (up in elements tree) element
            // Like a bubble in a tunneling event
            var senderType = sender.GetType();
            var depObj = e.OriginalSource as DependencyObject;
            while (depObj != null && depObj.GetType() != senderType)
                depObj = VisualTreeHelper.GetParent(depObj);

            if (depObj != sender)
                return;

            if (e.ChangedButton == MouseButton.Left && e.LeftButton == MouseButtonState.Pressed)
            {
                var dob = sender as DependencyObject;
                var suppress = dob != null && GetSuppressMouse(dob);
                e.Handled = suppress;

                if (!GetIsToggledByMouse(depObj))
                    return;

                UpdateIsChecked(sender as DependencyObject);
            }
        }

        private static void OnPreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key != Key.Space && e.Key != Key.Enter )
                return;

            var senderType = sender.GetType();
            var p = e.OriginalSource as DependencyObject;
            while (p != null && p.GetType() != senderType)
                p = VisualTreeHelper.GetParent(p);

            if (p != sender)
                return;

            var dob = sender as DependencyObject;
            var suppress = dob != null && GetSuppressKeyboard(dob);

            if (e.Key == Key.Space)
            {
                // ignore alt+space which invokes the system menu
                if ((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt)
                    return;

                UpdateIsChecked(sender as DependencyObject);
                e.Handled = suppress;
            }
            else if (e.Key == Key.Enter && (bool)(sender as DependencyObject).GetValue(KeyboardNavigation.AcceptsReturnProperty))
            {
                UpdateIsChecked(sender as DependencyObject);
                e.Handled = suppress;
            }

        }

        private static void UpdateIsChecked(DependencyObject d)
        {
            Nullable<bool> isChecked = GetIsChecked(d);
            if (isChecked == true)
            {
                SetIsChecked(d, GetIsThreeState(d) ? (Nullable<bool>)null : (Nullable<bool>)false);
            }
            else
            {
                SetIsChecked(d, isChecked.HasValue);
            }
        }

        private static void RaiseEvent(DependencyObject target, RoutedEventArgs args)
        {
            if (target is UIElement)
            {
                (target as UIElement).RaiseEvent(args);
            }
            else if (target is ContentElement)
            {
                (target as ContentElement).RaiseEvent(args);
            }
        }

        #endregion
    }