Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Data / PropertyPathWorker.cs / 1483137 / PropertyPathWorker.cs
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// Description: Defines PropertyPathWorker object, workhorse for CLR bindings
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Globalization;
using System.Text;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Controls; // Validation
using System.Windows.Data;
using System.Windows.Markup;
using MS.Internal;
using MS.Internal.Hashing.PresentationFramework; // HashHelper
namespace MS.Internal.Data
{
internal sealed class PropertyPathWorker: IWeakEventListener
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
internal PropertyPathWorker(PropertyPath path)
: this(path, DataBindEngine.CurrentDataBindEngine)
{
}
internal PropertyPathWorker(PropertyPath path, ClrBindingWorker host, bool isDynamic, DataBindEngine engine)
: this(path, engine)
{
_host = host;
_isDynamic = isDynamic;
}
private PropertyPathWorker(PropertyPath path, DataBindEngine engine)
{
_parent = path;
_arySVS = new SourceValueState[path.Length];
_engine = engine;
// initialize each level to NullDataItem, so that the first real
// item will force a change
for (int i=_arySVS.Length-1; i>=0; --i)
{
_arySVS[i].item = BindingExpression.CreateReference(BindingExpression.NullDataItem);
}
}
//------------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
internal int Length { get { return _parent.Length; } }
internal PropertyPathStatus Status { get { return _status; } }
internal DependencyObject TreeContext
{
get { return BindingExpression.GetReference(_treeContext) as DependencyObject; }
set { _treeContext = BindingExpression.CreateReference(value); }
}
internal void SetTreeContext(WeakReference wr)
{
_treeContext = BindingExpression.CreateReference(wr);
}
internal bool IsDBNullValidForUpdate
{
get
{
if (!_isDBNullValidForUpdate.HasValue)
{
DetermineWhetherDBNullIsValid();
}
return _isDBNullValidForUpdate.Value;
}
}
internal object SourceItem
{
get
{
int level = Length-1;
object item = (level >= 0) ? GetItem(level) : null;
if (item == BindingExpression.NullDataItem)
{
item = null;
}
return item;
}
}
internal string SourcePropertyName
{
get
{
int level = Length-1;
if (level < 0)
return null;
switch (SVI[level].type)
{
case SourceValueType.Property:
// return the real name of the property
DependencyProperty dp;
PropertyInfo pi;
PropertyDescriptor pd;
DynamicPropertyAccessor dpa;
SetPropertyInfo(GetAccessor(level), out pi, out pd, out dp, out dpa);
return (dp != null) ? dp.Name :
(pi != null) ? pi.Name :
(pd != null) ? pd.Name :
(dpa != null) ? dpa.PropertyName : null;
case SourceValueType.Indexer:
// return the indexer string, e.g. "[foo]"
string s = _parent.Path;
int lastBracketIndex = s.LastIndexOf('[');
return s.Substring(lastBracketIndex);
}
// in all other cases, no name is available
return null;
}
}
// true when we need to register for direct notification from the RawValue,
// i.e. when it's a DO that we get to via a non-DP
internal bool NeedsDirectNotification
{
get { return _needsDirectNotification; }
private set
{
if (value)
{
_dependencySourcesChanged = true;
}
_needsDirectNotification = value;
}
}
//------------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
//------- common methods ------
internal object GetItem(int level)
{
return BindingExpression.GetReference(_arySVS[level].item);
}
internal object GetAccessor(int level)
{
return _arySVS[level].info;
}
internal object[] GetIndexerArguments(int level)
{
object[] args = _arySVS[level].args;
// unwrap the IList wrapper, if any
IListIndexerArg wrapper;
if (args != null && args.Length == 1 &&
(wrapper = args[0] as IListIndexerArg) != null)
{
return new object[] { wrapper.Value };
}
return args;
}
internal Type GetType(int level)
{
return _arySVS[level].type;
}
//------- target mode ------
// Set the context for the path. Use this method in "target" mode
// to connect the path to a rootItem for a short time:
// using (path.SetContext(myItem))
// {
// ... call target-mode convenience methods ...
// }
internal IDisposable SetContext(object rootItem)
{
if (_contextHelper == null)
_contextHelper = new ContextHelper(this);
_contextHelper.SetContext(rootItem);
return _contextHelper;
}
//------- source mode (should only be called by ClrBindingWorker) ------
internal void AttachToRootItem(object rootItem)
{
_rootItem = BindingExpression.CreateReference(rootItem);
UpdateSourceValueState(-1, null);
}
internal void DetachFromRootItem()
{
_rootItem = BindingExpression.NullDataItem;
UpdateSourceValueState(-1, null);
_rootItem = null;
}
internal object GetValue(object item, int level)
{
bool isExtendedTraceEnabled = IsExtendedTraceEnabled(TraceDataLevel.GetValue);
DependencyProperty dp;
PropertyInfo pi;
PropertyDescriptor pd;
DynamicPropertyAccessor dpa;
object value = DependencyProperty.UnsetValue;
SetPropertyInfo(_arySVS[level].info, out pi, out pd, out dp, out dpa);
switch (SVI[level].type)
{
case SourceValueType.Property:
if (pi != null)
{
value = pi.GetValue(item, null);
}
else if (pd != null)
{
bool indexerIsNext = (level+1 < SVI.Length && SVI[level+1].type == SourceValueType.Indexer);
value = Engine.GetValue(item, pd, indexerIsNext);
}
else if (dp != null)
{
DependencyObject d = (DependencyObject)item;
if (level != Length-1 || _host == null || _host.TransfersDefaultValue)
value = d.GetValue(dp);
else if (!Helper.HasDefaultValue(d, dp))
value = d.GetValue(dp);
else
value = BindingExpression.IgnoreDefaultValue;
}
else if (dpa != null)
{
value = dpa.GetValue(item);
}
break;
case SourceValueType.Indexer:
DynamicIndexerAccessor dia;
//
if (pi != null)
{
object[] args = _arySVS[level].args;
IListIndexerArg wrapper;
if (args != null && args.Length == 1 &&
(wrapper = args[0] as IListIndexerArg) != null)
{
// common special case: IList indexer. Avoid
// out-of-range exceptions.
int index = wrapper.Value;
IList ilist = (IList)item;
if (0 <= index && index < ilist.Count)
{
value = ilist[index];
}
else
{
value = IListIndexOutOfRange;
}
}
else
{
// normal case
value = pi.GetValue(item,
BindingFlags.GetProperty, null,
args,
CultureInfo.InvariantCulture);
}
}
else if ((dia = _arySVS[level].info as DynamicIndexerAccessor) != null)
{
value = dia.GetValue(item, _arySVS[level].args);
}
else
{
throw new NotSupportedException(SR.Get(SRID.IndexedPropDescNotImplemented));
}
break;
case SourceValueType.Direct:
value = item;
break;
}
if (isExtendedTraceEnabled)
{
object accessor = _arySVS[level].info;
if (accessor == DependencyProperty.UnsetValue)
accessor = null;
TraceData.Trace(TraceEventType.Warning,
TraceData.GetValue(
TraceData.Identify(_host.ParentBindingExpression),
level,
TraceData.Identify(item),
TraceData.IdentifyAccessor(accessor),
TraceData.Identify(value)));
}
return value;
}
internal void SetValue(object item, object value)
{
bool isExtendedTraceEnabled = IsExtendedTraceEnabled(TraceDataLevel.GetValue);
PropertyInfo pi;
PropertyDescriptor pd;
DependencyProperty dp;
DynamicPropertyAccessor dpa;
int level = _arySVS.Length - 1;
SetPropertyInfo(_arySVS[level].info, out pi, out pd, out dp, out dpa);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.SetValue(
TraceData.Identify(_host.ParentBindingExpression),
level,
TraceData.Identify(item),
TraceData.IdentifyAccessor(_arySVS[level].info),
TraceData.Identify(value)));
}
switch (SVI[level].type)
{
case SourceValueType.Property:
if (pd != null)
{
pd.SetValue(item, value);
}
else if (pi != null)
{
pi.SetValue(item, value, null);
}
else if (dp != null)
{
((DependencyObject)item).SetValue(dp, value);
}
else if (dpa != null)
{
dpa.SetValue(item, value);
}
break;
case SourceValueType.Indexer:
DynamicIndexerAccessor dia;
//
if (pi != null)
{
pi.SetValue(item, value,
BindingFlags.SetProperty, null,
GetIndexerArguments(level),
CultureInfo.InvariantCulture);
}
else if ((dia = _arySVS[level].info as DynamicIndexerAccessor) != null)
{
dia.SetValue(item, _arySVS[level].args, value);
}
else
{
throw new NotSupportedException(SR.Get(SRID.IndexedPropDescNotImplemented));
}
break;
}
}
internal object RawValue()
{
object rawValue = RawValue(Length-1);
if (rawValue == AsyncRequestPending)
rawValue = DependencyProperty.UnsetValue; // the real value will arrive later
return rawValue;
}
// Called by BE.UpdateTarget(). Re-fetch the value at each level.
// If there's a difference, simulate a property-change at that level.
internal void RefreshValue()
{
for (int k=1; k<_arySVS.Length; ++k)
{
object oldValue = BindingExpression.GetReference(_arySVS[k].item);
if (!Object.Equals(oldValue, RawValue(k-1)))
{
UpdateSourceValueState(k-1, null);
return;
}
}
UpdateSourceValueState(Length-1, null);
}
// return the source level where the change happened, or -1 if the
// change is irrelevant.
internal int LevelForPropertyChange(object item, string propertyName)
{
// This test must be thread-safe - it can get called on the "wrong" context.
// It's read-only (good). And if another thread changes the values it reads,
// the worst that can happen is to schedule a transfer operation needlessly -
// the operation itself won't do anything (since the test is repeated on the
// right thread).
bool isIndexer = propertyName == Binding.IndexerName;
for (int k=0; k<_arySVS.Length; ++k)
{
if (BindingExpression.GetReference(_arySVS[k].item) == item &&
(String.IsNullOrEmpty(propertyName) ||
(isIndexer && SVI[k].type == MS.Internal.Data.SourceValueType.Indexer) ||
String.Equals(SVI[k].propertyName, propertyName, StringComparison.OrdinalIgnoreCase)))
{
return k;
}
}
return -1;
}
internal void OnPropertyChangedAtLevel(int level)
{
UpdateSourceValueState(level, null);
}
internal void OnCurrentChanged(ICollectionView collectionView)
{
for (int k=0; k= 0 && SVI[level].type == SourceValueType.Property)
{
object item = GetItem(level);
IDataErrorInfo idei = item as IDataErrorInfo;
if (idei != null)
{
DependencyProperty dp;
PropertyInfo pi;
PropertyDescriptor pd;
DynamicPropertyAccessor dpa;
SetPropertyInfo(GetAccessor(level), out pi, out pd, out dp, out dpa);
string name = (dp != null) ? dp.Name :
(pi != null) ? pi.Name :
(pd != null) ? pd.Name :
(dpa != null ) ? dpa.PropertyName :
null;
string error;
if (name != null)
{
// get the data error information, if any, by calling idie[name].
// We do this in a paranoid way, even though indexers with
// string-valued arguments are not supposed to throw exceptions.
// PreSharp uses message numbers that the C# compiler doesn't know about.
// Disable the C# complaints, per the PreSharp documentation.
#pragma warning disable 1634, 1691
// PreSharp complains about catching NullReference (and other) exceptions.
// It doesn't recognize that IsCritical[Application]Exception() handles these correctly.
#pragma warning disable 56500
try
{
error = idei[name];
}
catch (Exception ex)
{
if (CriticalExceptions.IsCriticalApplicationException(ex))
throw;
error = null;
if (TraceData.IsEnabled)
{
TraceData.Trace(TraceEventType.Error,
TraceData.DataErrorInfoFailed(
name,
item.GetType().FullName,
ex.GetType().FullName,
ex.Message),
bindingExpressionBase);
}
}
#pragma warning restore 56500
#pragma warning restore 1634, 1691
}
else
{
error = null;
}
if (!String.IsNullOrEmpty(error))
{
result = new ValidationError(DataErrorValidationRule.Instance,
bindingExpressionBase,
error,
null);
}
}
}
return result;
}
//-----------------------------------------------------
//
// Private Properties
//
//------------------------------------------------------
bool IsDynamic { get { return _isDynamic; } }
SourceValueInfo[] SVI { get { return _parent.SVI; } }
DataBindEngine Engine { get { return _engine; } }
//-----------------------------------------------------
//
// Private Methods
//
//-----------------------------------------------------
// fill in the SourceValueState with updated infomation, starting at level k+1.
// If view isn't null, also update the current item at level k.
private void UpdateSourceValueState(int k, ICollectionView collectionView)
{
UpdateSourceValueState(k, collectionView, BindingExpression.NullDataItem, false);
}
// fill in the SourceValueState with updated infomation, starting at level k+1.
// If view isn't null, also update the current item at level k.
private void UpdateSourceValueState(int k, ICollectionView collectionView, object newValue, bool isASubPropertyChange)
{
// give host a chance to shut down the binding if the target has
// gone away
DependencyObject target = null;
if (_host != null)
{
target = _host.CheckTarget();
if (_rootItem != BindingExpression.NullDataItem && target == null)
return;
}
int initialLevel = k;
object rawValue = null;
// optimistically assume the new value will fix previous path errors
_status = PropertyPathStatus.Active;
// prepare to collect changes to dependency sources
_dependencySourcesChanged = false;
// Update the current item at level k, if requested
if (collectionView != null)
{
Debug.Assert(0<=k && k<_arySVS.Length && _arySVS[k].collectionView == collectionView, "bad parameters to UpdateSourceValueState");
ReplaceItem(k, collectionView.CurrentItem, NoParent);
}
// update the remaining levels
for (++k; k<_arySVS.Length; ++k)
{
isASubPropertyChange = false; // sub-property changes only matter at the last level
ICollectionView oldCollectionView = _arySVS[k].collectionView;
// replace the item at level k using parent from level k-1
rawValue = (newValue == BindingExpression.NullDataItem) ? RawValue(k-1) : newValue;
newValue = BindingExpression.NullDataItem;
if (rawValue == AsyncRequestPending)
{
_status = PropertyPathStatus.AsyncRequestPending;
break; // we'll resume the loop after the request completes
}
ReplaceItem(k, BindingExpression.NullDataItem, rawValue);
// replace view, if necessary
ICollectionView newCollectionView = _arySVS[k].collectionView;
if (oldCollectionView != newCollectionView && _host != null)
{
_host.ReplaceCurrentItem(oldCollectionView, newCollectionView);
}
}
// notify binding about what happened
if (_host != null)
{
if (initialLevel < _arySVS.Length)
{
// when something in the path changes, recompute whether we
// need direct notifications from the raw value
NeedsDirectNotification = _status == PropertyPathStatus.Active &&
_arySVS.Length > 0 &&
SVI[_arySVS.Length-1].type != SourceValueType.Direct &&
!(_arySVS[_arySVS.Length-1].info is DependencyProperty) &&
typeof(DependencyObject).IsAssignableFrom(_arySVS[_arySVS.Length-1].type);
}
_host.NewValueAvailable(_dependencySourcesChanged, initialLevel < 0, isASubPropertyChange);
}
GC.KeepAlive(target); // keep target alive during changes (bug 956831)
}
// replace the item at level k with the given item, or with an item obtained from the given parent
private void ReplaceItem(int k, object newO, object parent)
{
bool isExtendedTraceEnabled = IsExtendedTraceEnabled(TraceDataLevel.ReplaceItem);
SourceValueState svs = new SourceValueState();
object oldO = BindingExpression.GetReference(_arySVS[k].item);
// stop listening to old item
if (IsDynamic && SVI[k].type != SourceValueType.Direct)
{
INotifyPropertyChanged oldPC = oldO as INotifyPropertyChanged;
if (oldPC != null)
{
PropertyChangedEventManager.RemoveListener(oldPC, this, SVI[k].propertyName);
}
else
{
PropertyDescriptor oldDesc = _arySVS[k].info as PropertyDescriptor;
if (oldDesc != null && oldO != null && oldO != BindingExpression.NullDataItem)
{
ValueChangedEventManager.RemoveListener(oldO, this, oldDesc);
}
}
DependencyProperty dp = _arySVS[k].info as DependencyProperty;
if (dp != null)
{
_dependencySourcesChanged = true;
}
}
// clear the IsDBNullValid cache
_isDBNullValidForUpdate = null;
if (newO == null ||
parent == DependencyProperty.UnsetValue ||
parent == BindingExpression.NullDataItem ||
parent == BindingExpressionBase.DisconnectedItem)
{
_arySVS[k].item = BindingExpression.ReplaceReference(_arySVS[k].item, newO);
if (parent == DependencyProperty.UnsetValue ||
parent == BindingExpression.NullDataItem ||
parent == BindingExpressionBase.DisconnectedItem)
{
_arySVS[k].collectionView = null;
}
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.ReplaceItemShort(
TraceData.Identify(_host.ParentBindingExpression),
k,
TraceData.Identify(newO)));
}
return;
}
// obtain the new item and its access info
if (newO != BindingExpression.NullDataItem)
{
parent = newO; // used by error reporting
GetInfo(k, newO, ref svs);
svs.collectionView = _arySVS[k].collectionView;
}
else
{
// Note: if we want to support binding to HasValue and/or Value
// properties of nullable types, we need a way to find out if
// the rawvalue is Nullable and pass that information here.
DrillIn drillIn = SVI[k].drillIn;
ICollectionView view = null;
// first look for info on the parent
if (drillIn != DrillIn.Always)
{
GetInfo(k, parent, ref svs);
}
// if that fails, look for information on the view itself
if (svs.info == null)
{
view = CollectionViewSource.GetDefaultCollectionView(parent, TreeContext);
if (view != null && drillIn != DrillIn.Always)
{
if (view != parent) // don't duplicate work
GetInfo(k, view, ref svs);
}
}
// if that fails, drill in to the current item
if (svs.info == null && drillIn != DrillIn.Never && view != null)
{
newO = view.CurrentItem;
if (newO != null)
{
GetInfo(k, newO, ref svs);
svs.collectionView = view;
}
else
{
// no current item: use previous info (if known)
svs = _arySVS[k];
svs.collectionView = view;
// if there's no current item because parent is an empty
// XmlDataCollection, treat it as a path error (the XPath
// didn't return any nodes)
if (!IsEmptyXmlDataCollection(parent))
{
// otherwise it's not an error - currency is simply
// off the collection
svs.item = BindingExpression.ReplaceReference(svs.item, BindingExpression.NullDataItem);
if (svs.info == null)
svs.info = DependencyProperty.UnsetValue;
}
}
}
}
// update info about new item
if (svs.info == null)
{
svs.item = BindingExpression.ReplaceReference(svs.item, BindingExpression.NullDataItem);
_arySVS[k] = svs;
_status = PropertyPathStatus.PathError;
ReportNoInfoError(k, parent);
return;
}
_arySVS[k] = svs;
newO = BindingExpression.GetReference(svs.item);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.ReplaceItemLong(
TraceData.Identify(_host.ParentBindingExpression),
k,
TraceData.Identify(newO),
TraceData.IdentifyAccessor(svs.info)));
}
// start listening to new item
if (IsDynamic && SVI[k].type != SourceValueType.Direct)
{
Engine.RegisterForCacheChanges(newO, svs.info);
INotifyPropertyChanged newPC = newO as INotifyPropertyChanged;
if (newPC != null)
{
PropertyChangedEventManager.AddListener(newPC, this, SVI[k].propertyName);
}
else
{
PropertyDescriptor newDesc = svs.info as PropertyDescriptor;
if (newDesc != null && newO != null)
ValueChangedEventManager.AddListener(newO, this, newDesc);
}
}
// at the last level, set up the default transformer
if (_host != null && k == Length-1)
{
_host.SetupDefaultValueConverter(svs.type);
// also, check for request to update a read-only property
if (_host.IsReflective)
{
CheckReadOnly(newO, svs.info);
}
}
}
void ReportNoInfoError(int k, object parent)
{
// report cannot find info. Ignore when in priority bindings.
if (TraceData.IsEnabled)
{
BindingExpression bindingExpression = (_host != null) ? _host.ParentBindingExpression : null;
if (bindingExpression == null || !bindingExpression.IsInPriorityBindingExpression)
{
if (!IsEmptyXmlDataCollection(parent))
{
SourceValueInfo svi = SVI[k];
string cs = (svi.type != SourceValueType.Indexer) ? svi.name : "[" + svi.name + "]";
string ps = TraceData.DescribeSourceObject(parent);
string os = (svi.drillIn == DrillIn.Always) ? "current item of collection" : "object";
// if the parent is null, the path error probably only means the
// data provider hasn't produced any data yet. When it does,
// the binding will try again and probably succeed. Give milder
// feedback for this special case, so as not to alarm users unduly.
if (parent == null)
{
TraceData.Trace(TraceEventType.Information, TraceData.NullItem(cs, os), bindingExpression);
}
// Similarly, if the parent is the NewItemPlaceholder.
else if (parent == CollectionView.NewItemPlaceholder ||
parent == DataGrid.NewItemPlaceholder)
{
TraceData.Trace(TraceEventType.Information, TraceData.PlaceholderItem(cs, os), bindingExpression);
}
else
{
TraceEventType traceType = (bindingExpression != null) ? bindingExpression.TraceLevel : TraceEventType.Error;
TraceData.Trace(traceType, TraceData.ClrReplaceItem(cs, ps, os), bindingExpression);
}
}
else
{
TraceEventType traceType = (bindingExpression != null) ? bindingExpression.TraceLevel : TraceEventType.Error;
_host.ReportBadXPath(traceType);
}
}
}
}
// determine if the cached state of the path is still correct. This is
// used to deduce whether event leapfrogging has occurred along the path
// (i.e. something changed, but we haven't yet received the notification)
internal bool IsPathCurrent(object rootItem)
{
if (Status != PropertyPathStatus.Active)
return false;
object item = rootItem;
for (int level=0, n=Length; level 0 : false;
}
// look for property/indexer on the given item
private void GetInfo(int k, object item, ref SourceValueState svs)
{
#if DEBUG
bool checkCacheResult = false;
#endif
object oldItem = BindingExpression.GetReference(_arySVS[k].item);
bool isExtendedTraceEnabled = IsExtendedTraceEnabled(TraceDataLevel.GetInfo);
// optimization - only change info if the type changed
// exception - if the info is a PropertyDescriptor, it might depend
// on the item itself (not just the type), so we have to re-fetch
Type oldType = (oldItem != null) ? oldItem.GetType() : null;
Type newType = (item != null) ? item.GetType() : null;
Type sourceType = null;
if (newType == oldType && oldItem != BindingExpression.NullDataItem &&
!(_arySVS[k].info is PropertyDescriptor))
{
svs = _arySVS[k];
svs.item = BindingExpression.ReplaceReference(svs.item, item);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GetInfo_Reuse(
TraceData.Identify(_host.ParentBindingExpression),
k,
TraceData.IdentifyAccessor(svs.info)));
}
return;
}
// if the new item is null, we won't find a property/indexer on it
if (newType == null && SVI[k].type != SourceValueType.Direct)
{
svs.info = null;
svs.args = null;
svs.type = null;
svs.item = BindingExpression.ReplaceReference(svs.item, item);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GetInfo_Null(
TraceData.Identify(_host.ParentBindingExpression),
k));
}
return;
}
// optimization - see if we've cached the answer
int index;
bool cacheAccessor = !PropertyPath.IsParameterIndex(SVI[k].name, out index);
if (cacheAccessor)
{
AccessorInfo accessorInfo = Engine.AccessorTable[SVI[k].type, newType, SVI[k].name];
if (accessorInfo != null)
{
svs.info = accessorInfo.Accessor;
svs.type = accessorInfo.PropertyType;
svs.args = accessorInfo.Args;
svs.item = BindingExpression.ReplaceReference(svs.item, item);
if (IsDynamic && SVI[k].type == SourceValueType.Property && svs.info is DependencyProperty)
{
_dependencySourcesChanged = true;
}
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GetInfo_Cache(
TraceData.Identify(_host.ParentBindingExpression),
k,
newType.Name,
SVI[k].name,
TraceData.IdentifyAccessor(svs.info)));
}
#if DEBUG // compute the answer the old-fashioned way, and compare
checkCacheResult = true;
#else
return;
#endif
}
}
object info = null;
object[] args = null;
switch (SVI[k].type)
{
case SourceValueType.Property:
info = _parent.ResolvePropertyName(k, item, newType, TreeContext);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GetInfo_Property(
TraceData.Identify(_host.ParentBindingExpression),
k,
newType.Name,
SVI[k].name,
TraceData.IdentifyAccessor(info)));
}
DependencyProperty dp;
PropertyInfo pi1;
PropertyDescriptor pd;
DynamicObjectAccessor doa;
PropertyPath.DowncastAccessor(info, out dp, out pi1, out pd, out doa);
if (dp != null)
{
sourceType = dp.PropertyType;
if (IsDynamic)
{
#if DEBUG
if (checkCacheResult)
Debug.Assert(_dependencySourcesChanged, "Cached accessor didn't change sources");
#endif
_dependencySourcesChanged = true;
}
break;
}
else if (pi1 != null)
{
sourceType = pi1.PropertyType;
}
else if (pd != null)
{
sourceType = pd.PropertyType;
}
else if (doa != null)
{
sourceType = doa.PropertyType;
#if DEBUG
checkCacheResult = false; // not relevant for dynamic objects
#endif
}
break;
case SourceValueType.Indexer:
IndexerParameterInfo[] aryInfo = _parent.ResolveIndexerParams(k, TreeContext);
// Check if we should treat the indexer as a property instead.
// (See ShouldConvertIndexerToProperty for why we might do that.)
if (aryInfo.Length == 1 &&
(aryInfo[0].type == null || aryInfo[0].type == typeof(string)))
{
string name = (string)aryInfo[0].value;
if (ShouldConvertIndexerToProperty(item, ref name))
{
_parent.ReplaceIndexerByProperty(k, name);
goto case SourceValueType.Property;
}
}
args = new object[aryInfo.Length];
// find the matching indexer
MemberInfo[][] aryMembers= new MemberInfo[][]{ newType.GetDefaultMembers(), null };
bool isIList = (item is IList);
if (isIList)
aryMembers[1] = typeof(IList).GetDefaultMembers();
for (int ii=0; info==null && ii 0)
{
Debug.Assert(false,
String.Format("Accessor cache returned incorrect result for ({0},{1},{2})\n{3}",
SVI[k].type, newType.Name, SVI[k].name, sb.ToString()));
}
return;
}
#endif
svs.info = info;
svs.args = args;
svs.type = sourceType;
svs.item = BindingExpression.ReplaceReference(svs.item, item);
// cache the answer, to avoid doing all that reflection again
// (but not if the answer is a PropertyDescriptor,
// since then the answer potentially depends on the item itself)
if (cacheAccessor && info != null && !(info is PropertyDescriptor))
{
Engine.AccessorTable[SVI[k].type, newType, SVI[k].name] =
new AccessorInfo(info, sourceType, args);
}
}
// convert the (string) argument names to types appropriate for use with
// the given property. Put the results in the args[] array. Return
// true if everything works.
private bool MatchIndexerParameters(ParameterInfo[] aryPI, IndexerParameterInfo[] aryInfo, object[] args, bool isIList)
{
// must have the right number of parameters
if (aryPI != null && aryPI.Length != aryInfo.Length)
return false;
// each parameter must be settable from user-specified type or from a string
for (int i=0; i= _arySVS.Length)
return DependencyProperty.UnsetValue;
object item = BindingExpression.GetReference(_arySVS[k].item);
object info = _arySVS[k].info;
// try to get the value, unless (a) binding is being detached,
// (b) no info - e.g. Nullable with no value, or (c) item expected
// but not present - e.g. currency moved off the end.
if (item != BindingExpression.NullDataItem && info != null && !(item == null && info != DependencyProperty.UnsetValue))
{
object o = DependencyProperty.UnsetValue;
DependencyProperty dp = info as DependencyProperty;
// if the binding is async, post a request to get the value
if (!(dp != null || SVI[k].type == SourceValueType.Direct))
{
if (_host != null && _host.AsyncGet(item, k))
{
_status = PropertyPathStatus.AsyncRequestPending;
return AsyncRequestPending;
}
}
// PreSharp uses message numbers that the C# compiler doesn't know about.
// Disable the C# complaints, per the PreSharp documentation.
#pragma warning disable 1634, 1691
// PreSharp complains about catching NullReference (and other) exceptions.
// It doesn't recognize that IsCritical[Application]Exception() handles these correctly.
#pragma warning disable 56500
try
{
o = GetValue(item, k);
}
// Catch all exceptions. There is no app code on the stack,
// so the exception isn't actionable by the app.
// Yet we don't want to crash the app.
catch (Exception ex) // if error getting value, we will use fallback/default instead
{
if (CriticalExceptions.IsCriticalApplicationException(ex))
throw;
if (_host != null)
_host.ReportGetValueError(k, item, ex);
}
catch // non CLS compliant exception
{
if (_host != null)
_host.ReportGetValueError(k, item, new InvalidOperationException(SR.Get(SRID.NonCLSException, "GetValue")));
}
// catch the pseudo-exception as well
if (o == IListIndexOutOfRange)
{
o = DependencyProperty.UnsetValue;
if (_host != null)
_host.ReportGetValueError(k, item, new ArgumentOutOfRangeException("index"));
}
#pragma warning restore 56500
#pragma warning restore 1634, 1691
return o;
}
if (_host != null)
{
_host.ReportRawValueErrors(k, item, info);
}
return DependencyProperty.UnsetValue;
}
void SetPropertyInfo(object info, out PropertyInfo pi, out PropertyDescriptor pd, out DependencyProperty dp, out DynamicPropertyAccessor dpa)
{
pi = null;
pd = null;
dpa = null;
dp = info as DependencyProperty;
if (dp == null)
{
pi = info as PropertyInfo;
if (pi == null)
{
pd = info as PropertyDescriptor;
if (pd == null)
dpa = info as DynamicPropertyAccessor;
}
}
}
void CheckReadOnly(object item, object info)
{
PropertyInfo pi;
PropertyDescriptor pd;
DependencyProperty dp;
DynamicPropertyAccessor dpa;
SetPropertyInfo(info, out pi, out pd, out dp, out dpa);
if (pi != null)
{
if (pi.GetSetMethod() == null)
throw new InvalidOperationException(SR.Get(SRID.CannotWriteToReadOnly, item.GetType(), pi.Name));
}
else if (pd != null)
{
if (pd.IsReadOnly)
throw new InvalidOperationException(SR.Get(SRID.CannotWriteToReadOnly, item.GetType(), pd.Name));
}
else if (dp != null)
{
if (dp.ReadOnly)
throw new InvalidOperationException(SR.Get(SRID.CannotWriteToReadOnly, item.GetType(), dp.Name));
}
else if (dpa != null)
{
if (dpa.IsReadOnly)
throw new InvalidOperationException(SR.Get(SRID.CannotWriteToReadOnly, item.GetType(), dpa.PropertyName));
}
}
// see whether DBNull is a valid value for update, and cache the answer
void DetermineWhetherDBNullIsValid()
{
bool result = false;
object item = GetItem(Length - 1);
if (item != null && AssemblyHelper.IsLoaded(UncommonAssembly.System_Data))
{
result = DetermineWhetherDBNullIsValid(item);
}
_isDBNullValidForUpdate = result;
}
// separate method, to avoid loading System.Data.dll until necessary
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
bool DetermineWhetherDBNullIsValid(object item)
{
System.Data.DataRowView drv;
System.Data.DataRow dr = null;
if ((drv = item as System.Data.DataRowView) == null &&
(dr = item as System.Data.DataRow) == null)
{
return false;
}
PropertyInfo pi;
PropertyDescriptor pd;
DependencyProperty dp;
DynamicPropertyAccessor dpa;
SetPropertyInfo(_arySVS[Length-1].info, out pi, out pd, out dp, out dpa);
// this code was provided by the ADO team
System.Data.DataTable table = (drv != null) ? drv.DataView.Table : dr.Table;
string columnName = (pd != null) ? pd.Name :
(pi != null) ? pi.Name : null;
System.Data.DataColumn column = null;
if (columnName == "Item" && pi != null)
{
object arg = _arySVS[Length-1].args[0];
if ((columnName = arg as String) != null)
{
column = table.Columns[columnName];
}
else if (arg is int)
{
int index = (int)arg;
if (0 <= index && index < table.Columns.Count)
{
column = table.Columns[index];
}
}
}
else if (columnName != null)
{
column = table.Columns[columnName];
}
return (column != null) && column.AllowDBNull;
}
///
/// Handle events from the centralized event table
///
bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
if (IsExtendedTraceEnabled(TraceDataLevel.Events))
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GotEvent(
TraceData.Identify(_host.ParentBindingExpression),
TraceData.IdentifyWeakEvent(managerType),
TraceData.Identify(sender)));
}
if (managerType == typeof(PropertyChangedEventManager))
{
PropertyChangedEventArgs pce = (PropertyChangedEventArgs)e;
_host.OnSourcePropertyChanged(sender, pce.PropertyName);
}
else if (managerType == typeof(ValueChangedEventManager))
{
ValueChangedEventArgs vce = (ValueChangedEventArgs)e;
_host.OnSourcePropertyChanged(sender, vce.PropertyDescriptor.Name);
}
else
{
return false; // unrecognized event
}
return true;
}
bool IsExtendedTraceEnabled(TraceDataLevel level)
{
if (_host != null)
{
return TraceData.IsExtendedTraceEnabled(_host.ParentBindingExpression, level);
}
else
{
return false;
}
}
//-----------------------------------------------------
//
// Private Classes
//
//------------------------------------------------------
// helper for setting context via the "using" pattern
class ContextHelper : IDisposable
{
PropertyPathWorker _owner;
public ContextHelper(PropertyPathWorker owner)
{
_owner = owner;
}
public void SetContext(object rootItem)
{
_owner.TreeContext = rootItem as DependencyObject;
_owner.AttachToRootItem(rootItem);
}
void IDisposable.Dispose()
{
_owner.DetachFromRootItem();
_owner.TreeContext = null;
GC.SuppressFinalize(this);
}
}
// wrapper for arguments to IList indexer
class IListIndexerArg
{
public IListIndexerArg(int arg)
{
_arg = arg;
}
public int Value { get { return _arg; } }
int _arg;
}
//-----------------------------------------------------
//
// Private Enums, Structs, Constants
//
//------------------------------------------------------
struct SourceValueState
{
public ICollectionView collectionView;
public object item;
public object info; // PropertyInfo or PropertyDescriptor or DP
public Type type; // Type of the value (useful for Arrays)
public object[] args; // for indexers
}
static readonly Char[] s_comma = new Char[]{','};
static readonly Char[] s_dot = new Char[]{'.'};
static readonly object NoParent = new NamedObject("NoParent");
static readonly object AsyncRequestPending = new NamedObject("AsyncRequestPending");
internal static readonly object IListIndexOutOfRange = new NamedObject("IListIndexOutOfRange");
//------------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
PropertyPath _parent;
PropertyPathStatus _status;
object _treeContext;
object _rootItem;
SourceValueState[] _arySVS;
ContextHelper _contextHelper;
ClrBindingWorker _host;
DataBindEngine _engine;
bool _dependencySourcesChanged;
bool _isDynamic;
bool _needsDirectNotification;
bool? _isDBNullValidForUpdate;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// Description: Defines PropertyPathWorker object, workhorse for CLR bindings
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Globalization;
using System.Text;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Controls; // Validation
using System.Windows.Data;
using System.Windows.Markup;
using MS.Internal;
using MS.Internal.Hashing.PresentationFramework; // HashHelper
namespace MS.Internal.Data
{
internal sealed class PropertyPathWorker: IWeakEventListener
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
internal PropertyPathWorker(PropertyPath path)
: this(path, DataBindEngine.CurrentDataBindEngine)
{
}
internal PropertyPathWorker(PropertyPath path, ClrBindingWorker host, bool isDynamic, DataBindEngine engine)
: this(path, engine)
{
_host = host;
_isDynamic = isDynamic;
}
private PropertyPathWorker(PropertyPath path, DataBindEngine engine)
{
_parent = path;
_arySVS = new SourceValueState[path.Length];
_engine = engine;
// initialize each level to NullDataItem, so that the first real
// item will force a change
for (int i=_arySVS.Length-1; i>=0; --i)
{
_arySVS[i].item = BindingExpression.CreateReference(BindingExpression.NullDataItem);
}
}
//------------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
internal int Length { get { return _parent.Length; } }
internal PropertyPathStatus Status { get { return _status; } }
internal DependencyObject TreeContext
{
get { return BindingExpression.GetReference(_treeContext) as DependencyObject; }
set { _treeContext = BindingExpression.CreateReference(value); }
}
internal void SetTreeContext(WeakReference wr)
{
_treeContext = BindingExpression.CreateReference(wr);
}
internal bool IsDBNullValidForUpdate
{
get
{
if (!_isDBNullValidForUpdate.HasValue)
{
DetermineWhetherDBNullIsValid();
}
return _isDBNullValidForUpdate.Value;
}
}
internal object SourceItem
{
get
{
int level = Length-1;
object item = (level >= 0) ? GetItem(level) : null;
if (item == BindingExpression.NullDataItem)
{
item = null;
}
return item;
}
}
internal string SourcePropertyName
{
get
{
int level = Length-1;
if (level < 0)
return null;
switch (SVI[level].type)
{
case SourceValueType.Property:
// return the real name of the property
DependencyProperty dp;
PropertyInfo pi;
PropertyDescriptor pd;
DynamicPropertyAccessor dpa;
SetPropertyInfo(GetAccessor(level), out pi, out pd, out dp, out dpa);
return (dp != null) ? dp.Name :
(pi != null) ? pi.Name :
(pd != null) ? pd.Name :
(dpa != null) ? dpa.PropertyName : null;
case SourceValueType.Indexer:
// return the indexer string, e.g. "[foo]"
string s = _parent.Path;
int lastBracketIndex = s.LastIndexOf('[');
return s.Substring(lastBracketIndex);
}
// in all other cases, no name is available
return null;
}
}
// true when we need to register for direct notification from the RawValue,
// i.e. when it's a DO that we get to via a non-DP
internal bool NeedsDirectNotification
{
get { return _needsDirectNotification; }
private set
{
if (value)
{
_dependencySourcesChanged = true;
}
_needsDirectNotification = value;
}
}
//------------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
//------- common methods ------
internal object GetItem(int level)
{
return BindingExpression.GetReference(_arySVS[level].item);
}
internal object GetAccessor(int level)
{
return _arySVS[level].info;
}
internal object[] GetIndexerArguments(int level)
{
object[] args = _arySVS[level].args;
// unwrap the IList wrapper, if any
IListIndexerArg wrapper;
if (args != null && args.Length == 1 &&
(wrapper = args[0] as IListIndexerArg) != null)
{
return new object[] { wrapper.Value };
}
return args;
}
internal Type GetType(int level)
{
return _arySVS[level].type;
}
//------- target mode ------
// Set the context for the path. Use this method in "target" mode
// to connect the path to a rootItem for a short time:
// using (path.SetContext(myItem))
// {
// ... call target-mode convenience methods ...
// }
internal IDisposable SetContext(object rootItem)
{
if (_contextHelper == null)
_contextHelper = new ContextHelper(this);
_contextHelper.SetContext(rootItem);
return _contextHelper;
}
//------- source mode (should only be called by ClrBindingWorker) ------
internal void AttachToRootItem(object rootItem)
{
_rootItem = BindingExpression.CreateReference(rootItem);
UpdateSourceValueState(-1, null);
}
internal void DetachFromRootItem()
{
_rootItem = BindingExpression.NullDataItem;
UpdateSourceValueState(-1, null);
_rootItem = null;
}
internal object GetValue(object item, int level)
{
bool isExtendedTraceEnabled = IsExtendedTraceEnabled(TraceDataLevel.GetValue);
DependencyProperty dp;
PropertyInfo pi;
PropertyDescriptor pd;
DynamicPropertyAccessor dpa;
object value = DependencyProperty.UnsetValue;
SetPropertyInfo(_arySVS[level].info, out pi, out pd, out dp, out dpa);
switch (SVI[level].type)
{
case SourceValueType.Property:
if (pi != null)
{
value = pi.GetValue(item, null);
}
else if (pd != null)
{
bool indexerIsNext = (level+1 < SVI.Length && SVI[level+1].type == SourceValueType.Indexer);
value = Engine.GetValue(item, pd, indexerIsNext);
}
else if (dp != null)
{
DependencyObject d = (DependencyObject)item;
if (level != Length-1 || _host == null || _host.TransfersDefaultValue)
value = d.GetValue(dp);
else if (!Helper.HasDefaultValue(d, dp))
value = d.GetValue(dp);
else
value = BindingExpression.IgnoreDefaultValue;
}
else if (dpa != null)
{
value = dpa.GetValue(item);
}
break;
case SourceValueType.Indexer:
DynamicIndexerAccessor dia;
//
if (pi != null)
{
object[] args = _arySVS[level].args;
IListIndexerArg wrapper;
if (args != null && args.Length == 1 &&
(wrapper = args[0] as IListIndexerArg) != null)
{
// common special case: IList indexer. Avoid
// out-of-range exceptions.
int index = wrapper.Value;
IList ilist = (IList)item;
if (0 <= index && index < ilist.Count)
{
value = ilist[index];
}
else
{
value = IListIndexOutOfRange;
}
}
else
{
// normal case
value = pi.GetValue(item,
BindingFlags.GetProperty, null,
args,
CultureInfo.InvariantCulture);
}
}
else if ((dia = _arySVS[level].info as DynamicIndexerAccessor) != null)
{
value = dia.GetValue(item, _arySVS[level].args);
}
else
{
throw new NotSupportedException(SR.Get(SRID.IndexedPropDescNotImplemented));
}
break;
case SourceValueType.Direct:
value = item;
break;
}
if (isExtendedTraceEnabled)
{
object accessor = _arySVS[level].info;
if (accessor == DependencyProperty.UnsetValue)
accessor = null;
TraceData.Trace(TraceEventType.Warning,
TraceData.GetValue(
TraceData.Identify(_host.ParentBindingExpression),
level,
TraceData.Identify(item),
TraceData.IdentifyAccessor(accessor),
TraceData.Identify(value)));
}
return value;
}
internal void SetValue(object item, object value)
{
bool isExtendedTraceEnabled = IsExtendedTraceEnabled(TraceDataLevel.GetValue);
PropertyInfo pi;
PropertyDescriptor pd;
DependencyProperty dp;
DynamicPropertyAccessor dpa;
int level = _arySVS.Length - 1;
SetPropertyInfo(_arySVS[level].info, out pi, out pd, out dp, out dpa);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.SetValue(
TraceData.Identify(_host.ParentBindingExpression),
level,
TraceData.Identify(item),
TraceData.IdentifyAccessor(_arySVS[level].info),
TraceData.Identify(value)));
}
switch (SVI[level].type)
{
case SourceValueType.Property:
if (pd != null)
{
pd.SetValue(item, value);
}
else if (pi != null)
{
pi.SetValue(item, value, null);
}
else if (dp != null)
{
((DependencyObject)item).SetValue(dp, value);
}
else if (dpa != null)
{
dpa.SetValue(item, value);
}
break;
case SourceValueType.Indexer:
DynamicIndexerAccessor dia;
//
if (pi != null)
{
pi.SetValue(item, value,
BindingFlags.SetProperty, null,
GetIndexerArguments(level),
CultureInfo.InvariantCulture);
}
else if ((dia = _arySVS[level].info as DynamicIndexerAccessor) != null)
{
dia.SetValue(item, _arySVS[level].args, value);
}
else
{
throw new NotSupportedException(SR.Get(SRID.IndexedPropDescNotImplemented));
}
break;
}
}
internal object RawValue()
{
object rawValue = RawValue(Length-1);
if (rawValue == AsyncRequestPending)
rawValue = DependencyProperty.UnsetValue; // the real value will arrive later
return rawValue;
}
// Called by BE.UpdateTarget(). Re-fetch the value at each level.
// If there's a difference, simulate a property-change at that level.
internal void RefreshValue()
{
for (int k=1; k<_arySVS.Length; ++k)
{
object oldValue = BindingExpression.GetReference(_arySVS[k].item);
if (!Object.Equals(oldValue, RawValue(k-1)))
{
UpdateSourceValueState(k-1, null);
return;
}
}
UpdateSourceValueState(Length-1, null);
}
// return the source level where the change happened, or -1 if the
// change is irrelevant.
internal int LevelForPropertyChange(object item, string propertyName)
{
// This test must be thread-safe - it can get called on the "wrong" context.
// It's read-only (good). And if another thread changes the values it reads,
// the worst that can happen is to schedule a transfer operation needlessly -
// the operation itself won't do anything (since the test is repeated on the
// right thread).
bool isIndexer = propertyName == Binding.IndexerName;
for (int k=0; k<_arySVS.Length; ++k)
{
if (BindingExpression.GetReference(_arySVS[k].item) == item &&
(String.IsNullOrEmpty(propertyName) ||
(isIndexer && SVI[k].type == MS.Internal.Data.SourceValueType.Indexer) ||
String.Equals(SVI[k].propertyName, propertyName, StringComparison.OrdinalIgnoreCase)))
{
return k;
}
}
return -1;
}
internal void OnPropertyChangedAtLevel(int level)
{
UpdateSourceValueState(level, null);
}
internal void OnCurrentChanged(ICollectionView collectionView)
{
for (int k=0; k= 0 && SVI[level].type == SourceValueType.Property)
{
object item = GetItem(level);
IDataErrorInfo idei = item as IDataErrorInfo;
if (idei != null)
{
DependencyProperty dp;
PropertyInfo pi;
PropertyDescriptor pd;
DynamicPropertyAccessor dpa;
SetPropertyInfo(GetAccessor(level), out pi, out pd, out dp, out dpa);
string name = (dp != null) ? dp.Name :
(pi != null) ? pi.Name :
(pd != null) ? pd.Name :
(dpa != null ) ? dpa.PropertyName :
null;
string error;
if (name != null)
{
// get the data error information, if any, by calling idie[name].
// We do this in a paranoid way, even though indexers with
// string-valued arguments are not supposed to throw exceptions.
// PreSharp uses message numbers that the C# compiler doesn't know about.
// Disable the C# complaints, per the PreSharp documentation.
#pragma warning disable 1634, 1691
// PreSharp complains about catching NullReference (and other) exceptions.
// It doesn't recognize that IsCritical[Application]Exception() handles these correctly.
#pragma warning disable 56500
try
{
error = idei[name];
}
catch (Exception ex)
{
if (CriticalExceptions.IsCriticalApplicationException(ex))
throw;
error = null;
if (TraceData.IsEnabled)
{
TraceData.Trace(TraceEventType.Error,
TraceData.DataErrorInfoFailed(
name,
item.GetType().FullName,
ex.GetType().FullName,
ex.Message),
bindingExpressionBase);
}
}
#pragma warning restore 56500
#pragma warning restore 1634, 1691
}
else
{
error = null;
}
if (!String.IsNullOrEmpty(error))
{
result = new ValidationError(DataErrorValidationRule.Instance,
bindingExpressionBase,
error,
null);
}
}
}
return result;
}
//-----------------------------------------------------
//
// Private Properties
//
//------------------------------------------------------
bool IsDynamic { get { return _isDynamic; } }
SourceValueInfo[] SVI { get { return _parent.SVI; } }
DataBindEngine Engine { get { return _engine; } }
//-----------------------------------------------------
//
// Private Methods
//
//-----------------------------------------------------
// fill in the SourceValueState with updated infomation, starting at level k+1.
// If view isn't null, also update the current item at level k.
private void UpdateSourceValueState(int k, ICollectionView collectionView)
{
UpdateSourceValueState(k, collectionView, BindingExpression.NullDataItem, false);
}
// fill in the SourceValueState with updated infomation, starting at level k+1.
// If view isn't null, also update the current item at level k.
private void UpdateSourceValueState(int k, ICollectionView collectionView, object newValue, bool isASubPropertyChange)
{
// give host a chance to shut down the binding if the target has
// gone away
DependencyObject target = null;
if (_host != null)
{
target = _host.CheckTarget();
if (_rootItem != BindingExpression.NullDataItem && target == null)
return;
}
int initialLevel = k;
object rawValue = null;
// optimistically assume the new value will fix previous path errors
_status = PropertyPathStatus.Active;
// prepare to collect changes to dependency sources
_dependencySourcesChanged = false;
// Update the current item at level k, if requested
if (collectionView != null)
{
Debug.Assert(0<=k && k<_arySVS.Length && _arySVS[k].collectionView == collectionView, "bad parameters to UpdateSourceValueState");
ReplaceItem(k, collectionView.CurrentItem, NoParent);
}
// update the remaining levels
for (++k; k<_arySVS.Length; ++k)
{
isASubPropertyChange = false; // sub-property changes only matter at the last level
ICollectionView oldCollectionView = _arySVS[k].collectionView;
// replace the item at level k using parent from level k-1
rawValue = (newValue == BindingExpression.NullDataItem) ? RawValue(k-1) : newValue;
newValue = BindingExpression.NullDataItem;
if (rawValue == AsyncRequestPending)
{
_status = PropertyPathStatus.AsyncRequestPending;
break; // we'll resume the loop after the request completes
}
ReplaceItem(k, BindingExpression.NullDataItem, rawValue);
// replace view, if necessary
ICollectionView newCollectionView = _arySVS[k].collectionView;
if (oldCollectionView != newCollectionView && _host != null)
{
_host.ReplaceCurrentItem(oldCollectionView, newCollectionView);
}
}
// notify binding about what happened
if (_host != null)
{
if (initialLevel < _arySVS.Length)
{
// when something in the path changes, recompute whether we
// need direct notifications from the raw value
NeedsDirectNotification = _status == PropertyPathStatus.Active &&
_arySVS.Length > 0 &&
SVI[_arySVS.Length-1].type != SourceValueType.Direct &&
!(_arySVS[_arySVS.Length-1].info is DependencyProperty) &&
typeof(DependencyObject).IsAssignableFrom(_arySVS[_arySVS.Length-1].type);
}
_host.NewValueAvailable(_dependencySourcesChanged, initialLevel < 0, isASubPropertyChange);
}
GC.KeepAlive(target); // keep target alive during changes (bug 956831)
}
// replace the item at level k with the given item, or with an item obtained from the given parent
private void ReplaceItem(int k, object newO, object parent)
{
bool isExtendedTraceEnabled = IsExtendedTraceEnabled(TraceDataLevel.ReplaceItem);
SourceValueState svs = new SourceValueState();
object oldO = BindingExpression.GetReference(_arySVS[k].item);
// stop listening to old item
if (IsDynamic && SVI[k].type != SourceValueType.Direct)
{
INotifyPropertyChanged oldPC = oldO as INotifyPropertyChanged;
if (oldPC != null)
{
PropertyChangedEventManager.RemoveListener(oldPC, this, SVI[k].propertyName);
}
else
{
PropertyDescriptor oldDesc = _arySVS[k].info as PropertyDescriptor;
if (oldDesc != null && oldO != null && oldO != BindingExpression.NullDataItem)
{
ValueChangedEventManager.RemoveListener(oldO, this, oldDesc);
}
}
DependencyProperty dp = _arySVS[k].info as DependencyProperty;
if (dp != null)
{
_dependencySourcesChanged = true;
}
}
// clear the IsDBNullValid cache
_isDBNullValidForUpdate = null;
if (newO == null ||
parent == DependencyProperty.UnsetValue ||
parent == BindingExpression.NullDataItem ||
parent == BindingExpressionBase.DisconnectedItem)
{
_arySVS[k].item = BindingExpression.ReplaceReference(_arySVS[k].item, newO);
if (parent == DependencyProperty.UnsetValue ||
parent == BindingExpression.NullDataItem ||
parent == BindingExpressionBase.DisconnectedItem)
{
_arySVS[k].collectionView = null;
}
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.ReplaceItemShort(
TraceData.Identify(_host.ParentBindingExpression),
k,
TraceData.Identify(newO)));
}
return;
}
// obtain the new item and its access info
if (newO != BindingExpression.NullDataItem)
{
parent = newO; // used by error reporting
GetInfo(k, newO, ref svs);
svs.collectionView = _arySVS[k].collectionView;
}
else
{
// Note: if we want to support binding to HasValue and/or Value
// properties of nullable types, we need a way to find out if
// the rawvalue is Nullable and pass that information here.
DrillIn drillIn = SVI[k].drillIn;
ICollectionView view = null;
// first look for info on the parent
if (drillIn != DrillIn.Always)
{
GetInfo(k, parent, ref svs);
}
// if that fails, look for information on the view itself
if (svs.info == null)
{
view = CollectionViewSource.GetDefaultCollectionView(parent, TreeContext);
if (view != null && drillIn != DrillIn.Always)
{
if (view != parent) // don't duplicate work
GetInfo(k, view, ref svs);
}
}
// if that fails, drill in to the current item
if (svs.info == null && drillIn != DrillIn.Never && view != null)
{
newO = view.CurrentItem;
if (newO != null)
{
GetInfo(k, newO, ref svs);
svs.collectionView = view;
}
else
{
// no current item: use previous info (if known)
svs = _arySVS[k];
svs.collectionView = view;
// if there's no current item because parent is an empty
// XmlDataCollection, treat it as a path error (the XPath
// didn't return any nodes)
if (!IsEmptyXmlDataCollection(parent))
{
// otherwise it's not an error - currency is simply
// off the collection
svs.item = BindingExpression.ReplaceReference(svs.item, BindingExpression.NullDataItem);
if (svs.info == null)
svs.info = DependencyProperty.UnsetValue;
}
}
}
}
// update info about new item
if (svs.info == null)
{
svs.item = BindingExpression.ReplaceReference(svs.item, BindingExpression.NullDataItem);
_arySVS[k] = svs;
_status = PropertyPathStatus.PathError;
ReportNoInfoError(k, parent);
return;
}
_arySVS[k] = svs;
newO = BindingExpression.GetReference(svs.item);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.ReplaceItemLong(
TraceData.Identify(_host.ParentBindingExpression),
k,
TraceData.Identify(newO),
TraceData.IdentifyAccessor(svs.info)));
}
// start listening to new item
if (IsDynamic && SVI[k].type != SourceValueType.Direct)
{
Engine.RegisterForCacheChanges(newO, svs.info);
INotifyPropertyChanged newPC = newO as INotifyPropertyChanged;
if (newPC != null)
{
PropertyChangedEventManager.AddListener(newPC, this, SVI[k].propertyName);
}
else
{
PropertyDescriptor newDesc = svs.info as PropertyDescriptor;
if (newDesc != null && newO != null)
ValueChangedEventManager.AddListener(newO, this, newDesc);
}
}
// at the last level, set up the default transformer
if (_host != null && k == Length-1)
{
_host.SetupDefaultValueConverter(svs.type);
// also, check for request to update a read-only property
if (_host.IsReflective)
{
CheckReadOnly(newO, svs.info);
}
}
}
void ReportNoInfoError(int k, object parent)
{
// report cannot find info. Ignore when in priority bindings.
if (TraceData.IsEnabled)
{
BindingExpression bindingExpression = (_host != null) ? _host.ParentBindingExpression : null;
if (bindingExpression == null || !bindingExpression.IsInPriorityBindingExpression)
{
if (!IsEmptyXmlDataCollection(parent))
{
SourceValueInfo svi = SVI[k];
string cs = (svi.type != SourceValueType.Indexer) ? svi.name : "[" + svi.name + "]";
string ps = TraceData.DescribeSourceObject(parent);
string os = (svi.drillIn == DrillIn.Always) ? "current item of collection" : "object";
// if the parent is null, the path error probably only means the
// data provider hasn't produced any data yet. When it does,
// the binding will try again and probably succeed. Give milder
// feedback for this special case, so as not to alarm users unduly.
if (parent == null)
{
TraceData.Trace(TraceEventType.Information, TraceData.NullItem(cs, os), bindingExpression);
}
// Similarly, if the parent is the NewItemPlaceholder.
else if (parent == CollectionView.NewItemPlaceholder ||
parent == DataGrid.NewItemPlaceholder)
{
TraceData.Trace(TraceEventType.Information, TraceData.PlaceholderItem(cs, os), bindingExpression);
}
else
{
TraceEventType traceType = (bindingExpression != null) ? bindingExpression.TraceLevel : TraceEventType.Error;
TraceData.Trace(traceType, TraceData.ClrReplaceItem(cs, ps, os), bindingExpression);
}
}
else
{
TraceEventType traceType = (bindingExpression != null) ? bindingExpression.TraceLevel : TraceEventType.Error;
_host.ReportBadXPath(traceType);
}
}
}
}
// determine if the cached state of the path is still correct. This is
// used to deduce whether event leapfrogging has occurred along the path
// (i.e. something changed, but we haven't yet received the notification)
internal bool IsPathCurrent(object rootItem)
{
if (Status != PropertyPathStatus.Active)
return false;
object item = rootItem;
for (int level=0, n=Length; level 0 : false;
}
// look for property/indexer on the given item
private void GetInfo(int k, object item, ref SourceValueState svs)
{
#if DEBUG
bool checkCacheResult = false;
#endif
object oldItem = BindingExpression.GetReference(_arySVS[k].item);
bool isExtendedTraceEnabled = IsExtendedTraceEnabled(TraceDataLevel.GetInfo);
// optimization - only change info if the type changed
// exception - if the info is a PropertyDescriptor, it might depend
// on the item itself (not just the type), so we have to re-fetch
Type oldType = (oldItem != null) ? oldItem.GetType() : null;
Type newType = (item != null) ? item.GetType() : null;
Type sourceType = null;
if (newType == oldType && oldItem != BindingExpression.NullDataItem &&
!(_arySVS[k].info is PropertyDescriptor))
{
svs = _arySVS[k];
svs.item = BindingExpression.ReplaceReference(svs.item, item);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GetInfo_Reuse(
TraceData.Identify(_host.ParentBindingExpression),
k,
TraceData.IdentifyAccessor(svs.info)));
}
return;
}
// if the new item is null, we won't find a property/indexer on it
if (newType == null && SVI[k].type != SourceValueType.Direct)
{
svs.info = null;
svs.args = null;
svs.type = null;
svs.item = BindingExpression.ReplaceReference(svs.item, item);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GetInfo_Null(
TraceData.Identify(_host.ParentBindingExpression),
k));
}
return;
}
// optimization - see if we've cached the answer
int index;
bool cacheAccessor = !PropertyPath.IsParameterIndex(SVI[k].name, out index);
if (cacheAccessor)
{
AccessorInfo accessorInfo = Engine.AccessorTable[SVI[k].type, newType, SVI[k].name];
if (accessorInfo != null)
{
svs.info = accessorInfo.Accessor;
svs.type = accessorInfo.PropertyType;
svs.args = accessorInfo.Args;
svs.item = BindingExpression.ReplaceReference(svs.item, item);
if (IsDynamic && SVI[k].type == SourceValueType.Property && svs.info is DependencyProperty)
{
_dependencySourcesChanged = true;
}
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GetInfo_Cache(
TraceData.Identify(_host.ParentBindingExpression),
k,
newType.Name,
SVI[k].name,
TraceData.IdentifyAccessor(svs.info)));
}
#if DEBUG // compute the answer the old-fashioned way, and compare
checkCacheResult = true;
#else
return;
#endif
}
}
object info = null;
object[] args = null;
switch (SVI[k].type)
{
case SourceValueType.Property:
info = _parent.ResolvePropertyName(k, item, newType, TreeContext);
if (isExtendedTraceEnabled)
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GetInfo_Property(
TraceData.Identify(_host.ParentBindingExpression),
k,
newType.Name,
SVI[k].name,
TraceData.IdentifyAccessor(info)));
}
DependencyProperty dp;
PropertyInfo pi1;
PropertyDescriptor pd;
DynamicObjectAccessor doa;
PropertyPath.DowncastAccessor(info, out dp, out pi1, out pd, out doa);
if (dp != null)
{
sourceType = dp.PropertyType;
if (IsDynamic)
{
#if DEBUG
if (checkCacheResult)
Debug.Assert(_dependencySourcesChanged, "Cached accessor didn't change sources");
#endif
_dependencySourcesChanged = true;
}
break;
}
else if (pi1 != null)
{
sourceType = pi1.PropertyType;
}
else if (pd != null)
{
sourceType = pd.PropertyType;
}
else if (doa != null)
{
sourceType = doa.PropertyType;
#if DEBUG
checkCacheResult = false; // not relevant for dynamic objects
#endif
}
break;
case SourceValueType.Indexer:
IndexerParameterInfo[] aryInfo = _parent.ResolveIndexerParams(k, TreeContext);
// Check if we should treat the indexer as a property instead.
// (See ShouldConvertIndexerToProperty for why we might do that.)
if (aryInfo.Length == 1 &&
(aryInfo[0].type == null || aryInfo[0].type == typeof(string)))
{
string name = (string)aryInfo[0].value;
if (ShouldConvertIndexerToProperty(item, ref name))
{
_parent.ReplaceIndexerByProperty(k, name);
goto case SourceValueType.Property;
}
}
args = new object[aryInfo.Length];
// find the matching indexer
MemberInfo[][] aryMembers= new MemberInfo[][]{ newType.GetDefaultMembers(), null };
bool isIList = (item is IList);
if (isIList)
aryMembers[1] = typeof(IList).GetDefaultMembers();
for (int ii=0; info==null && ii 0)
{
Debug.Assert(false,
String.Format("Accessor cache returned incorrect result for ({0},{1},{2})\n{3}",
SVI[k].type, newType.Name, SVI[k].name, sb.ToString()));
}
return;
}
#endif
svs.info = info;
svs.args = args;
svs.type = sourceType;
svs.item = BindingExpression.ReplaceReference(svs.item, item);
// cache the answer, to avoid doing all that reflection again
// (but not if the answer is a PropertyDescriptor,
// since then the answer potentially depends on the item itself)
if (cacheAccessor && info != null && !(info is PropertyDescriptor))
{
Engine.AccessorTable[SVI[k].type, newType, SVI[k].name] =
new AccessorInfo(info, sourceType, args);
}
}
// convert the (string) argument names to types appropriate for use with
// the given property. Put the results in the args[] array. Return
// true if everything works.
private bool MatchIndexerParameters(ParameterInfo[] aryPI, IndexerParameterInfo[] aryInfo, object[] args, bool isIList)
{
// must have the right number of parameters
if (aryPI != null && aryPI.Length != aryInfo.Length)
return false;
// each parameter must be settable from user-specified type or from a string
for (int i=0; i= _arySVS.Length)
return DependencyProperty.UnsetValue;
object item = BindingExpression.GetReference(_arySVS[k].item);
object info = _arySVS[k].info;
// try to get the value, unless (a) binding is being detached,
// (b) no info - e.g. Nullable with no value, or (c) item expected
// but not present - e.g. currency moved off the end.
if (item != BindingExpression.NullDataItem && info != null && !(item == null && info != DependencyProperty.UnsetValue))
{
object o = DependencyProperty.UnsetValue;
DependencyProperty dp = info as DependencyProperty;
// if the binding is async, post a request to get the value
if (!(dp != null || SVI[k].type == SourceValueType.Direct))
{
if (_host != null && _host.AsyncGet(item, k))
{
_status = PropertyPathStatus.AsyncRequestPending;
return AsyncRequestPending;
}
}
// PreSharp uses message numbers that the C# compiler doesn't know about.
// Disable the C# complaints, per the PreSharp documentation.
#pragma warning disable 1634, 1691
// PreSharp complains about catching NullReference (and other) exceptions.
// It doesn't recognize that IsCritical[Application]Exception() handles these correctly.
#pragma warning disable 56500
try
{
o = GetValue(item, k);
}
// Catch all exceptions. There is no app code on the stack,
// so the exception isn't actionable by the app.
// Yet we don't want to crash the app.
catch (Exception ex) // if error getting value, we will use fallback/default instead
{
if (CriticalExceptions.IsCriticalApplicationException(ex))
throw;
if (_host != null)
_host.ReportGetValueError(k, item, ex);
}
catch // non CLS compliant exception
{
if (_host != null)
_host.ReportGetValueError(k, item, new InvalidOperationException(SR.Get(SRID.NonCLSException, "GetValue")));
}
// catch the pseudo-exception as well
if (o == IListIndexOutOfRange)
{
o = DependencyProperty.UnsetValue;
if (_host != null)
_host.ReportGetValueError(k, item, new ArgumentOutOfRangeException("index"));
}
#pragma warning restore 56500
#pragma warning restore 1634, 1691
return o;
}
if (_host != null)
{
_host.ReportRawValueErrors(k, item, info);
}
return DependencyProperty.UnsetValue;
}
void SetPropertyInfo(object info, out PropertyInfo pi, out PropertyDescriptor pd, out DependencyProperty dp, out DynamicPropertyAccessor dpa)
{
pi = null;
pd = null;
dpa = null;
dp = info as DependencyProperty;
if (dp == null)
{
pi = info as PropertyInfo;
if (pi == null)
{
pd = info as PropertyDescriptor;
if (pd == null)
dpa = info as DynamicPropertyAccessor;
}
}
}
void CheckReadOnly(object item, object info)
{
PropertyInfo pi;
PropertyDescriptor pd;
DependencyProperty dp;
DynamicPropertyAccessor dpa;
SetPropertyInfo(info, out pi, out pd, out dp, out dpa);
if (pi != null)
{
if (pi.GetSetMethod() == null)
throw new InvalidOperationException(SR.Get(SRID.CannotWriteToReadOnly, item.GetType(), pi.Name));
}
else if (pd != null)
{
if (pd.IsReadOnly)
throw new InvalidOperationException(SR.Get(SRID.CannotWriteToReadOnly, item.GetType(), pd.Name));
}
else if (dp != null)
{
if (dp.ReadOnly)
throw new InvalidOperationException(SR.Get(SRID.CannotWriteToReadOnly, item.GetType(), dp.Name));
}
else if (dpa != null)
{
if (dpa.IsReadOnly)
throw new InvalidOperationException(SR.Get(SRID.CannotWriteToReadOnly, item.GetType(), dpa.PropertyName));
}
}
// see whether DBNull is a valid value for update, and cache the answer
void DetermineWhetherDBNullIsValid()
{
bool result = false;
object item = GetItem(Length - 1);
if (item != null && AssemblyHelper.IsLoaded(UncommonAssembly.System_Data))
{
result = DetermineWhetherDBNullIsValid(item);
}
_isDBNullValidForUpdate = result;
}
// separate method, to avoid loading System.Data.dll until necessary
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
bool DetermineWhetherDBNullIsValid(object item)
{
System.Data.DataRowView drv;
System.Data.DataRow dr = null;
if ((drv = item as System.Data.DataRowView) == null &&
(dr = item as System.Data.DataRow) == null)
{
return false;
}
PropertyInfo pi;
PropertyDescriptor pd;
DependencyProperty dp;
DynamicPropertyAccessor dpa;
SetPropertyInfo(_arySVS[Length-1].info, out pi, out pd, out dp, out dpa);
// this code was provided by the ADO team
System.Data.DataTable table = (drv != null) ? drv.DataView.Table : dr.Table;
string columnName = (pd != null) ? pd.Name :
(pi != null) ? pi.Name : null;
System.Data.DataColumn column = null;
if (columnName == "Item" && pi != null)
{
object arg = _arySVS[Length-1].args[0];
if ((columnName = arg as String) != null)
{
column = table.Columns[columnName];
}
else if (arg is int)
{
int index = (int)arg;
if (0 <= index && index < table.Columns.Count)
{
column = table.Columns[index];
}
}
}
else if (columnName != null)
{
column = table.Columns[columnName];
}
return (column != null) && column.AllowDBNull;
}
///
/// Handle events from the centralized event table
///
bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
if (IsExtendedTraceEnabled(TraceDataLevel.Events))
{
TraceData.Trace(TraceEventType.Warning,
TraceData.GotEvent(
TraceData.Identify(_host.ParentBindingExpression),
TraceData.IdentifyWeakEvent(managerType),
TraceData.Identify(sender)));
}
if (managerType == typeof(PropertyChangedEventManager))
{
PropertyChangedEventArgs pce = (PropertyChangedEventArgs)e;
_host.OnSourcePropertyChanged(sender, pce.PropertyName);
}
else if (managerType == typeof(ValueChangedEventManager))
{
ValueChangedEventArgs vce = (ValueChangedEventArgs)e;
_host.OnSourcePropertyChanged(sender, vce.PropertyDescriptor.Name);
}
else
{
return false; // unrecognized event
}
return true;
}
bool IsExtendedTraceEnabled(TraceDataLevel level)
{
if (_host != null)
{
return TraceData.IsExtendedTraceEnabled(_host.ParentBindingExpression, level);
}
else
{
return false;
}
}
//-----------------------------------------------------
//
// Private Classes
//
//------------------------------------------------------
// helper for setting context via the "using" pattern
class ContextHelper : IDisposable
{
PropertyPathWorker _owner;
public ContextHelper(PropertyPathWorker owner)
{
_owner = owner;
}
public void SetContext(object rootItem)
{
_owner.TreeContext = rootItem as DependencyObject;
_owner.AttachToRootItem(rootItem);
}
void IDisposable.Dispose()
{
_owner.DetachFromRootItem();
_owner.TreeContext = null;
GC.SuppressFinalize(this);
}
}
// wrapper for arguments to IList indexer
class IListIndexerArg
{
public IListIndexerArg(int arg)
{
_arg = arg;
}
public int Value { get { return _arg; } }
int _arg;
}
//-----------------------------------------------------
//
// Private Enums, Structs, Constants
//
//------------------------------------------------------
struct SourceValueState
{
public ICollectionView collectionView;
public object item;
public object info; // PropertyInfo or PropertyDescriptor or DP
public Type type; // Type of the value (useful for Arrays)
public object[] args; // for indexers
}
static readonly Char[] s_comma = new Char[]{','};
static readonly Char[] s_dot = new Char[]{'.'};
static readonly object NoParent = new NamedObject("NoParent");
static readonly object AsyncRequestPending = new NamedObject("AsyncRequestPending");
internal static readonly object IListIndexOutOfRange = new NamedObject("IListIndexOutOfRange");
//------------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
PropertyPath _parent;
PropertyPathStatus _status;
object _treeContext;
object _rootItem;
SourceValueState[] _arySVS;
ContextHelper _contextHelper;
ClrBindingWorker _host;
DataBindEngine _engine;
bool _dependencySourcesChanged;
bool _isDynamic;
bool _needsDirectNotification;
bool? _isDBNullValidForUpdate;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SpellerStatusTable.cs
- LinkUtilities.cs
- DelegateArgumentValue.cs
- WeakEventManager.cs
- DesignerHelpers.cs
- MenuItem.cs
- TextSelectionHighlightLayer.cs
- ListQueryResults.cs
- WindowsListViewItemStartMenu.cs
- SafeSecurityHandles.cs
- MembershipSection.cs
- DataSourceGeneratorException.cs
- IfAction.cs
- DataGridItem.cs
- ReferenceTypeElement.cs
- RadioButtonAutomationPeer.cs
- TypeSchema.cs
- WebPartVerbsEventArgs.cs
- Pkcs9Attribute.cs
- CompilationUnit.cs
- ObjectDataSourceMethodEditor.cs
- MenuStrip.cs
- WindowsTreeView.cs
- VideoDrawing.cs
- CutCopyPasteHelper.cs
- login.cs
- Base64Decoder.cs
- RemoteCryptoTokenProvider.cs
- KeySplineConverter.cs
- Shared.cs
- IImplicitResourceProvider.cs
- FixedDocumentSequencePaginator.cs
- DataGridViewControlCollection.cs
- VerticalConnector.xaml.cs
- CommonDialog.cs
- Cursor.cs
- DefaultValueConverter.cs
- BuildProviderAppliesToAttribute.cs
- RtfControls.cs
- TypeUsage.cs
- ResourceDictionaryCollection.cs
- ThicknessAnimation.cs
- IQueryable.cs
- DependencyPropertyAttribute.cs
- ResourceDisplayNameAttribute.cs
- StringUtil.cs
- ParameterBinding.cs
- BuildProviderUtils.cs
- QilNode.cs
- WbmpConverter.cs
- SQLDoubleStorage.cs
- ParallelRangeManager.cs
- PathGeometry.cs
- GenericIdentity.cs
- SqlProviderServices.cs
- C14NUtil.cs
- PrintPreviewDialog.cs
- SecurityTokenParametersEnumerable.cs
- ImpersonateTokenRef.cs
- InArgumentConverter.cs
- SchemaElementLookUpTable.cs
- AnnotationResource.cs
- SmtpClient.cs
- GZipDecoder.cs
- StrokeNodeOperations.cs
- EncryptedType.cs
- CompilationUtil.cs
- ChangeTracker.cs
- XmlElementAttribute.cs
- SqlWebEventProvider.cs
- AttachedAnnotationChangedEventArgs.cs
- MimeTypeMapper.cs
- IODescriptionAttribute.cs
- TagNameToTypeMapper.cs
- MailAddress.cs
- DeviceContexts.cs
- BoundPropertyEntry.cs
- SafeSystemMetrics.cs
- Constants.cs
- SqlCommandBuilder.cs
- XmlAttributeAttribute.cs
- PropertyKey.cs
- MessageHeaderT.cs
- BlockCollection.cs
- PictureBox.cs
- EventLevel.cs
- TrustExchangeException.cs
- AsyncOperationContext.cs
- DataSourceCache.cs
- CommandBindingCollection.cs
- WebPartDisplayModeCancelEventArgs.cs
- ErrorTableItemStyle.cs
- ProxyWebPartManager.cs
- ProjectionAnalyzer.cs
- ParameterCollection.cs
- DataTableExtensions.cs
- ConsoleTraceListener.cs
- ProfileServiceManager.cs
- DetailsViewRow.cs
- ConnectivityStatus.cs