/// <summary> /// Capture property changes made by the user and return the design time value. /// </summary> /// <param name="item">The model item for a TabControl.</param> /// <param name="identifier">The property that the user is changing the value of.</param> /// <param name="value">The new value that the user is giving the property.</param> /// <returns>The value to set the property to in the designer.</returns> public override object TranslatePropertyValue(ModelItem item, PropertyIdentifier identifier, object value) { if (identifier == MyPlatformTypes.TabControl.SelectedIndexProperty) { // if SelectedIndex has been modified from XAML/PB, we use that as the value for selectedIndex // otherwise we determine the index of active tabItem and return that as the selected Index // TabControl's DMVP gets called when user changes SelectedIndex from XAML/PB and whenever TabControl gets created/recreated. // TabControl gets recreated when its items collection is updated (adding/removing tabs) // **************Scenario 1:TabItem is added/removed // When a tabItem is added or removed, TabItemAdornerProvider updates the selection for TabItems and we want to retain that selection // This is done by updating DesignTimeSelectedIndex value each time selection for Tabitem is updated and we use this value in TabControls DMVP // *************Scenario 2:User hasa updated SelectedIndex value from XAML/PB // Here we want to use the updated value of SelectedIndex that gets passed into TabControl DMVP // To distinguish between the scenario where Tabcontrol is recreated(Scenario 1) and the case where user has simply updated SelectedIndex property value // we maintain another DesignerProperty called as CurrentSelectedIndexValueProperty, which stores current value of SelectedIndex that has been serialized // We compare CurrentSelectedIndexValueProperty with new value that is passed in to determine whether user has updated SelectedIndex from XAML/PB // If this is the case, we should use updated value of SelectedIndex that user has set and update TabItem selection too if (GetCurrentSelectedIndexPropertyValue(item) != (int)value) { // this is Scenario 2: User has updated SelectedIndex value from XAML/PB SetCurrentSelectedIndexPropertyValue(item, (int)value); if (item.Content.Collection != null && (int)value >= 0 && (int)value < item.Content.Collection.Count) { ModelItem tabItem = item.Content.Collection[(int)value]; TabItemDesignModeValueProvider.SetDesignTimeIsSelected(tabItem, true); return(value); } } // If control flows till here, then its Scenario 1: TabItem is added/removed int selectedIndex = GetDesignTimeSelectedIndex(item); if (selectedIndex != -1) { return(selectedIndex); } else if (item.Properties[identifier].IsSet) { return(value); } else { return(0); } } return(base.TranslatePropertyValue(item, identifier, value)); }
/// <summary> /// Get the value of SelectedIndex. /// </summary> /// <param name="item">The model item for a TabControl.</param> /// <returns>SelectedIndex of the TabControl.</returns> public static int GetDesignTimeSelectedIndex(ModelItem item) { int selectedIndex = item.GetDesignerProperty(DesignTimeSelectedIndexProperty); // check if that tab is really active. If not, then return -1 (none of the tabs are active if (item.Content != null && item.Content.Collection.Count > 0 && selectedIndex < item.Content.Collection.Count) { if (TabItemDesignModeValueProvider.GetDesignTimeIsSelected(item.Content.Collection[selectedIndex])) { return(selectedIndex); } } return(-1); }
/// <summary> /// When this TabItem is activated set IsSelected to true. /// </summary> /// <param name="item">A ModelItem representing the adorned element.</param> protected override void Activate(ModelItem item) { if (item != null && item.IsItemOfType(MyPlatformTypes.TabItem.TypeId)) { if (Context != null) { Tool tool = Context.Items.GetValue <Tool>(); if (tool == null || tool.FocusedTask == null) { TabItemDesignModeValueProvider.SetDesignTimeIsSelected(item, true); // activate the tab that has been selected item.View.UpdateLayout(); } } } base.Activate(item); }
/// <summary> /// Set the value of SelectedIndex and raise change notification. /// Make the selected TabItem the Active TabItem. /// </summary> /// <param name="item">Model item for the TabControl.</param> /// <param name="value">The SelectedIndex value.</param> public static void SetDesignTimeSelectedIndex(ModelItem item, int value) { item.SetDesignerProperty(DesignTimeSelectedIndexProperty, value); Util.InvalidateProperty(item, MyPlatformTypes.TabControl.SelectedIndexProperty); ModelProperty content = item.Content; ModelItemCollection tabControlChildCollection = null; // activate the corresponding TabItem if (content != null) { tabControlChildCollection = content.Collection; if (tabControlChildCollection != null && value <= tabControlChildCollection.Count) { TabItemDesignModeValueProvider.SetDesignTimeIsSelected(tabControlChildCollection[value], true); } } }
/// <summary> /// Determine how the control is parented into the TabItem. /// If the control is a TabItem then parent it to the TabControl rather /// than the TabItem (think select, copy, paste a TabItem). /// If the TabItem has content and the content can accept children /// then parent into that and so on. /// </summary> /// <param name="parent">The parent item.</param> /// <param name="childType">The type of child item.</param> /// <returns>Redirected parent.</returns> public override ModelItem RedirectParent(ModelItem parent, Type childType) { _canParent = true; if (parent == null) { throw new ArgumentNullException("parent"); } if (childType == null) { throw new ArgumentNullException("childType"); } // if the tabItem is not activated and/or not within TabControl, // redirect to its parent by returning ourselves. if (parent.IsItemOfType(MyPlatformTypes.TabItem.TypeId) && parent.Parent != null && (!parent.Parent.IsItemOfType(MyPlatformTypes.TabControl.TypeId) || !TabItemDesignModeValueProvider.GetDesignTimeIsSelected(parent))) { _canParent = false; return(parent); } // if element being parented is tabItem then add it as sibling of // existing tabItems inside TabControl - redirect to parent; // else parent this control in TabItem's content, if its Panel. if (ModelFactory.ResolveType(parent.Context, MyPlatformTypes.TabItem.TypeId).IsAssignableFrom(childType)) { _canParent = false; return(parent); } if (parent.Content != null && parent.Content.IsSet) { // if TabItem has a content and if the content is a panel or a contentcontrol, // let the content act as the parent. ModelItem content = parent.Content.Value; if (content != null) { ViewItem contentView = content.View; if (content.View != null) { // if the content is not visible but the tabItem is selected, // Update this TabItems Layout. if (!contentView.IsVisible && TabItemDesignModeValueProvider.GetDesignTimeIsSelected(parent)) { parent.View.UpdateLayout(); } if (contentView.IsVisible && (content.IsItemOfType(MyPlatformTypes.Panel.TypeId) || content.IsItemOfType(MyPlatformTypes.ContentControl.TypeId))) { return(content); } } else { // TabItem has a content already but the content cannot accept parenting right now // so let tabItem's parent take care of parenting. _canParent = false; return(parent); } } } // TabItem doesnt have any content and now tabItem itself acts as the parent. return(base.RedirectParent(parent, childType)); }
/// <summary> /// Parent the given control into the TabControl. /// </summary> /// <param name="parent">The new parent item for child.</param> /// <param name="child">The child item.</param> public override void Parent(ModelItem parent, ModelItem child) { if (parent == null) { throw new ArgumentNullException("parent"); } if (child == null) { throw new ArgumentNullException("child"); } // Clear existing property values that we don't want to apply to the new container. child.Properties[MyPlatformTypes.FrameworkElement.MarginProperty].ClearValue(); child.Properties[MyPlatformTypes.FrameworkElement.HorizontalAlignmentProperty].ClearValue(); child.Properties[MyPlatformTypes.FrameworkElement.VerticalAlignmentProperty].ClearValue(); bool childIsTabItem = child.IsItemOfType(MyPlatformTypes.TabItem.TypeId); // We always accept parenting in TabControl if there is not active focused Task. // If the control being pasted is not TabItem and TabControl is empty (doesnt have any TabItem(s) in it) // then we inject a TabItem with Grid in TabControl and paste the control under consideration in TabItem. // We inject a TabItem also in cases when active TabItem is not capable of parenting concerned control if (!childIsTabItem) { // Based on evaluation done in RedirectParent(), // if any control other than TabItem is being parented to Control in this Parent() call // then we need to add a new Tabitem with Grid in it try { ModelItem newTabItem = ModelFactory.CreateItem(parent.Context, MyPlatformTypes.TabItem.TypeId, CreateOptions.InitializeDefaults); parent.Content.Collection.Add(newTabItem); // activate the newly added tabItem TabItemDesignModeValueProvider.SetDesignTimeIsSelected(newTabItem, true); int index = parent.Content.Collection.Count - 1; // Find a suitable parent for control to be pasted. // Since we always accept parenting for TabControl when there is no active focused task, // we better make sure this works. AdapterService adapterService = parent.Context.Services.GetService <AdapterService>(); if (adapterService != null) { ModelItem targetParent = FindSuitableParent(adapterService, parent, child.ItemType, index); if (targetParent != null) { ParentAdapter parentAdapter = adapterService.GetAdapter <ParentAdapter>(targetParent.ItemType); parentAdapter.Parent(targetParent, child); } else { Debug.Assert(targetParent != null, "Parenting failed!"); } } } catch (Exception ex) { throw new InvalidOperationException("Parenting Failed", ex.InnerException); } } else { // child being added is a TabItem; child.Properties[MyPlatformTypes.TabItem.IsSelectedProperty].ClearValue(); parent.Content.Collection.Add(child); TabItemDesignModeValueProvider.SetDesignTimeIsSelected(child, true); // Activate the newly added tabItem } }