本文共 11629 字,大约阅读时间需要 38 分钟。
RelativeSource实现标记扩展,以描述绑定源相对于绑定目标的位置。
- or
// Summary: // Describes the location of the binding source relative to the position of // the binding target. public enum RelativeSourceMode { // Summary: // Allows you to bind the previous data item (not that control that contains // the data item) in the list of data items being displayed. PreviousData = 0, // // Summary: // Refers to the element to which the template (in which the data-bound element // exists) is applied. This is similar to setting a System.Windows.TemplateBindingExtension // and is only applicable if the System.Windows.Data.Binding is within a template. TemplatedParent = 1, // // Summary: // Refers to the element on which you are setting the binding and allows you // to bind one property of that element to another property on the same element. Self = 2, // // Summary: // Refers to the ancestor in the parent chain of the data-bound element. You // can use this to bind to an ancestor of a specific type or its subclasses. // This is the mode you use if you want to specify System.Windows.Data.RelativeSource.AncestorType // and/or System.Windows.Data.RelativeSource.AncestorLevel. FindAncestor = 3, }
Xaml 示例
RelativeSource内部实现
using System;using System.ComponentModel;using System.Windows.Markup;namespace System.Windows.Data{ public class RelativeSource : MarkupExtension, ISupportInitialize { public RelativeSource(); public RelativeSource(RelativeSourceMode mode); public RelativeSource(RelativeSourceMode mode, Type ancestorType, int ancestorLevel); public Type AncestorType { get; set; } public RelativeSourceMode Mode { get; set; } public static RelativeSource PreviousData { get; } public static RelativeSource Self { get; } public static RelativeSource TemplatedParent { get; } public override object ProvideValue(IServiceProvider serviceProvider); ... }}
using System;using System.ComponentModel;using System.Windows.Markup; namespace System.Windows.Data{ ///Implements a markup extension that describes the location of the binding source relative to the position of the binding target. [MarkupExtensionReturnType(typeof(RelativeSource))] public class RelativeSource : MarkupExtension, ISupportInitialize { private RelativeSourceMode _mode; private Type _ancestorType; private int _ancestorLevel = -1; private static RelativeSource s_previousData; private static RelativeSource s_templatedParent; private static RelativeSource s_self; ///Gets a static value that is used to return a ///constructed for the mode. A static public static RelativeSource PreviousData { get { if (RelativeSource.s_previousData == null) { RelativeSource.s_previousData = new RelativeSource(RelativeSourceMode.PreviousData); } return RelativeSource.s_previousData; } } ///. Gets a static value that is used to return a ///constructed for the mode. A static public static RelativeSource TemplatedParent { get { if (RelativeSource.s_templatedParent == null) { RelativeSource.s_templatedParent = new RelativeSource(RelativeSourceMode.TemplatedParent); } return RelativeSource.s_templatedParent; } } ///. Gets a static value that is used to return a ///constructed for the mode. A static public static RelativeSource Self { get { if (RelativeSource.s_self == null) { RelativeSource.s_self = new RelativeSource(RelativeSourceMode.Self); } return RelativeSource.s_self; } } ///. Gets or sets a ///value that describes the location of the binding source relative to the position of the binding target. One of the ///values. The default value is null. This property is immutable after initialization. Instead of changing the [ConstructorArgument("mode")] public RelativeSourceMode Mode {get { return this._mode; } set { if (this.IsUninitialized) { this.InitializeMode(value); return; } if (value != this._mode) { throw new InvalidOperationException(SR.Get("RelativeSourceModeIsImmutable")); } } } ///on this instance, create a new or use a different static instance. Gets or sets the type of ancestor to look for. ///The type of ancestor. The default value is null. ///The public Type AncestorType {get { return this._ancestorType; } set { if (this.IsUninitialized) { this.AncestorLevel = 1; } if (this._mode != RelativeSourceMode.FindAncestor) { if (value != null) { throw new InvalidOperationException(SR.Get("RelativeSourceNotInFindAncestorMode")); } } else { this._ancestorType = value; } } } ///is not in the mode. Gets or sets the level of ancestor to look for, in ///mode. Use 1 to indicate the one nearest to the binding target element. The ancestor level. Use 1 to indicate the one nearest to the binding target element. public int AncestorLevel {get { return this._ancestorLevel; } set { if (this._mode != RelativeSourceMode.FindAncestor) { if (value != 0) { throw new InvalidOperationException(SR.Get("RelativeSourceNotInFindAncestorMode")); } } else { if (value < 1) { throw new ArgumentOutOfRangeException(SR.Get("RelativeSourceInvalidAncestorLevel")); } this._ancestorLevel = value; } } } private bool IsUninitialized { get { return this._ancestorLevel == -1; } } ///Initializes a new instance of the public RelativeSource() { this._mode = RelativeSourceMode.FindAncestor; } ///class. Initializes a new instance of the /// One of theclass with an initial mode. values. public RelativeSource(RelativeSourceMode mode) { this.InitializeMode(mode); } /// Initializes a new instance of the /// One of theclass with an initial mode and additional tree-walking qualifiers for finding the desired relative source. values. For this signature to be relevant, this should be . /// The of ancestor to look for. /// The ordinal position of the desired ancestor among all ancestors of the given type. public RelativeSource(RelativeSourceMode mode, Type ancestorType, int ancestorLevel) { this.InitializeMode(mode); this.AncestorType = ancestorType; this.AncestorLevel = ancestorLevel; } /// This member supports the Windows Presentation Foundation (WPF) infrastructure and is not intended to be used directly from your code. void ISupportInitialize.BeginInit() { } ///This member supports the Windows Presentation Foundation (WPF) infrastructure and is not intended to be used directly from your code. void ISupportInitialize.EndInit() { if (this.IsUninitialized) { throw new InvalidOperationException(SR.Get("RelativeSourceNeedsMode")); } if (this._mode == RelativeSourceMode.FindAncestor && this.AncestorType == null) { throw new InvalidOperationException(SR.Get("RelativeSourceNeedsAncestorType")); } } ///Indicates whether the ///property should be persisted. true if the property value has changed from its default; otherwise, false. public bool ShouldSerializeAncestorType() { return this._mode == RelativeSourceMode.FindAncestor; } ///Indicates whether the ///property should be persisted. true if the property value has changed from its default; otherwise, false. public bool ShouldSerializeAncestorLevel() { return this._mode == RelativeSourceMode.FindAncestor; } ///Returns an object that should be set as the value on the target object's property for this markup extension. For ///, this is another , using the appropriate source for the specified mode. Another /// An object that can provide services for the markup extension. In this implementation, this parameter can be null. public override object ProvideValue(IServiceProvider serviceProvider) { if (this._mode == RelativeSourceMode.PreviousData) { return RelativeSource.PreviousData; } if (this._mode == RelativeSourceMode.Self) { return RelativeSource.Self; } if (this._mode == RelativeSourceMode.TemplatedParent) { return RelativeSource.TemplatedParent; } return this; } private void InitializeMode(RelativeSourceMode mode) { if (mode == RelativeSourceMode.FindAncestor) { this._ancestorLevel = 1; this._mode = mode; return; } if (mode == RelativeSourceMode.PreviousData || mode == RelativeSourceMode.Self || mode == RelativeSourceMode.TemplatedParent) { this._ancestorLevel = 0; this._mode = mode; return; } throw new ArgumentException(SR.Get("RelativeSourceModeInvalid"), "mode"); } }}.
转载地址:http://ywbql.baihongyu.com/