NickLi

导航

剖析WPF Control 类(一)

1. Declare the class
/// <summary> 
///     The base class for all controls.
/// </summary>
public class Control : FrameworkElement
{
}
 
2. Constructors
#region Constructors
// 静态构造函数
static Control()
{
// 处理和焦点相关
FocusableProperty.OverrideMetadata(typeof(Control),
new FrameworkPropertyMetadata(BooleanBoxes.TrueBox)); 
// 注册鼠标左键双击前事件
EventManager.RegisterClassHandler(typeof(Control), UIElement.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(HandleDoubleClick), true);
 
// 注册鼠标左键双击事件
EventManager.RegisterClassHandler(typeof(Control), UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(HandleDoubleClick), true);
 
// 注册鼠标右键双击前事件
EventManager.RegisterClassHandler(typeof(Control), UIElement.PreviewMouseRightButtonDownEvent, new MouseButtonEventHandler(HandleDoubleClick), true);
 
// 注册鼠标右键双击事件
EventManager.RegisterClassHandler(typeof(Control), UIElement.MouseRightButtonDownEvent, new MouseButtonEventHandler(HandleDoubleClick), true);
 
// change handlers to update validation visual state
// ???
IsKeyboardFocusedPropertyKey.OverrideMetadata(typeof(Control), new PropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged)));
}    
 
/// <summary>
///     Default Control constructor
/// </summary>
/// <remarks>
///     Automatic determination of current Dispatcher.
///     Use alternative constructor 
///     that accepts a Dispatcher for best performance.
/// </remarks>
public Control() : base()
{
// 触发TemplateChanged
// Initialize the _templateCache to the default value for TemplateProperty.
// If the default value is non-null then wire it to the current instance.
// PropertyMetadata: 定义依赖项对象在应用于特定类型(包括该属性向其注册的条件)
// 时行为的某些方面。
// TemplateProperty: Template 依赖项属性
// GetMetadata(DependencyObjectType): 为此依赖项属性(当它位于指定类型上时)返回元数据
PropertyMetadata metadata = TemplateProperty.GetMetadata(DependencyObjectType); 
ControlTemplate defaultValue = (ControlTemplate) metadata.DefaultValue;
if (defaultValue != null)
{
OnTemplateChanged(this, new DependencyPropertyChangedEventArgs(TemplateProperty, metadata, null, defaultValue));
}
}

#endregion Constructors
 
#region Properties
// 定义了15个属性
/// <summary> 
///     The DependencyProperty for the BorderBrush property.
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty BorderBrushProperty
                = Border.BorderBrushProperty.AddOwner(typeof(Control),
                    new FrameworkPropertyMetadata(
                        Border.BorderBrushProperty.DefaultMetadata.DefaultValue,
                        FrameworkPropertyMetadataOptions.None));
 
/// <summary>
///     An object that describes the border background.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 1.获取或设置一个用于描述控件的边框背景的画笔。
[Bindable(true), Category("Appearance")]
public Brush BorderBrush
{
get { return (Brush) GetValue(BorderBrushProperty); }
set { SetValue(BorderBrushProperty, value); }
}
***************************************************************
/// <summary>
///     The DependencyProperty for the BorderThickness property.
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty BorderThicknessProperty
                = Border.BorderThicknessProperty.AddOwner(typeof(Control),
                    new FrameworkPropertyMetadata(
                        Border.BorderThicknessProperty.DefaultMetadata.DefaultValue,
                        FrameworkPropertyMetadataOptions.None));

/// <summary>
///     An object that describes the border thickness.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 2.获取或设置控件的边框宽度。
[Bindable(true), Category("Appearance")]
public Thickness BorderThickness
{
get { return (Thickness) GetValue(BorderThicknessProperty); }
set { SetValue(BorderThicknessProperty, value); }
}
***************************************************************
/// <summary> 
///     The DependencyProperty for the Background property.
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty BackgroundProperty =
                Panel.BackgroundProperty.AddOwner(typeof(Control),
                    new FrameworkPropertyMetadata(
                        Panel.BackgroundProperty.DefaultMetadata.DefaultValue,
                        FrameworkPropertyMetadataOptions.None));
/// <summary>
///     An object that describes the background.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 3.获取或设置一个用于描述控件背景的画笔。
[Bindable(true), Category("Appearance")]
public Brush Background
{
get { return (Brush) GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}

********************************************************

/// <summary>
///     The DependencyProperty for the Foreground property.
///     Flags:              Can be used in style rules
///     Default Value:      System Font Color
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty ForegroundProperty =
                TextElement.ForegroundProperty.AddOwner(
                        typeof(Control),
                        new FrameworkPropertyMetadata(SystemColors.ControlTextBrush,
                            FrameworkPropertyMetadataOptions.Inherits));
 
/// <summary>
///     An brush that describes the foreground color.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 4.获取或设置一个用于描述前景色的画笔。
[Bindable(true), Category("Appearance")]
public Brush Foreground
{
get { return (Brush) GetValue(ForegroundProperty); }
set { SetValue(ForegroundProperty, value); }
}

********************************************************

/// <summary>
///     The DependencyProperty for the FontFamily property.
///     Flags:              Can be used in style rules
///     Default Value:      System Dialog Font
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty FontFamilyProperty =
                TextElement.FontFamilyProperty.AddOwner(
                        typeof(Control),
                        new FrameworkPropertyMetadata(SystemFonts.MessageFontFamily,
                            FrameworkPropertyMetadataOptions.Inherits));

/// <summary>
///     The font family of the desired font.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 5.获取或设置控件的字体系列。
[Bindable(true), Category("Appearance")]
[Localizability(LocalizationCategory.Font)]
public FontFamily FontFamily
{
get { return (FontFamily) GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); }
}
***************************************************************
/// <summary> 
///     The DependencyProperty for the FontSize property.
///     Flags:              Can be used in style rules
///     Default Value:      System Dialog Font Size
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty FontSizeProperty =
                TextElement.FontSizeProperty.AddOwner(
                        typeof(Control),
                        new FrameworkPropertyMetadata(SystemFonts.MessageFontSize,
                            FrameworkPropertyMetadataOptions.Inherits));

/// <summary>
///     The size of the desired font.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 6.获取或设置字号。
// px(默认值)表示与设备无关的单位(每个单位 1/96 英寸)
// in 表示英寸;1in==96px
// cm 表示厘米;1cm==(96/2.54) px
// pt 表示磅;1pt==(96/72) px
// 注意:在很多情况下,double 可能会设置为“Auto”,
// 但如果设置为“Auto”,Control.FontSize 将不会呈现。
[TypeConverter(typeof(FontSizeConverter))]
[Bindable(true), Category("Appearance")]
[Localizability(LocalizationCategory.None)]
public double FontSize
{
    get { return (double) GetValue(FontSizeProperty); }
    set { SetValue(FontSizeProperty, value); }
}
***************************************************************
/// <summary>
///     The DependencyProperty for the FontStretch property.
///     Flags:              Can be used in style rules
///     Default Value:      FontStretches.Normal
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty FontStretchProperty
            = TextElement.FontStretchProperty.AddOwner(typeof(Control),
                    new FrameworkPropertyMetadata(TextElement.FontStretchProperty.DefaultMetadata.DefaultValue,
                        FrameworkPropertyMetadataOptions.Inherits));
 
/// <summary>
///     The stretch of the desired font.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 7.获取或设置字体在屏幕上的压缩或扩展程度。
[Bindable(true), Category("Appearance")]
public FontStretch FontStretch
{
get { return (FontStretch) GetValue(FontStretchProperty); }
set { SetValue(FontStretchProperty, value); }
}
**************************************************************
/// <summary>
///     The DependencyProperty for the FontStyle property.
///     Flags:              Can be used in style rules
///     Default Value:      System Dialog Font Style
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty FontStyleProperty =
                TextElement.FontStyleProperty.AddOwner(
                        typeof(Control),
                        new FrameworkPropertyMetadata(SystemFonts.MessageFontStyle,
                            FrameworkPropertyMetadataOptions.Inherits));

/// <summary>
///     The style of the desired font.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 8.获取或设置字体样式。
[Bindable(true), Category("Appearance")]
public FontStyle FontStyle
{
get { return (FontStyle) GetValue(FontStyleProperty); }
set { SetValue(FontStyleProperty, value); }
}
***************************************************************
/// <summary> 
///     The DependencyProperty for the FontWeight property.
///     Flags:              Can be used in style rules
///     Default Value:      System Dialog Font Weight
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty FontWeightProperty =
                TextElement.FontWeightProperty.AddOwner(
                        typeof(Control),
                        new FrameworkPropertyMetadata(SystemFonts.MessageFontWeight,
                            FrameworkPropertyMetadataOptions.Inherits));
 
/// <summary>
///     The weight or thickness of the desired font.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 9.获取或设置指定字体的粗细。
[Bindable(true), Category("Appearance")]
public FontWeight FontWeight
{
get { return (FontWeight) GetValue(FontWeightProperty); }
set { SetValue(FontWeightProperty, value); }
}
***************************************************************
/// <summary> 
/// HorizontalContentAlignment Dependency Property.
///     Flags:              Can be used in style rules
///     Default Value:      HorizontalAlignment.Left
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty HorizontalContentAlignmentProperty =
                    DependencyProperty.Register(
                                "HorizontalContentAlignment",
                                typeof(HorizontalAlignment),
                                typeof(Control),
                                new FrameworkPropertyMetadata(HorizontalAlignment.Left),
                                new ValidateValueCallback(FrameworkElement.ValidateHorizontalAlignmentValue));

/// <summary>
///     The horizontal alignment of the control.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 10.获取或设置控件内容的水平对齐方式。
[Bindable(true), Category("Layout")]
public HorizontalAlignment HorizontalContentAlignment
{
get { return (HorizontalAlignment) GetValue(HorizontalContentAlignmentProperty); }
set { SetValue(HorizontalContentAlignmentProperty, value); }
}
***************************************************************
/// <summary>
/// VerticalContentAlignment Dependency Property.
///     Flags:              Can be used in style rules
///     Default Value:      VerticalAlignment.Top
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty VerticalContentAlignmentProperty =
                    DependencyProperty.Register(
                                "VerticalContentAlignment",
                                typeof(VerticalAlignment),
                                typeof(Control),
                                new FrameworkPropertyMetadata(VerticalAlignment.Top),
                                new ValidateValueCallback(FrameworkElement.ValidateVerticalAlignmentValue));
 
/// <summary>
///     The vertical alignment of the control.
///     This will only affect controls whose template uses the property
///     as a parameter. On other controls, the property will do nothing.
/// </summary>
// 11.Gets or sets the vertical alignment of a control's content.
// 获取或设置控件内容的垂直对齐方式。
[Bindable(true), Category("Layout")]
public VerticalAlignment VerticalContentAlignment
{
get { return (VerticalAlignment) GetValue(VerticalContentAlignmentProperty); }
set { SetValue(VerticalContentAlignmentProperty, value); }
}

********************************************************

/// <summary>
///     The DependencyProperty for the TabIndex property.
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty TabIndexProperty
                = KeyboardNavigation.TabIndexProperty.AddOwner(typeof(Control));

/// <summary>
///     TabIndex property change the order of Tab navigation between Controls.
///     Control with lower TabIndex will get focus before the Control with higher index
/// </summary>

// 12.获取或设置 HotSpot 区域的选项卡索引。
[Bindable(true), Category("Behavior")]
public int TabIndex
{
get { return (int) GetValue(TabIndexProperty); }
set { SetValue(TabIndexProperty, value); }
}

***************************************************************

/// <summary>
///     The DependencyProperty for the IsTabStop property.
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty IsTabStopProperty
                = KeyboardNavigation.IsTabStopProperty.AddOwner(typeof(Control));

/// <summary>
///     Determine is the Control should be considered during Tab navigation.
///     If IsTabStop is false then it is excluded from Tab navigation
/// </summary>

// 13.获取或设置一个值,该值指示是否将某个控件包含在 Tab 导航中。
[Bindable(true), Category("Behavior")]
public bool IsTabStop
{
    get { return (bool) GetValue(IsTabStopProperty); }
    set { SetValue(IsTabStopProperty, BooleanBoxes.Box(value)); }
}

********************************************************

/// <summary>
/// PaddingProperty
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty PaddingProperty
            = DependencyProperty.Register( "Padding",
                                        typeof(Thickness), typeof(Control),
                                        new FrameworkPropertyMetadata(
                                                new Thickness(),
                                                FrameworkPropertyMetadataOptions.AffectsParentMeasure));

/// <summary>
/// Padding Property
/// </summary>
// 14.获取或设置控件内的边距。
[Bindable(true), Category("Layout")]
public Thickness Padding
{
get { return (Thickness) GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}
***************************************************************
/// <summary>
///  TemplateProperty
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty TemplateProperty =
                DependencyProperty.Register(
                        "Template",
                        typeof(ControlTemplate),
                        typeof(Control),
                        new FrameworkPropertyMetadata(
                                (ControlTemplate) null,  // default value
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnTemplateChanged)));
 

/// <summary>
///  Template Property
/// </summary>
// 15.获取或设置控件模板。
public ControlTemplate Template
{
get { return _templateCache; }
set { SetValue(TemplateProperty, value); }
}
***************************************************************

// What purpose of these methods?
private static bool IsMarginValid(object value)
{
Thickness t = (Thickness)value;
return (t.Left >= 0.0d
            && t.Right >= 0.0d
            && t.Top >= 0.0d
            && t.Bottom >= 0.0d);
}

 

// Internal Helper so the FrameworkElement could see this property
internal override FrameworkTemplate TemplateInternal
{
get { return Template; }
}
 
// Internal Helper so the FrameworkElement could see the template cache
internal override FrameworkTemplate TemplateCache
{
get { return _templateCache; }
set { _templateCache = (ControlTemplate) value; }
}

// Internal helper so FrameworkElement could see call the template changed virtual
internal override void OnTemplateChangedInternal(FrameworkTemplate oldTemplate, FrameworkTemplate newTemplate)
{
OnTemplateChanged((ControlTemplate) oldTemplate, (ControlTemplate)newTemplate);
}

// Property invalidation callback invoked when TemplateProperty is invalidated
private static void OnTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Control c = (Control) d;
StyleHelper.UpdateTemplateCache(c, (FrameworkTemplate) e.OldValue, (FrameworkTemplate) e.NewValue, TemplateProperty);
}
 
/// <summary>
///     Template has changed
/// </summary>
/// <remarks>
///     When a Template changes, the VisualTree is removed. The new Template's
///     VisualTree will be created when ApplyTemplate is called
/// </remarks>
/// <param name="oldTemplate">The old Template</param>
/// <param name="newTemplate">The new Template</param>
protected virtual void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate)
{
}
 
/// <summary>
///     If control has a scrollviewer in its style and has a custom keyboard
///scrolling behavior when HandlesScrolling should return true.
/// Then ScrollViewer will not handle keyboard input and leave it up to the control.
/// </summary>
protected internal virtual bool HandlesScrolling
{
get { return false; }
}
 
internal bool VisualStateChangeSuspended
{
get { return ReadControlFlag(ControlBoolFlags.VisualStateChangeSuspended); }
set { WriteControlFlag(ControlBoolFlags.VisualStateChangeSuspended, value); }
}
 
#endregion Properties
 
#region Data

internal enum ControlBoolFlags : ushort
{
    // used in contentcontrol.cs
ContentIsNotLogical                 = 0x0001,    
       
    // used in ButtonBase.cs
    IsSpaceKeyDown                      = 0x0002,            
    // used in HeaderedContentControl.cs, HeaderedItemsControl.cs
    HeaderIsNotLogical                  = 0x0004,            
    // used in ButtonBase.cs, MenuItem.cs
CommandDisabled                     = 0x0008,           
    // used in contentcontrol.cs 
ContentIsItem                       = 0x0010,           
    // used in HeaderedContentControl.cs,  HeaderedItemsControl.cs
    HeaderIsItem                        = 0x0020,            
    // used in ItemsControl.cs
ScrollHostValid                     = 0x0040, 
          
    // used in TreeViewItem.cs
ContainsSelection                   = 0x0080,  
         
    // used in Control.cs 
VisualStateChangeSuspended          = 0x0100,           
} 
 
// Property caches
private ControlTemplate         _templateCache;
// Cache valid bits
internal ControlBoolFlags       _controlBoolField;  
 
#endregion Data
 
#region Events 
 
/// <summary> 
///     PreviewMouseDoubleClick event
/// </summary>
public static readonly RoutedEvent PreviewMouseDoubleClickEvent = EventManager.RegisterRoutedEvent("PreviewMouseDoubleClick", RoutingStrategy.Direct, typeof(MouseButtonEventHandler), typeof(Control));

/// <summary>
///     An event reporting a mouse button was pressed twice in a row.
/// </summary>
public event MouseButtonEventHandler PreviewMouseDoubleClick
{
add { AddHandler(PreviewMouseDoubleClickEvent, value); }
remove { RemoveHandler(PreviewMouseDoubleClickEvent, value); }
}

/// <summary>
///     An event reporting a mouse button was pressed twice in a row.
/// </summary>
/// <param name="e">Event arguments</param>
protected virtual void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
{
RaiseEvent(e);
}
 
/// <summary>
///     MouseDoubleClick event
/// </summary>
public static readonly RoutedEvent MouseDoubleClickEvent = EventManager.RegisterRoutedEvent("MouseDoubleClick", RoutingStrategy.Direct, typeof(MouseButtonEventHandler), typeof(Control));
 
/// <summary>
///     An event reporting a mouse button was pressed twice in a row.
/// </summary>
public event MouseButtonEventHandler MouseDoubleClick
{
add { AddHandler(MouseDoubleClickEvent, value); }
remove { RemoveHandler(MouseDoubleClickEvent, value); }
}
 
/// <summary>
///     An event reporting a mouse button was pressed twice in a row.
/// </summary>
/// <param name="e">Event arguments</param>
protected virtual void OnMouseDoubleClick(MouseButtonEventArgs e)
{
RaiseEvent(e);
}

// What purpose of this methods ?
private static void HandleDoubleClick(object sender, MouseButtonEventArgs e) 
{
if (e.ClickCount == 2)
{
     Control ctrl = (Control)sender;
     MouseButtonEventArgs doubleClick = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, e.ChangedButton, e.StylusDevice);
if ((e.RoutedEvent == UIElement.PreviewMouseLeftButtonDownEvent) ||
                    (e.RoutedEvent == UIElement.PreviewMouseRightButtonDownEvent))
                {
                    doubleClick.RoutedEvent = PreviewMouseDoubleClickEvent;
                    doubleClick.Source = e.OriginalSource; // Set OriginalSource because initially is null
                    doubleClick.OverrideSource(e.Source);
                    ctrl.OnPreviewMouseDoubleClick(doubleClick);
                }
                else
                {
                    doubleClick.RoutedEvent = MouseDoubleClickEvent;
                    doubleClick.Source = e.OriginalSource;
                    // Set OriginalSource because initially is null 
                    doubleClick.OverrideSource(e.Source);
                    ctrl.OnMouseDoubleClick(doubleClick);
                }

                // If MouseDoubleClick event is handled - we delegate the state to original MouseButtonEventArgs
                if (doubleClick.Handled)
                    e.Handled = true;
}
}
 
#endregion Events
 
 
 

posted on 2010-10-14 19:18  孤叶无眠  阅读(2396)  评论(0编辑  收藏  举报