Want to control the content of a picklist from another picklist or other ItemType property values? Check the following video to find out how this can be done:
In Update 16, we introduced PickList Source and Settings for extracting PickList values from different sources. Please refer to the PickListProvider blog to learn about it. MicroStation U17 adds API, GetValueFromContext, to achieve workflow as mentioned in the video. This API gets you to the value for a fully qualified accessString from an instance to which GetStandardValues:ecProperty belongs. GetStandardValues has reference to the WIP instance on which StandardValues are requested. In your GetStandardValues implementation, you can use the GetValueFromContext method to get the value of some other property belonging to the same instance of the GetStandardValues "ecProperty" argument. In this blog, you will learn how to use these APIs to achieve a filtered or conditional picklist.
SDK Sample:
Implementation: Step 1: Implement IPickListNetProvider/IPickListProvider :
Managed:
IPickListNetProvider is an abstract class, available under Bentley.DgnPlatformNET namespace in Bentley.DgnPlatformNET.dll. In the class, the constructer sets the unique value of the provider and display label.Implement GetStandardValues() and IsValidSettings(). Use GetValueFromContext() in GetStandardValues() to control picklist values.
/*=================================================================================**//** * This class implements IPickListNetProvider interface. * For CSV based picklists the value extraction will be done here. * @bsiclass Bentley Systems +===============+===============+===============+===============+===============+======*/ class ConditionalPickListProvider : IPickListNetProvider { private IECProperty m_wipProperty = null; //-------------------------------------------------------------------------------------- // @description Constrcutor for PickListCSVNetProvider // @bsimethod Bentley //+---------------+---------------+---------------+---------------+---------------+------ public ConditionalPickListProvider() : base ("ConditionalPickList", "ConditionalPickList") { } //-------------------------------------------------------------------------------------- // @description This function has CSV provider specifc picklist value extraction code. // @bsimethod Bentley //+---------------+---------------+---------------+---------------+---------------+------ public override IList<string> GetStandardValues(DgnFile dgnFile, IECProperty ecProperty, IECPrimitiveType primitiveType) { List <string> values = new List<string>(); //validate provider if (!IPickListNetProvider.GetProviderName(dgnFile, ecProperty).Equals(this.Name)) return values; string providerSettings = IPickListNetProvider.GetProviderSettings(dgnFile, ecProperty); if (!ecProperty.ClassDefinition.Contains(providerSettings)) return values; IECPrimitiveType pType = null; object pValue = this.GetValueFromContext(providerSettings, ref pType); if (pValue == null) return values; string foodType = pValue.ToString().ToLower(); if (foodType == "fruits") values = new List<string>(){"Mango", "Banana", "Apple"}; else if (foodType == "veggis") values = new List<string>() { "Tomato", "Brinjal", "carrot", "corn"}; else if (foodType == "all") values = new List<string>() { "Mango", "Banana", "Apple", "Tomato", "Brinjal", "carrot", "corn"}; else values.Add("sorry no food"); return values; } //-------------------------------------------------------------------------------------- // @description Check picklist settings are valid or not for CSV Provider. // @bsimethod Bentley //+---------------+---------------+---------------+---------------+---------------+------ public override bool IsValidSettings(string providerSettings) { return true; } }
Native:
IPickListProvider is an abstract class, available under Bentley::DgnPlatform namespace in Bentley.DgnPlatform5.dll.In the class, the constructer sets the unique value of the provider and display label.Implement GetStandardValues() and IsValidSettings(). Use GetValueFromContext() in GetStandardValues() to control picklist values.
/*=================================================================================**//** * This class implements IPickListProvider interface. * It will give out filtered values * @bsiclass Bentley Systems +===============+===============+===============+===============+===============+======*/ struct ConditionalPickListProvider : Bentley::DgnPlatform::IPickListProvider { private: static WString _ProviderName; // = L"ConditionalPickListNative"; public: ConditionalPickListProvider (); virtual bool GetStandardValues (DgnFileP dgnFile, ECN::ECPropertyCP ecProperty, ECN::PrimitiveType primitiveType, StandardValuesCollection& values) override; virtual bool IsValidSettings (WCharCP settings) const override; private: bool AddValuesFromDgn (WCharCP pSettings, DgnFileP dgnFile, ECN::PrimitiveType primitiveType, StandardValuesCollection& values); }; /*---------------------------------------------------------------------------------**//** * PickListCSVProvider constructer * @bsimethod Bentley Systems +---------------+---------------+---------------+---------------+---------------+------*/ WString ConditionalPickListProvider::_ProviderName = L"ConditionalPickListNative"; ConditionalPickListProvider::ConditionalPickListProvider () : Bentley::DgnPlatform::IPickListProvider (_ProviderName.c_str ()) { SetDisplayLabel (_ProviderName.c_str ()); } /*---------------------------------------------------------------------------------**//** * This function has CSV provider specifc picklist value extraction code. * @bsimethod Bentley Systems +---------------+---------------+---------------+---------------+---------------+------*/ bool ConditionalPickListProvider::GetStandardValues (DgnFileP dgnFile, ECN::ECPropertyCP ecProperty, ECN::PrimitiveType primitiveType, StandardValuesCollection& values) { ECN::ECValue ecValueProviderName; bool status = IPickListProvider::GetProviderName (ecProperty, ecValueProviderName); if (!status || ecValueProviderName.IsNull () || !_ProviderName.Equals (ecValueProviderName.GetString ())) return false; ECN::ECValue ecValueProviderSetting; status = IPickListProvider::GetProviderSettings (ecProperty, ecValueProviderSetting); if (!status || ecValueProviderSetting.IsNull () || WString::IsNullOrEmpty (ecValueProviderSetting.GetString ())) return false; return AddValuesFromDgn(ecValueProviderSetting.GetString(), dgnFile, primitiveType, values); } /*---------------------------------------------------------------------------------**//** * Check picklist settings are valid or not for CSV Provider. * @bsimethod Bentley Systems +---------------+---------------+---------------+---------------+---------------+------*/ bool ConditionalPickListProvider::IsValidSettings (WCharCP settings) const { return true; } /*---------------------------------------------------------------------------------**//** * Check picklist settings are valid or not for CSV Provider. * @bsimethod Bentley Systems +---------------+---------------+---------------+---------------+---------------+------*/ bool ConditionalPickListProvider::AddValuesFromDgn (WCharCP pSettings, DgnFileP dgnFile, ECN::PrimitiveType primitiveType, StandardValuesCollection& values) { ECN::ECValue filter; values.clear (); if (SUCCESS == this->GetValueFromContext (filter, pSettings)) { if (filter.IsNull () || filter.IsUninitialized ()) return false; WString foodType = filter.GetString(); foodType.ToLower(); if (0 == wcscmp (foodType.c_str(), L"fruits")) { values.push_back (L"Mango"); values.push_back (L"Banana"); values.push_back (L"Grapes"); } else if (0 == wcscmp (foodType.c_str (), L"veggis")) { values.push_back (L"Tomato"); values.push_back (L"Brinjal"); values.push_back (L"carrot"); values.push_back (L"corn"); } else if (0 == wcscmp (foodType.c_str (), L"all")) { values.push_back (L"Mango"); values.push_back (L"Banana"); values.push_back (L"Grapes"); values.push_back (L"Tomato"); values.push_back (L"Brinjal"); values.push_back (L"carrot"); values.push_back (L"corn"); } else { values.push_back(L"Sorry No food"); } } return (values.size () > 0); }
Step 2: Register Provider:Register provider implementation:
bool status = Bentley.DgnPlatformNET.IPickListNetProvider.RegisterProvider(new ConditionalPickListProvider());
s_conditionalPickListProvider = new ConditionalPickListProvider(); Bentley::DgnPlatform::DgnECManager::GetManager ().RegisterPickListProvider (s_conditionalPickListProvider);
Step 3: Create Custom User control by implementing IPickListDataSettings:
Note: UI will be always in Managed code.IPickListDataSettings is an interface available in Bentley.DgnPlatformNET namespace in Bentley.DgnDisplayNet.dll.
XAML:
<UserControl x:Class="PickListProviderManagedExample.ConditionProviderUI" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="ItemType property: "></TextBlock> <TextBox Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" Margin="2" MinWidth="100" Height="25" Text="{Binding AccessString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> </TextBox> <!--<ComboBox Grid.Row="1" Grid.Column="0" MinWidth="100" Height="25" HorizontalAlignment="Stretch" Margin="2"></ComboBox>--> </Grid> </UserControl>
XAML.cs
/*=================================================================================**//** * This class is UserControl class which is used for CSV provider * @bsiclass Bentley Systems +===============+===============+===============+===============+===============+======*/ public partial class ConditionProviderUI : UserControl { internal ConditionProviderVm ViewModel { get; set; } /*---------------------------------------------------------------------------------**//** * Constructor for PickListCSVProvider * @bsimethod Bentley Systems /*--------------+---------------+---------------+---------------+---------------+------*/ public ConditionProviderUI() { InitializeComponent(); ViewModel = new ConditionProviderVm(this); DataContext = ViewModel; } }
ViewModel:
/*=================================================================================**//** * This class implements IPickListDataSettings interface, Bentley.UI.Mvvm.ViewModelBase class. * ViewModel for VS based picklist which will provider Usercontrol. * @bsiclass Bentley Systems +===============+===============+===============+===============+===============+======*/ internal class ConditionProviderVm : Bentley.UI.Mvvm.ViewModelBase, IPickListDataSettings { private DependencyObject m_dependencyObject; private string m_accessString; /// <summary> /// Fully qualified property access string. /// </summary> public string AccessString { set { m_accessString = value; OnPropertyChanged("AccessString"); } get { return m_accessString; } } //-------------------------------------------------------------------------------------- // @description Constrcutor for PickListCSVProvider // @bsimethod Bentley //+---------------+---------------+---------------+---------------+---------------+------ public ConditionProviderVm(DependencyObject d) { m_dependencyObject = d; } //-------------------------------------------------------------------------------------- // @description Conditon to enable/disable UI with apprpriate error message. // @bsimethod Bentley //+---------------+---------------+---------------+---------------+---------------+------ public bool CanShowUIForProperty(CustomProperty customProperty, ITypeDescriptorContext context, out string errorMessage) { errorMessage = string.Empty; return true; } //-------------------------------------------------------------------------------------- // @description Send the string which will be stored as PickList Setting // @bsimethod Bentley //+---------------+---------------+---------------+---------------+---------------+------ public string GetPickListSetting() { return AccessString; } //-------------------------------------------------------------------------------------- // @description Send the UserControl used for CSV provider // @bsimethod Bentley //+---------------+---------------+---------------+---------------+---------------+------ public System.Windows.Controls.UserControl GetUI(CustomProperty customProperty, ITypeDescriptorContext context) { string pickListSettingVal = customProperty.PickListSettings; AccessString = string.IsNullOrEmpty(pickListSettingVal) ? string.Empty : pickListSettingVal; return (System.Windows.Controls.UserControl)m_dependencyObject; } }
4. Register UI class:
IPickListDataSettings csvUI = new ConditionProviderUI().ViewModel; PickListUIManager.Instance.RegisterUI(pickListUIName, csvUI);
5. See it running:
Step 1: Register providers:
Execute following key-ins either for managed or native.
- For managed - mdl Load PickListProviderManagedExample.dll - picklistprovidermanagedexample initializeprovider - picklistprovidermanagedexample initializeui ConditionalPickList - For native - mdl Load PickListProviderManagedExample.dll - mdl load PickListProviderNativeExample - PickListProviderNativeExample InitializeProvider - picklistprovidermanagedexample initializeui ConditionalPickListNative
Step 2: Create DGN picklist.
Open PickList manager. Create DGN picklist with values: All, Fruits, Veggis
Step 3: Create ItemType Library and ItemType with Following Properties
1. FoodType: Text Property. Set DGN picklist as created in step#2.
2. Food: Text property. Select PickList source as ConditionalPickList for managed or ConditionalPickListNative for native sample.
Click the Settings button. And, write "FoodType" in UI.
Step 4: Try Attach item
Open Attach item dialog. You will observe that, if you select FoodType as "Fruit", you will see "Food" values as "Apple, Banana & Mango". And, when you select "FoodType" as "Veggies", you will see "Food" values as "Brinjal, Carrot, Corn and Tomato".
Note: SDK sample should be available starting with the Microstation U17 release.