= How to ... implement a view = In HeuristicLab contents and views are strictly separated. A view must be derived from `IContentView` and tagged with a `ViewAttribute` and `ContentAttribute`. The reason behind this is, that the `MainFormManager` automatically discovers all classes of type `IContentView` to allow the automatic display of contents by the `MainForm`. {{{#!csharp MainFormManager.MainForm.ShowContent(IContent content); //displays the content with its default view MainFormManager.MainForm.ShowContent(IContent content, Type viewType); //displays the content with the specified view type }}} In addition, there is an specialized control provided that is able to display arbitrary contents, the `ViewHost`. It can be used if the content type is not known during compile time, for example in collection views. In the following the implementation of the `StringConvertibleValueView` will be explaind in detail to describe the core functionality of the view concept in HeuristicLab. The `StringConvertibleValueView` is located in HeuristicLab.Data.View and consists of a label and a textbox. [[Image(StringConvertibleValueView.png)]] == Frame of HeuristicLab views == {{{#!csharp [View("StringConvertibleValue View")] [Content(typeof(IStringConvertibleValue), true)] public partial class StringConvertibleValueView : AsynchronousContentView { public new IStringConvertibleValue Content { get { return (IStringConvertibleValue)base.Content; } set { base.Content = value; } } } }}} First of all, one will notice the two attributes on the `StringConvertibleValueView`. The `ViewAttribute` is responsible for providing an identifier that can be used in the GUI. The second attribute, the `ContentAttribute`, is more important as it states which type of contents can be displayed by the view. The first parameter of the `ContentAttribute` states the displayable content types and the second parameter wheter or not the view should be used per default for this content type. In this example, the `StringConvertibleValueView` can display all contents of type `IStringConvertibleValue` and furthermore is used as a default. It is important that it can only exists one default view per content type, because otherwise it is undecidable which view should be used to display the according content. == Registering content events and updating of controls == {{{#!csharp protected override void DeregisterContentEvents() { Content.ValueChanged -= new EventHandler(Content_ValueChanged); base.DeregisterContentEvents(); } protected override void OnContentChanged() { base.OnContentChanged(); if (Content == null) { valueTextBox.Text = string.Empty; } else valueTextBox.Text = Content.GetValue(); } protected override void RegisterContentEvents() { base.RegisterContentEvents(); Content.ValueChanged += new EventHandler(Content_ValueChanged); } private void Content_ValueChanged(object sender, EventArgs e) { if (InvokeRequired) Invoke(new EventHandler(Content_ValueChanged), sender, e); else valueTextBox.Text = Content.GetValue(); } }}} If a new content is set in a view, first the `DeregisterContentEvents` method is called, afterwards `OnContentChanged` and at last `RegisterContentEvents`. `DeregisterContentEvents` is responsible for deregistering events from the "old" content, and is only called if the old content is not null. `OnContentChanged` the controls in the view must be filled with the properties of the content, in this case the valueTextBox is either populated with the result of `Content.GetValue()` or displays nothing (`String.Empty`) if the content is null. `RegisterContentEvents` is the equivalent to `DeregisterContentEvents` for registering necessary events on the new content object. If the `Content` changes its value the previously registered `Content_ValueChanged` method is called and the value of the `TextBox` is updated. Please keep in mind, that these events are often called asynchronous and therefore, an `InvokeRequired` check with according `Invoke` call is necessary (more information on [http://msdn.microsoft.com/en-us/library/ms171728.aspx thread-safe calls to controls]). == Enabling & Disabling of Controls == Every HeuristicLab view has the two states `Locked` and `ReadOnly` that are used to indicate if an operation is in progress and contents should not be altered, e.g. saving to a file or a running algorithm. Changes to these two properties, as well as content changes, trigger to following overriden method. {{{#!csharp protected override void SetEnabledStateOfControls() { base.SetEnabledStateOfControls(); valueTextBox.Enabled = !Locked && Content != null; valueTextBox.ReadOnly = ReadOnly; } }}} In `SetEnabledStateOfControls` used controls must be adapted according to the current state of the view. If other HeuristicLab views are nested in the current view, no additional handling is necessary, as state changes are automatically propagated by the base class. The Locked state of a view is set if a operation is in progress and !ReadOnly is used if the content object itself indicates that it must not be changed. Most times the enabled property corresponds to the Locked state and additionally to !ReadOnly if not separates handling is provided by the control. == Setting the AutoScaleMode of ContainerControls == To guarantee that HeuristicLab is rendered correctly with different font sizes and language settings (see #1688 for more information), the '''AutoScaleMode''' of ContainerControls has to be set to '''Inherit'''. This property has to be configured in the Visual Studio Windows Forms designer in the properties window for all ContainerControls: [[Image(autoscalemode.png)]] This covers the main parts that must be kept in mind when developing new views for HeuristicLab. You can find the source code of the `StringConvertibleValueView` used as an example attached to this page.