protected virtual bool ShowEnumField(PropertyGridProperty property, Type type, string name, out string displayName) { if (property == null) { throw new ArgumentNullException("property"); } if (type == null) { throw new ArgumentNullException("type"); } if (name == null) { throw new ArgumentNullException("name"); } FieldInfo fi = type.GetField(name, BindingFlags.Static | BindingFlags.Public); displayName = fi.Name; var ba = fi.GetAttribute <BrowsableAttribute>(); if (ba != null && !ba.Browsable) { return(false); } var da = fi.GetAttribute <DescriptionAttribute>(); if (da != null && !string.IsNullOrWhiteSpace(da.Description)) { displayName = da.Description; } return(true); }
public virtual bool?ShowEditor(PropertyGridProperty property, object parameter) { if (property == null) { throw new ArgumentNullException("property"); } Window editor = GetEditor(property, parameter); if (editor != null) { bool?ret; var go = property.DataProvider.Data as IPropertyGridObject; if (go != null) { if (go.TryShowEditor(property, editor, out ret)) { return(ret); } RefreshSelectedObject(editor); } ret = editor.ShowDialog(); if (go != null) { go.EditorClosed(property, editor); } return(ret); } return(null); }
public static object EnumToObject(PropertyGridProperty property, object value) { if (property == null) { throw new ArgumentNullException("property"); } if (value != null && property.PropertyType.IsEnum) { return(Extensions.EnumToObject(property.PropertyType, value)); } if (value != null && value.GetType().IsEnum) { return(Extensions.EnumToObject(value.GetType(), value)); } if (property.PropertyType != typeof(string)) { return(ConversionService.ChangeType(value, property.PropertyType)); } var options = PropertyGridOptionsAttribute.FromProperty(property); if (options == null) { return(ConversionService.ChangeType(value, property.PropertyType)); } return(EnumToObject(options, property.PropertyType, value)); }
protected virtual bool Filter(PropertyGridDataTemplate template, PropertyGridProperty property) { if (template == null) { throw new ArgumentNullException("template"); } if (property == null) { throw new ArgumentNullException("property"); } // check various filters if (template.IsCollection.HasValue && template.IsCollection.Value != property.IsCollection) { return(true); } if (template.IsCollectionItemValueType.HasValue && template.IsCollectionItemValueType.Value != property.IsCollectionItemValueType) { return(true); } if (template.IsValueType.HasValue && template.IsValueType.Value != property.IsValueType) { return(true); } if (template.IsReadOnly.HasValue && template.IsReadOnly.Value != property.IsReadOnly) { return(true); } if (template.IsError.HasValue && template.IsError.Value != property.IsError) { return(true); } if (template.IsValid.HasValue && template.IsValid.Value != property.IsValid) { return(true); } if (template.IsFlagsEnum.HasValue && template.IsFlagsEnum.Value != property.IsFlagsEnum) { return(true); } if (template.Category != null && !property.Category.EqualsIgnoreCase(template.Category)) { return(true); } if (template.Name != null && !property.Name.EqualsIgnoreCase(template.Name)) { return(true); } return(false); }
protected virtual void ScanProperties() { Properties.Clear(); List <PropertyGridProperty> props = new List <PropertyGridProperty>(); foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(Data)) { if (!descriptor.IsBrowsable) { continue; } PropertyGridProperty property = CreateProperty(descriptor); if (property != null) { props.Add(property); } } IPropertyGridObject pga = Data as IPropertyGridObject; if (pga != null) { pga.FinalizeProperties(this, props); } props.Sort(); foreach (PropertyGridProperty property in props) { Properties.Add(property); } }
public virtual PropertyGridProperty AddProperty(string propertyName) { if (propertyName == null) { throw new ArgumentNullException("propertyName"); } PropertyGridProperty prop = Properties.FirstOrDefault(p => p.Name == propertyName); if (prop != null) { return(prop); } PropertyDescriptor desc = TypeDescriptor.GetProperties(Data).OfType <PropertyDescriptor>().FirstOrDefault(p => p.Name == propertyName); if (desc != null) { prop = CreateProperty(desc); if (prop != null) { Properties.Add(prop); } } return(prop); }
protected virtual void OnGuidCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) { var property = PropertyGridProperty.FromEvent(e); if (property != null && (property.PropertyType == typeof(Guid) || property.PropertyType == typeof(Guid?))) { e.CanExecute = true; } }
protected virtual void OnEditorWindowSaveExecuted(object sender, ExecutedRoutedEventArgs e) { Window window = (Window)sender; PropertyGridProperty prop = window.DataContext as PropertyGridProperty; if (prop != null) { prop.Executed(sender, e); } }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { PropertyGridProperty property = value as PropertyGridProperty; if (property != null) { return(Extension.BuildItems(property, targetType, parameter, culture)); } return(value); }
protected virtual void Describe(PropertyGridProperty property, PropertyDescriptor descriptor) { if (property == null) { throw new ArgumentNullException("property"); } if (descriptor == null) { throw new ArgumentNullException("descriptor"); } property.Descriptor = descriptor; property.Name = descriptor.Name; property.PropertyType = descriptor.PropertyType; // unset by default. conversion service does the default job //property.Converter = descriptor.Converter; property.Category = string.IsNullOrWhiteSpace(descriptor.Category) || descriptor.Category.EqualsIgnoreCase(CategoryAttribute.Default.Category) ? Grid.DefaultCategoryName : descriptor.Category; property.IsReadOnly = descriptor.IsReadOnly; property.Description = descriptor.Description; property.DisplayName = descriptor.DisplayName; if (property.DisplayName == descriptor.Name) { property.DisplayName = DecamelizationService.Decamelize(property.DisplayName); } property.IsEnum = descriptor.PropertyType.IsEnum; property.IsFlagsEnum = descriptor.PropertyType.IsEnum && Extensions.IsFlagsEnum(descriptor.PropertyType); DefaultValueAttribute att = descriptor.GetAttribute <DefaultValueAttribute>(); property.HasDefaultValue = att != null; property.DefaultValue = att != null ? att.Value : null; PropertyGridOptionsAttribute options = descriptor.GetAttribute <PropertyGridOptionsAttribute>(); if (options != null) { if (options.SortOrder != 0) { property.SortOrder = options.SortOrder; } property.IsEnum = options.IsEnum; property.IsFlagsEnum = options.IsFlagsEnum; } AddDynamicProperties(descriptor.Attributes.OfType <PropertyGridAttribute>(), property.Attributes); AddDynamicProperties(descriptor.PropertyType.GetAttributes <PropertyGridAttribute>(), property.TypeAttributes); }
public virtual PropertyGridProperty CreateProperty(PropertyDescriptor descriptor) { if (descriptor == null) { throw new ArgumentNullException("descriptor"); } bool forceReadWrite = false; PropertyGridProperty property = null; PropertyGridOptionsAttribute options = descriptor.GetAttribute <PropertyGridOptionsAttribute>(); if (options != null) { forceReadWrite = options.ForceReadWrite; if (options.PropertyType != null) { property = (PropertyGridProperty)Activator.CreateInstance(options.PropertyType, this); } } if (property == null) { options = descriptor.PropertyType.GetAttribute <PropertyGridOptionsAttribute>(); if (options != null) { if (!forceReadWrite) { forceReadWrite = options.ForceReadWrite; } if (options.PropertyType != null) { property = (PropertyGridProperty)Activator.CreateInstance(options.PropertyType, this); } } } if (property == null) { property = CreateProperty(); } Describe(property, descriptor); if (forceReadWrite) { property.IsReadOnly = false; } property.OnDescribed(); property.RefreshValueFromDescriptor(); return(property); }
protected virtual void OnEditorWindowCloseCanExecute(object sender, CanExecuteRoutedEventArgs e) { Window window = (Window)sender; PropertyGridProperty prop = window.DataContext as PropertyGridProperty; if (prop != null) { prop.CanExecute(sender, e); if (e.Handled) { return; } } e.CanExecute = true; }
protected virtual void OnEditorWindowCloseExecuted(object sender, ExecutedRoutedEventArgs e) { Window window = (Window)sender; PropertyGridProperty prop = window.DataContext as PropertyGridProperty; if (prop != null) { prop.Executed(sender, e); if (e.Handled) { return; } } window.Close(); }
protected virtual void OnSourcePropertyChanged(object sender, PropertyChangedEventArgs e) { if (e == null || e.PropertyName == null) { return; } PropertyGridProperty property = GetProperty(e.PropertyName); if (property != null) { property.RefreshValueFromDescriptor(); OnPropertyChanged(this, CreateEventArgs(property)); } }
public virtual bool?ShowEditor(string propertyName, object parameter) { if (propertyName == null) { throw new ArgumentNullException("propertyName"); } PropertyGridProperty property = GetProperty(propertyName); if (property == null) { return(null); } return(ShowEditor(property, parameter)); }
public static PropertyGridOptionsAttribute FromProperty(PropertyGridProperty property) { if (property == null) { throw new ArgumentNullException("property"); } PropertyGridOptionsAttribute att = property.Options; if (att != null) { return(att); } if (property.Descriptor != null) { att = property.Descriptor.GetAttribute <PropertyGridOptionsAttribute>(); } return(att); }
protected virtual bool CollectionEditorHasOnlyOneColumn(PropertyGridProperty property) { if (property == null) { throw new ArgumentNullException("property"); } var att = PropertyGridOptionsAttribute.FromProperty(property); if (att != null) { return(att.CollectionEditorHasOnlyOneColumn); } if (_collectionEditorHasOnlyOneColumnList.Contains(property.CollectionItemPropertyType)) { return(true); } return(!PropertyGridDataProvider.HasProperties(property.CollectionItemPropertyType)); }
protected virtual void OnBrowseCommandExecuted(object sender, ExecutedRoutedEventArgs e) { var browse = new RoutedEventArgs(BrowseEvent, e.OriginalSource); RaiseEvent(browse); if (browse.Handled) { return; } var property = PropertyGridProperty.FromEvent(e); if (property != null) { property.Executed(sender, e); if (!e.Handled) { ShowEditor(property, e.Parameter); } } }
protected virtual void OnSourcePropertyChanged(object sender, PropertyChangedEventArgs e) { if (e == null || e.PropertyName == null) { return; } PropertyGridProperty property = GetProperty(e.PropertyName); if (property != null) { bool forceRaise = false; var options = PropertyGridOptionsAttribute.FromProperty(property); if (options != null) { forceRaise = options.ForcePropertyChanged; } property.RefreshValueFromDescriptor(true, forceRaise, true); OnPropertyChanged(this, CreateEventArgs(property)); } }
public static DataTemplate SelectTemplate(PropertyGridProperty property, object item, DependencyObject container) { if (property == null) { throw new ArgumentNullException("property"); } PropertyGridOptionsAttribute att = FromProperty(property); if (att == null) { return(null); } if (att.EditorDataTemplateResourceKey != null) { if (Application.Current != null) { DataTemplate dt = (DataTemplate)Application.Current.TryFindResource(att.EditorDataTemplateResourceKey); if (dt != null) { return(dt); } } var fe = container as FrameworkElement; if (fe != null) { var dt = (DataTemplate)fe.TryFindResource(att.EditorDataTemplateResourceKey); if (dt != null) { return(dt); } } return(null); } if (att.EditorType != null) { object editor = Activator.CreateInstance(att.EditorType); if (att.EditorDataTemplateSelectorPropertyPath != null) { var dts = (DataTemplateSelector)DataBindingEvaluator.GetPropertyValue(editor, att.EditorDataTemplateSelectorPropertyPath); return(dts != null?dts.SelectTemplate(item, container) : null); } if (att.EditorDataTemplatePropertyPath != null) { return((DataTemplate)DataBindingEvaluator.GetPropertyValue(editor, att.EditorDataTemplatePropertyPath)); } var cc = editor as ContentControl; if (cc != null) { if (cc.ContentTemplateSelector != null) { DataTemplate template = cc.ContentTemplateSelector.SelectTemplate(item, container); if (template != null) { return(template); } } return(cc.ContentTemplate); } var cp = editor as ContentPresenter; if (cp != null) { if (cp.ContentTemplateSelector != null) { DataTemplate template = cp.ContentTemplateSelector.SelectTemplate(item, container); if (template != null) { return(template); } } return(cp.ContentTemplate); } } return(null); }
protected virtual Window GetEditor(PropertyGridProperty property, object parameter) { if (property == null) { throw new ArgumentNullException("property"); } string resourceKey = string.Format("{0}", parameter); if (string.IsNullOrWhiteSpace(resourceKey)) { var att = PropertyGridOptionsAttribute.FromProperty(property); if (att != null) { resourceKey = att.EditorResourceKey; } if (string.IsNullOrWhiteSpace(resourceKey)) { resourceKey = property.DefaultEditorResourceKey; if (string.IsNullOrWhiteSpace(resourceKey)) { resourceKey = "ObjectEditorWindow"; } } } var editor = TryFindResource(resourceKey) as Window; if (editor != null) { editor.Owner = this.GetVisualSelfOrParent <Window>(); if (editor.Owner != null) { PropertyGridWindowOptions wo = PropertyGridWindowManager.GetOptions(editor); if ((wo & PropertyGridWindowOptions.UseDefinedSize) == PropertyGridWindowOptions.UseDefinedSize) { if (double.IsNaN(editor.Left)) { editor.Left = editor.Owner.Left + ChildEditorWindowOffset; } if (double.IsNaN(editor.Top)) { editor.Top = editor.Owner.Top + ChildEditorWindowOffset; } if (double.IsNaN(editor.Width)) { editor.Width = editor.Owner.Width; } if (double.IsNaN(editor.Height)) { editor.Height = editor.Owner.Height; } } else { editor.Left = editor.Owner.Left + ChildEditorWindowOffset; editor.Top = editor.Owner.Top + ChildEditorWindowOffset; editor.Width = editor.Owner.Width; editor.Height = editor.Owner.Height; } } editor.DataContext = property; Selector selector = LogicalTreeHelper.FindLogicalNode(editor, "EditorSelector") as Selector; if (selector != null) { selector.SelectedIndex = 0; } Grid grid = LogicalTreeHelper.FindLogicalNode(editor, "CollectionEditorListGrid") as Grid; if (grid != null && grid.ColumnDefinitions.Count > 2) { if (property.IsCollection && CollectionEditorHasOnlyOneColumn(property)) { grid.ColumnDefinitions[1].Width = new GridLength(0, GridUnitType.Pixel); grid.ColumnDefinitions[2].Width = new GridLength(0, GridUnitType.Pixel); } else { grid.ColumnDefinitions[1].Width = new GridLength(5, GridUnitType.Pixel); grid.ColumnDefinitions[2].Width = new GridLength(1, GridUnitType.Star); } } var pge = editor as IPropertyGridEditor; if (pge != null) { if (!pge.SetContext(property, parameter)) { return(null); } } } return(editor); }
public virtual bool IsAssignableFrom(Type type, Type propertyType, PropertyGridDataTemplate template, PropertyGridProperty property) { if (type == null) { throw new ArgumentNullException("type"); } if (propertyType == null) { throw new ArgumentNullException("propertyType"); } if (template == null) { throw new ArgumentNullException("template"); } if (property == null) { throw new ArgumentNullException("property"); } if (type.IsAssignableFrom(propertyType)) { // bool? is assignable from bool, but we don't want that match if (!type.IsNullable() || propertyType.IsNullable()) { return(true); } } // hack for nullable enums... if (type == PropertyGridDataTemplate.NullableEnumType) { Type enumType; bool nullable; PropertyGridProperty.IsEnumOrNullableEnum(propertyType, out enumType, out nullable); if (nullable) { return(true); } } var options = PropertyGridOptionsAttribute.FromProperty(property); if (options != null) { if ((type.IsEnum || type == typeof(Enum)) && options.IsEnum) { if (!options.IsFlagsEnum) { return(true); } if (Extensions.IsFlagsEnum(type)) { return(true); } if (template.IsFlagsEnum.HasValue && template.IsFlagsEnum.Value) { return(true); } } } return(false); }
public override DataTemplate SelectTemplate(object item, DependencyObject container) { if (container == null) { throw new ArgumentNullException("container"); } PropertyGridProperty property = item as PropertyGridProperty; if (property == null) { return(base.SelectTemplate(item, container)); } DataTemplate propTemplate = PropertyGridOptionsAttribute.SelectTemplate(property, item, container); if (propTemplate != null) { return(propTemplate); } if (_propertyGrid == null) { _propertyGrid = container.GetVisualSelfOrParent <PropertyGrid>(); } if (_propertyGrid.ValueEditorTemplateSelector != null && _propertyGrid.ValueEditorTemplateSelector != this) { DataTemplate template = _propertyGrid.ValueEditorTemplateSelector.SelectTemplate(item, container); if (template != null) { return(template); } } foreach (PropertyGridDataTemplate template in DataTemplates) { if (Filter(template, property)) { continue; } if (template.IsCollection.HasValue && template.IsCollection.Value) { if (string.IsNullOrWhiteSpace(template.CollectionItemPropertyType) && template.DataTemplate != null) { return(template.DataTemplate); } if (property.CollectionItemPropertyType != null) { foreach (Type type in template.ResolvedCollectionItemPropertyTypes) { if (IsAssignableFrom(type, property.CollectionItemPropertyType, template, property)) { return(template.DataTemplate); } } } } else { if (string.IsNullOrWhiteSpace(template.PropertyType) && template.DataTemplate != null) { return(template.DataTemplate); } foreach (Type type in template.ResolvedPropertyTypes) { if (IsAssignableFrom(type, property.PropertyType, template, property)) { return(template.DataTemplate); } } } } return(base.SelectTemplate(item, container)); }
public PropertyGridEventArgs(PropertyGridProperty property) : this(property, null) { }
public PropertyGridEventArgs(PropertyGridProperty property, object context) { Property = property; Context = context; }
public virtual PropertyGridEventArgs CreateEventArgs(PropertyGridProperty property) { return(ActivatorService.CreateInstance <PropertyGridEventArgs>(property)); }
public virtual IEnumerable BuildItems(PropertyGridProperty property, Type targetType, object parameter, CultureInfo culture) { if (property == null) { throw new ArgumentNullException("property"); } Type enumType; bool nullable; bool isEnumOrNullableEnum = PropertyGridProperty.IsEnumOrNullableEnum(property.PropertyType, out enumType, out nullable); PropertyGridItem zero = null; var att = PropertyGridOptionsAttribute.FromProperty(property); var items = new ObservableCollection <PropertyGridItem>(); if (isEnumOrNullableEnum) { if (nullable) { PropertyGridItem item = CreateItem(); item.Property = property; item.Name = null; // "<unset>"; item.Value = null; item.IsUnset = true; items.Add(item); } string[] names = Enum.GetNames(enumType); Array values = Enum.GetValues(enumType); if (Extensions.IsFlagsEnum(enumType)) { ulong uvalue = EnumToUInt64(property, property.Value); for (int i = 0; i < names.Length; i++) { string name = names[i]; ulong nameValue = EnumToUInt64(property, values.GetValue(i)); string displayName; if (!ShowEnumField(property, enumType, names[i], out displayName)) { continue; } PropertyGridItem item = CreateItem(); item.Property = property; item.Name = displayName; item.Value = nameValue; item.IsZero = nameValue == 0; bool isChecked = true; if (nameValue == 0) { zero = item; } // determine if this name is in fact a combination of other names ulong bitsCount = (ulong)Extensions.GetEnumMaxPower(enumType) - 1; // skip first ulong b = 1; for (ulong bit = 1; bit < bitsCount; bit++) // signed, skip highest bit { string bitName = Enum.GetName(enumType, b); if (bitName != null && name != bitName && (nameValue & b) != 0) { if ((uvalue & b) == 0) { isChecked = false; } } b *= 2; } isChecked = (uvalue & nameValue) != 0; item.IsChecked = isChecked; items.Add(item); } // determine if the lisbox is empty, which we don't want anyway if (items.Count == 0) { PropertyGridItem item = CreateItem(); item.Property = property; item.Name = DefaultZeroName; item.Value = 0; item.IsZero = true; items.Add(item); } if (uvalue == 0 && zero != null) { zero.IsChecked = true; } } else { for (int i = 0; i < names.Length; i++) { string displayName; if (!ShowEnumField(property, enumType, names[i], out displayName)) { continue; } PropertyGridItem item = CreateItem(); item.Property = property; item.Name = displayName; item.Value = values.GetValue(i); item.IsZero = i == 0; // first one is default items.Add(item); } } } else { if (att != null && att.IsEnum) { bool manualFlags = false; // either EnumList or EnumValues can be null but not both // if not null, length must be the same if (att.EnumNames == null || att.EnumNames.Length == 0) { if (att.EnumValues == null || att.EnumValues.Length == 0) { return(items); } att.EnumNames = new string[att.EnumValues.Length]; for (int i = 0; i < att.EnumValues.Length; i++) { att.EnumNames[i] = string.Format("{0}", att.EnumValues[i]); } } else { if (att.EnumValues == null || att.EnumValues.Length != att.EnumNames.Length) { att.EnumValues = new object[att.EnumNames.Length]; if (att.IsFlagsEnum) { ulong current = 1; // don't use zero when nothing is specified in flags mode manualFlags = true; for (int i = 0; i < att.EnumNames.Length; i++) { att.EnumValues[i] = current; current *= 2; } } else { for (int i = 0; i < att.EnumNames.Length; i++) { att.EnumValues[i] = string.Format("{0}", att.EnumNames[i]); } } } } // items value must of a compatible type with property.Value Func <object, object> valueConverter = (v) => { Type propType = property.Value != null?property.Value.GetType() : property.PropertyType; if (v == null) { if (!propType.IsValueType) { return(null); } return(Activator.CreateInstance(propType)); } Type vType = v.GetType(); if (propType.IsAssignableFrom(vType)) { return(v); } return(ConversionService.ChangeType(v, propType)); }; if (att.IsFlagsEnum) { ulong uvalue = EnumToUInt64(property, property.Value); for (int i = 0; i < att.EnumNames.Length; i++) { ulong nameValue = EnumToUInt64(property, att.EnumValues[i]); PropertyGridItem item = CreateItem(); item.Property = property; item.Name = att.EnumNames[i]; item.Value = valueConverter(att.EnumValues[i]); if (manualFlags) { item.IsZero = i == 0; } else { item.IsZero = nameValue == 0; } bool isChecked = true; if (nameValue == 0) { zero = item; } // note: in this case, we don't support names as a combination of other names ulong bitsCount = (ulong)GetEnumMaxPower(att) - 1; // skip first ulong b = 1; for (ulong bit = 1; bit < bitsCount; bit++) // signed, skip highest bit { if ((uvalue & b) == 0) { isChecked = false; } b *= 2; } isChecked = (uvalue & nameValue) != 0; item.IsChecked = isChecked; items.Add(item); } // determine if the list is empty, which we don't want anyway if (items.Count == 0) { PropertyGridItem item = CreateItem(); item.Property = property; item.Name = DefaultZeroName; item.Value = valueConverter(0); item.IsZero = true; items.Add(item); } if (uvalue == 0 && zero != null) { zero.IsChecked = true; } } else { for (int i = 0; i < att.EnumNames.Length; i++) { PropertyGridItem item = CreateItem(); item.Property = property; item.Name = att.EnumNames[i]; item.Value = valueConverter(att.EnumValues[i]); item.IsZero = i == 0; // first one is default items.Add(item); } } } } var ctx = new Dictionary <string, object>(); ctx["items"] = items; property.OnEvent(this, ActivatorService.CreateInstance <PropertyGridEventArgs>(property, ctx)); return(items); }
public static ulong EnumToUInt64(PropertyGridProperty property, object value) { if (property == null) { throw new ArgumentNullException("property"); } if (value == null) { return(0); } Type type = value.GetType(); if (type.IsEnum) { return(Extensions.EnumToUInt64(value)); } TypeCode typeCode = Convert.GetTypeCode(value); switch (typeCode) { case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: return((ulong)Convert.ToInt64(value)); case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: return(Convert.ToUInt64(value)); } var att = PropertyGridOptionsAttribute.FromProperty(property); if (att == null || att.EnumNames == null) { return(0); } string svalue = string.Format("{0}", value); ulong ul; if (ulong.TryParse(svalue, out ul)) { return(ul); } var enums = ParseEnum(svalue); if (enums.Count == 0) { return(0); } foreach (string name in enums) { int index = IndexOf(att.EnumNames, name); if (index < 0) { continue; } ulong ulvalue = Extensions.EnumToUInt64(att.EnumValues[index]); ul |= ulvalue; } return(ul); }