protected void LoadMethods()
        {
            m_methodDictionary = new Dictionary <string, MethodData>();

            // load device methods
            var deviceMethods = from m in HostedDevice.GetType().GetRuntimeMethods()
                                let ma = m.GetCustomAttributes(typeof(MTConnectMethodAttribute), true).FirstOrDefault()
                                         where ma != null
                                         select m;

            Debug.WriteLine(string.Format("Device '{0}' Methods", HostedDevice.Name));

            foreach (var method in deviceMethods)
            {
                Debug.WriteLine(" - " + method.Name);
                m_methodDictionary.Add(method.Name,
                                       new MethodData
                {
                    MethodInfo = method,
                    Instance   = HostedDevice
                }
                                       );
            }

            if (HostedDevice.Components != null)
            {
                foreach (var component in HostedDevice.Components)
                {
                    Debug.WriteLine(string.Format(" Component '{0}'", component.Name));

                    var componentMethods = from m in component.GetType().GetRuntimeMethods()
                                           let ma = m.GetCustomAttributes(typeof(MTConnectMethodAttribute), true).FirstOrDefault()
                                                    where ma != null
                                                    select m;

                    foreach (var method in componentMethods)
                    {
                        Debug.WriteLine("  - " + method.Name);
                        m_methodDictionary.Add(method.Name,
                                               new MethodData
                        {
                            MethodInfo = method,
                            Instance   = component
                        }
                                               );
                    }
                }
            }
        }
        protected void LoadProperties()
        {
            lock (m_syncRoot)
            {
                m_propertyDictionary = new Dictionary <string, PropertyData>(StringComparer.OrdinalIgnoreCase);
                m_propertyKeyMap     = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

                // load device properties
                var deviceProperties = from p in HostedDevice.GetType().GetRuntimeProperties()
                                       let pr = p.GetCustomAttributes(typeof(DataItemAttribute), true).FirstOrDefault()
                                                where pr != null
                                                select new DataItemProperty
                {
                    PropertyInfo      = p,
                    PropertyAttribute = pr as DataItemAttribute
                };

                Debug.WriteLine(string.Format("Device '{0}' Properties", HostedDevice.Name));

                List <DataItemProperty> props = deviceProperties.ToList();

                foreach (var prop in deviceProperties)
                {
                    Debug.WriteLine(" - " + prop.PropertyInfo.Name);

                    // create a DataItem to export
                    var id = prop.PropertyAttribute.ID;
                    if (id.IsNullOrEmpty())
                    {
                        id = CreateDataItemID(HostedDevice.Name, null, prop.PropertyInfo.Name);
                    }

                    var dataItem = CreateDataItem(prop, id);
                    // see if it's publicly writable
                    if (prop.PropertyInfo.SetMethod == null)
                    {
                        dataItem.Writable = false;
                    }

                    Device.AddDataItem(dataItem);

                    // cache the propertyinfo for later use
                    var pd = new PropertyData
                    {
                        PropertyInfo = prop.PropertyInfo,
                        Instance     = HostedDevice,
                    };
                    m_propertyDictionary.Add(id, pd);
                    var key = string.Format("{0}_{1}", HostedDevice.Name, prop.PropertyInfo.Name);
                    m_propertyKeyMap.Add(key, id);

                    // wire the DataItem set to the HostedProperty setter
                    if (pd.PropertyInfo.CanWrite)
                    {
                        dataItem.ValueSet += delegate(object sender, DataItemValue e)
                        {
                            // look to see if we're getting called from a propertychanged handler - if so we want to prevent reentrancy
                            lock (m_ignorePropertyChangeIDs)
                            {
                                if (m_ignorePropertyChangeIDs.Contains(id))
                                {
                                    return;
                                }
                            }

                            var n = HostedDevice as INotifyPropertyChanged;
                            // remove the change handler so our change doesn't reflect back to this point
                            if (n != null)
                            {
                                n.PropertyChanged -= PropertyChangedHandler;
                            }

                            SetMTConnectPropertyFromDataItemValueChange(pd, e.Value);

                            // rewire the change handler
                            if (n != null)
                            {
                                n.PropertyChanged += PropertyChangedHandler;
                            }
                        };
                    }
                }

                var notifier = HostedDevice as INotifyPropertyChanged;
                if (notifier != null)
                {
                    notifier.PropertyChanged += PropertyChangedHandler;
                }
                else
                {
                    Debug.WriteLine("notifier is null");
                }

                // load component properties
                if (HostedDevice.Components != null)
                {
                    foreach (var component in HostedDevice.Components)
                    {
                        var host = Device.Components[component.ID];
                        LoadComponentProperties(host, component);

                        // recurse one level only (that's all the spec allows)
                        if (component.Components != null)
                        {
                            foreach (var subcomponent in component.Components)
                            {
                                var subhost = host.Components[subcomponent.ID];
                                LoadComponentProperties(subhost, subcomponent);
                            }
                        }
                    }
                }
            }
        }