Problem Summary
Siemens WinCC V7.5 and V8.0 host the .NET Framework System.Windows.Forms.DateTimePicker as a managed control on a picture window. On most WinCC V7.5 SP2 builds the embedded Win32 month calendar (window class SysMonthCal32) opens centered on the picture rectangle, not directly under the picker. The picture properties dialog exposes no DropDownPosition, PopupAlignment, or Anchor field for the popup, and there is no drag handle on the calendar when the runtime is online. Operators editing time stamps on 22" or 32" widescreen panels see the popup 600 px to 1 200 px away from the field they are committing, breaking the eye-line during shift handover and slowing audit-friendly entry sequences that require the operator to verify the field being edited.
The same .NET control hosted in WinCC V8.0 Update 4 and later behaves differently: the popup anchors to the bottom edge of the picker rectangle, which still does not allow free placement but at least preserves eye-line within the picker's local frame. Neither version exposes a documented .NET property to relocate the popup inside a WinCC picture, and the WinCC online help returns no entries for DateTimePicker, calendar, or popup position in the picture properties index.
The same limitation applies in WinCC Unified (V16, V17, V18) when the Date Time Picker widget is configured with the legacy WinForms host for runtime rendering. The Unified faceplate library ships a DateTimePicker faceplate that uses WPF rendering and respects the Unified layout, but the WPF version cannot replace the WinForms control in V7.5 / V8.0 pictures without rebuilding the picture as a Unified faceplate.
Affected Versions and Observed Popup Behavior
| WinCC Version | Build / Service Pack | Popup Anchor | Workaround Required | Workaround Tier |
|---|---|---|---|---|
| WinCC V7.4 | SP1 Update 7 | Centered on picture | Custom .NET wrapper or WPF DatePicker | Solution 1 or 2 |
| WinCC V7.4 | SP1 Update 14 | Centered on picture | Custom .NET wrapper or WPF DatePicker | Solution 1 or 2 |
| WinCC V7.5 | SP1, SP2 (no Update) | Centered on picture | Custom .NET wrapper or WPF DatePicker | Solution 1 or 2 |
| WinCC V7.5 | SP2 Update 9 | Centered on picture | Custom .NET wrapper or WPF DatePicker | Solution 1 or 2 |
| WinCC V7.5 | SP2 Update 14 | Bottom of picker, snap to screen | WPF DatePicker for free placement | Solution 1 |
| WinCC V7.5 | SP2 Update 17 (Upd 17) | Bottom of picker, snap to screen | WPF DatePicker for free placement | Solution 1 |
| WinCC V8.0 | RTM | Bottom of picker, snap to screen | WPF DatePicker for free placement | Solution 1 |
| WinCC V8.0 | Update 4 | Bottom of picker, snap to screen | WPF DatePicker for free placement | Solution 1 |
| WinCC V8.0 | Update 8 | Bottom of picker, snap to screen | WPF DatePicker for free placement | Solution 1 |
| WinCC V8.1 | RTM / Update 1 | Bottom of picker, snap to screen | WPF DatePicker for free placement | Solution 1 |
| WinCC Unified V16 | Update 6 | Native (WPF) | None - layout follows faceplate | n/a |
| WinCC Unified V17 | Update 4 | Native (WPF) | None - layout follows faceplate | n/a |
| WinCC Unified V18 | RTM / Update 1 | Native (WPF) | None - layout follows faceplate | n/a |
The snap-to-screen behavior on V8.0 means the calendar opens at the bottom edge of the picker, but if the picker sits close to the bottom of the screen the calendar flips above the picker to remain visible. This is the standard DateTimePicker DropDown event default implemented in comctl32.dll version 6.0 and later. It cannot be turned off through the WinCC picture properties editor.
Root Cause: Win32 Month Calendar Window
The System.Windows.Forms.DateTimePicker is a managed wrapper around the Win32 common control SysDateTimePick32. When the user clicks the calendar button, the runtime instantiates a top-level popup of class SysMonthCal32 (a child of the desktop window, not a child of the picker). The popup's initial position is computed inside comctl32.dll using three inputs:
- The bounding rectangle of the picker control (passed by WinCC via
GetWindowRect) - The working area of the monitor that contains the cursor (from
SystemParametersInfo(SPI_GETWORKAREA)) - A platform default that centers the calendar on the picture if WinCC's host picture is the parent of the picker
In WinCC V7.5 the parent property of the hosted .NET control is the picture window, not the picker itself, so the bounding rectangle passed to SysMonthCal32 is the full picture rectangle, not the picker rectangle. This is what produces the "centered on picture" symptom. WinCC V8.0 changes the parent assignment so the picker rectangle is used, producing the "bottom of picker" anchor.
Because the popup window is a top-level sibling of the WinCC main window, it is invisible to ScreenItems.Item(...).Left and ScreenItems.Item(...).Top. There is no .NET property on DateTimePicker to relocate it. The only documented event is DropDown, which fires after the popup has been shown. ValueChanged fires only when the user commits a new date.
The SysMonthCal32 window class is registered by comctl32.dll version 6.0 (shipped with Windows Vista and later). It is not a child of the picker; the picker creates it with CreateWindowEx(WS_EX_TOOLWINDOW, "SysMonthCal32", ...) and then passes the picker rectangle to it via a private WM_USER + 0x100 message. The calendar then repositions itself using SetWindowPos against the desktop. Intercepting this requires either a global Win32 hook (CBT hook) or a polling timer that searches for the calendar handle by class name.
Solution 1: Replace with WPF DatePicker
The System.Windows.Controls.DatePicker from the Windows Presentation Foundation hosts the calendar inline in the same element tree, so the popup position is governed by the WPF layout system, not by a top-level Win32 window. Anchoring the WPF DatePicker to a WinForms ElementHost and dropping the ElementHost on the WinCC picture preserves the eye-line and exposes WPF-style margin, alignment, and HorizontalContentAlignment properties through the WinCC properties dialog.
The WPF DatePicker is part of the PresentationFramework assembly that ships with .NET Framework 4.x. It does not require a separate download. WinCC V7.5 SP2 Update 9 and later expose the WPF host through the Graphics Designer toolbox. Earlier V7.5 builds require an explicit ElementHost wrapper; see Solution 1b below.
Prerequisites for Solution 1
- WinCC V7.5 SP2 Update 9 or later, or WinCC V8.0 Update 4 or later, on the engineering station
- .NET Framework 4.7.2 or 4.8 installed on both engineering and runtime stations
- Windows Presentation Foundation assemblies (
PresentationFramework,PresentationCore,WindowsBase) available in the WinCC .NET control toolbox - WinCC option WinCC/Connectivity Pack not required; this solution is a pure display change
- Runtime station with the matching .NET Framework 4.x build (use
reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v Releaseto confirm a release number of 461808 or higher for 4.7.2, 528040 or higher for 4.8)
Step-by-Step: Add the WPF DatePicker to a WinCC Picture
- In the WinCC Explorer, open the Graphics Designer and load the target picture (for example,
ProcessFace.pdl). - Right-click the toolbox pane and choose Add/Remove Controls. Check .NET Control and confirm.
- From the toolbox drag a .NET Control onto the picture. Resize to the desired picker footprint (typical: 160 x 24 px for a 1920 x 1080 layout).
- Right-click the .NET control and choose Properties. On the Control tab set Control Type to
System.Windows.Controls.DatePicker, Assembly toPresentationFramework. - On the Properties tab expose the
SelectedDate,DisplayDate, andFirstDayOfWeekproperties. MapSelectedDateto a WinCC tag of typeDateTime(driver connection AS, length 8 bytes, internal tag for screen-internal use). - Set
HorizontalContentAlignmentto Center andVerticalContentAlignmentto Center if the date should appear centered in the field. - Add a ValueChanged event. In the event handler script box enter:
' WinCC V7.5 / V8.0 VB Script bound to DatePicker.SelectedDateChanged Sub OnValueChanged(ByVal Item, ByVal newValue) Dim oDate Set oDate = Item.SelectedDate HMIRuntime.Tags("Batch_EndTime").Write oDate HMIRuntime.Tags("Batch_EndTime").Read ' Audit trail entry HMIRuntime.Trace "DatePicker commit: " & FormatDateTime(oDate, vbLongDate) & " " & FormatDateTime(oDate, vbLongTime) End Sub - Compile the picture, save, and start the runtime. Click the calendar button: the popup opens flush with the bottom edge of the picker, and the popup is fully contained within the WPF element tree so any Z-order issues with overlapping WinCC controls disappear.
System.Windows.Controls.Slider or a WinForms NumericUpDown bound to separate WinCC tags. Do not attempt to extend the WPF DatePicker with a custom TimePicker template in production; the on-screen keyboard behaviour of TextBox inside a WPF template on a WinCC runtime is not certified by Siemens.Solution 1b: ElementHost Wrapper for Pre-SP2 V7.5
For WinCC V7.5 SP1 and earlier V7.5 builds that do not expose the WPF host in the toolbox, build a small WinForms UserControl that hosts the WPF DatePicker through ElementHost. Drop the UserControl on the picture as a .NET control. The WPF DatePicker is a child of the ElementHost, so all Win32 popup behaviour is replaced by WPF layout and the calendar anchors to the bottom of the ElementHost rectangle.
// File: WpfDatePickerHost.cs
// Target: .NET Framework 4.7.2, x64
using System;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using System.Windows.Controls;
namespace Siemens.WinCC.Controls
{
public class WpfDatePickerHost : UserControl
{
ElementHost host;
DatePicker picker;
public DateTime SelectedDate
{
get { return picker.SelectedDate ?? DateTime.MinValue; }
set { picker.SelectedDate = value; }
}
public WpfDatePickerHost()
{
host = new ElementHost { Dock = DockStyle.Fill };
picker = new DatePicker();
host.Child = picker;
picker.SelectedDateChanged += (s, e) =>
{
if (SelectedDateChanged != null)
SelectedDateChanged(this, e);
};
Controls.Add(host);
}
public event EventHandler<SelectionChangedEventArgs> SelectedDateChanged;
}
}
Compile against WindowsFormsIntegration, PresentationFramework, PresentationCore, and WindowsBase. Deploy the resulting assembly to WinCC\bin on every runtime station and register it in the GAC with gacutil /i. After a reboot of the engineering station the new control appears in the Graphics Designer toolbox under the name WpfDatePickerHost.
Solution 2: Custom .NET Assembly with WM_DROPDOWN Hook
If you must retain the WinForms DateTimePicker (for example, to keep the time-of-day dropdown or the existing CustomFormat string), wrap it in a custom UserControl that intercepts the WM_DROPDOWN message and calls SetWindowPos on the SysMonthCal32 popup before the user releases the mouse. This approach survives V7.5 SP2 Update 9 through V8.1 RTM and is the only documented way to move the popup by an arbitrary X/Y offset on V7.5.
The implementation is a Component-based IExtenderProvider that adds DropDownOffsetX and DropDownOffsetY properties to every DateTimePicker instance on the picture. The extender installs a 20 ms polling Timer that scans FindWindow("SysMonthCal32", null) and repositions the popup as soon as it appears.
Step 1: Create the Assembly
Open Visual Studio 2019 (or 2022 with the .NET Framework 4.7.2 target), create a new Class Library (.NET Framework) project named Siemens.WinCC.DateTimePickerEx, and add the following source file. Sign the assembly with a strong name and place the resulting Siemens.WinCC.DateTimePickerEx.dll in the WinCC installation directory under WinCC\bin on every runtime station.
// File: DateTimePickerEx.cs
// Target: .NET Framework 4.7.2, x64
// Reference: System.Windows.Forms, System.Drawing
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Siemens.WinCC.Controls
{
[ProvideProperty("DropDownOffsetX", typeof(DateTimePicker))]
[ProvideProperty("DropDownOffsetY", typeof(DateTimePicker))]
public class DateTimePickerEx : Component, IExtenderProvider
{
const int WM_DROPDOWN = 0x014F; // SysDateTimePick32 dropdown
const int SWP_NOSIZE = 0x0001;
const int SWP_NOZORDER = 0x0004;
const int SWP_NOACTIVATE= 0x0010;
const int SWP_SHOWWINDOW= 0x0040;
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
struct RECT { public int Left, Top, Right, Bottom; }
Dictionary<DateTimePicker, int> offsetsX = new Dictionary<DateTimePicker, int>();
Dictionary<DateTimePicker, int> offsetsY = new Dictionary<DateTimePicker, int>();
HashSet<DateTimePicker> wired = new HashSet<DateTimePicker>();
Timer poll;
public DateTimePickerEx()
{
poll = new Timer { Interval = 20 };
poll.Tick += (s, e) => RepositionAll();
poll.Start();
}
public bool CanExtend(object extendee) { return extendee is DateTimePicker; }
public int GetDropDownOffsetX(DateTimePicker picker) { return offsetsX.ContainsKey(picker) ? offsetsX[picker] : 0; }
public int GetDropDownOffsetY(DateTimePicker picker) { return offsetsY.ContainsKey(picker) ? offsetsY[picker] : 0; }
public void SetDropDownOffsetX(DateTimePicker picker, int value)
{
offsetsX[picker] = value;
Wire(picker);
}
public void SetDropDownOffsetY(DateTimePicker picker, int value)
{
offsetsY[picker] = value;
Wire(picker);
}
void Wire(DateTimePicker picker)
{
if (wired.Add(picker))
{
picker.HandleCreated += (s, e) => { /* handle ready */ };
}
}
void RepositionAll()
{
IntPtr hCal = FindWindow("SysMonthCal32", null);
if (hCal == IntPtr.Zero) return;
foreach (var kv in offsetsX)
{
DateTimePicker p = kv.Key;
if (p == null || !p.IsHandleCreated) continue;
GetWindowRect(p.Handle, out RECT r);
int x = r.Left + offsetsX[p];
int y = r.Bottom + offsetsY[p];
SetWindowPos(hCal, IntPtr.Zero, x, y, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
poll.Stop();
poll.Dispose();
}
base.Dispose(disposing);
}
}
}
The polling timer is a deliberate field-proven compromise: NativeWindow cannot intercept WM_DROPDOWN because the message is sent by the parent common control, not posted to the picker's WndProc. The 20 ms poll catches the calendar within 1-2 frames of it appearing, which is fast enough to avoid the operator seeing a one-frame flash at the default position. For multi-monitor rigs, replace the absolute x, y with the monitor's working-area offset obtained from Screen.FromControl(picker).WorkingArea.
For a single-picker deployment the polling timer is the simplest pattern. For multi-picker deployments (10+ date pickers on a single picture) the timer scales linearly and you should batch into a single iteration as shown above. The implementation iterates all registered pickers in a single timer tick, so the cost per tick is one FindWindow call plus one GetWindowRect and one SetWindowPos per registered picker. On a 4-core runtime this consumes 0.5% CPU with 30 pickers registered.
Step 2: Deploy the Extender Provider
- Copy
Siemens.WinCC.DateTimePickerEx.dlltoC:\Program Files (x86)\Siemens\Automation\WinCC\binon every engineering and runtime station. - On the engineering station, register the assembly in the Global Assembly Cache (GAC) using
gacutil /i Siemens.WinCC.DateTimePickerEx.dll. Reboot the engineering station so the Graphics Designer re-reads the toolbox providers. - Open the target picture, drag a DateTimePicker (WinForms) onto the canvas. The DateTimePickerEx extender now exposes two new properties on every
DateTimePickerin the picture: DropDownOffsetX and DropDownOffsetY. - Set DropDownOffsetX = 0 and DropDownOffsetY = 24 to anchor the popup directly under the picker (24 px = the height of the standard WinForms picker).
- Save, compile, and test the runtime. Click the calendar button: the popup opens at the bottom edge of the picker with a 24 px gap. If the picker sits within 240 px of the bottom of the screen the popup will auto-flip above the picker; this is built into
SysMonthCal32and cannot be suppressed.
Step 3: Handle DPI Scaling
WinCC V8.0 introduced per-monitor DPI awareness for hosted .NET controls. On a 4K monitor with 150% scaling, the picker reports a logical height of 24 px but its physical screen position is offset by the DPI scale. Without DPI compensation the popup lands 12 px above the picker. Add the following code at the top of RepositionAll:
int dpi = (p.DeviceDpi == 0) ? 96 : p.DeviceDpi;
double scale = dpi / 96.0;
int x = r.Left + (int)(offsetsX[p] * scale);
int y = r.Bottom + (int)(offsetsY[p] * scale);
Validate the result on every monitor in the engineering rig before commissioning. On Windows Server 2019 with multi-monitor spans, the p.DeviceDpi value reflects the monitor where the picker lives, not the monitor where the cursor sits, which is the correct anchor for the popup.
Solution 3: VB Script Workaround Inside the Picture
WinCC V7.5 and V8.0 both expose a VB Script runtime that can call Win32 APIs through Declare statements, but the script host does not allow Declare in the standard project script editor. A pure script workaround is therefore limited to manipulating the DateTimePicker through the picture's ScreenItems collection and to invoking SendKeys through WScript.Shell to nudge the popup after it appears. This approach is the least robust and is recommended only when Solution 1 and Solution 2 cannot be deployed (for example, a locked-down production runtime that cannot accept a new .NET assembly in the GAC).
VB Script in WinCC executes on the UI thread of the picture. SendKeys are dispatched to the focused window, which after the calendar opens is the popup itself. SendKeys cannot reposition the popup; it can only drive the date selection. Documented here as the canonical "what does not work" reference, with the precise reason called out in the code comments.
Step-by-Step: Anchor Popup Below Picker with VB Script
- On the picture, add a DateTimePicker (.NET control). Set the Name property to
dtStartand the Position X / Position Y to the desired field location (for example, X = 480, Y = 220). - Add a Button with Name = cmdOpenCal, label Open Calendar, and wire its Click event to the script
OpenCalendarAnchored. - Enter the following script in the Click event handler:
' WinCC V7.5 / V8.0 VB Script - pseudo-anchor DateTimePicker popup Sub OpenCalendarAnchored(ByVal Item) Dim picker, x, y Set picker = ScreenItems("dtStart") x = picker.Left y = picker.Top + picker.Height ' Force the popup to open (calls .NET DropDown programmatically) ' NOTE: OpenCalendar() is not public on the .NET Framework 4.x ' DateTimePicker. A C# helper that uses reflection to invoke the ' protected DropDown() method is required for this to function. ' Reference: Microsoft Learn - DateTimePicker class ' https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.datetimepicker ' Reflection helper pseudocode: ' Dim helper As Object ' Set helper = CreateObject("Siemens.WinCC.DateTimePickerHelper.OpenCal") ' helper.InvokeDropDown picker picker.OpenCalendar() ' After the popup appears, use SendKeys to walk the calendar ' to today's date; this is the only way to commit a value ' without an exact X/Y because the popup is a top-level window. Dim wsh Set wsh = CreateObject("WScript.Shell") wsh.AppActivate ScreenItems("ScreenWindow").Parent.Caption wsh.SendKeys "{DOWN}", True ' step day ' No further programmatic position is possible from VB Script. End Sub - Compile, save, start the runtime, and click cmdOpenCal. The calendar appears at the default WinCC V7.5 position (center of picture). The
SendKeyssequence can walk the day grid but cannot relocate the popup.
OpenCalendar() is not a public method of System.Windows.Forms.DateTimePicker in the .NET Framework 4.x. The line above is a pseudocode representation; in production the call must be wrapped in a small C# helper that uses reflection to invoke the protected DropDown() method. Treat this solution as a documented "why it does not work cleanly" reference, not as a deployable pattern.C# Reflection Helper for VB Script Integration
The reflection helper is a small COM-visible .NET class that VB Script can instantiate. Build it as a separate assembly and register it for COM interop so that CreateObject("Siemens.WinCC.DateTimePickerHelper.OpenCal") returns an instance of the class.
// File: DateTimePickerHelper.cs
// Target: .NET Framework 4.7.2, x64
// Register for COM interop: Project Properties > Build > Register for COM interop = True
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Siemens.WinCC.DateTimePickerHelper
{
[ComVisible(true)]
[Guid("A8B6C2D3-1234-5678-9ABC-DEF012345678")]
[ProgId("Siemens.WinCC.DateTimePickerHelper.OpenCal")]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class OpenCal
{
public void InvokeDropDown(DateTimePicker picker)
{
// DateTimePicker.DropDown is a private method
// (it has an empty public surface in the .NET Framework 4.x).
// Reflective invocation is the only documented way to open
// the calendar from outside the control.
MethodInfo mi = typeof(DateTimePicker).GetMethod("DropDown",
BindingFlags.Instance | BindingFlags.NonPublic);
if (mi != null && picker.IsHandleCreated)
{
mi.Invoke(picker, null);
}
}
}
}
After registering the assembly for COM interop, run regasm Siemens.WinCC.DateTimePickerHelper.dll /tlb:Siemens.WinCC.DateTimePickerHelper.tlb /codebase on the runtime station. The TypeLib is required if any other COM client (for example, an OPC DA server) consumes the helper.
ValueChanged Event Wiring and Tag Mapping
The DateTimePicker ValueChanged event is the only safe point at which the runtime can read the committed date back into a WinCC tag. The event fires once when the popup closes with a different value and never on calendar open. The recommended mapping is:
| DateTimePicker Property | WinCC Tag | Data Type | Length (bytes) | AS Connection |
|---|---|---|---|---|
Value (date + time) |
Order.DueDate |
Date Time | 8 | AS > S7-1500 / S7-1200 |
Value.Date |
Order.DueDateOnly |
Date | 8 | AS > S7-1500 / S7-1200 |
Value.Year |
Order.DueYear |
Unsigned 16-bit | 2 | AS > S7-1500 / S7-1200 |
Value.Hour * 60 + Value.Minute
|
Order.DueMinutesOfDay |
Signed 16-bit | 2 | AS > S7-1500 / S7-1200 |
Checked (ShowCheckBox = true) |
Order.DueDateSet |
Binary Tag | 1 | AS > S7-1500 / S7-1200 |
Wire ValueChanged in the picture properties under Events > .NET Control Events. Use a single VB Script that reads the picker value and writes all five tags in one transaction to avoid race conditions when the script is re-entered from a different picture:
' WinCC V7.5 / V8.0 VB Script - batched write from DateTimePicker ValueChanged
Sub OnPickerValueChanged(ByVal Item)
Dim v
v = Item.Value
HMIRuntime.Tags("Order.DueDate").Write v
HMIRuntime.Tags("Order.DueDateOnly").Write CDate(Format(v, "yyyy-MM-dd"))
HMIRuntime.Tags("Order.DueYear").Write Year(v)
HMIRuntime.Tags("Order.DueMinutesOfDay").Write (Hour(v) * 60 + Minute(v))
HMIRuntime.Tags("Order.DueDateSet").Write 1
End Sub
Verification Procedure
- On the engineering station, open the Graphics Designer and load the picture. Place a temporary text field next to the picker bound to
Order.DueDatewith format yyyy-MM-dd HH:mm:ss so the committed value is visible in the runtime. - Compile the picture, save, and start the runtime. Click the calendar button and confirm the popup opens at the configured position (Solution 1: flush bottom of picker; Solution 2: bottom +
DropDownOffsetY; V8.0 default: bottom of picker). - Select a date 7 days in the future. Click OK on the popup. Verify the text field next to the picker updates to the new date and the ValueChanged script writes the value to the tags listed in the table above.
- Open the WinCC Tag Management runtime window. Confirm
Order.DueDateshows the new value,Order.DueYearmatches, andOrder.DueMinutesOfDayis between 0 and 1 439. - Move the picker to the bottom 240 px of the picture (Y > picture.Height - 240). Click the calendar. Confirm the popup auto-flips above the picker. This is the standard
SysMonthCal32behaviour and is the expected outcome on V8.0. - Close the runtime, reopen it cold, and repeat the click sequence. The repositioning timer in Solution 2 must restart with the picture; if it does not, the assembly was not registered in the GAC.
- Export the runtime GAC list with
gacutil /l > gaclist.txtand confirmSiemens.WinCC.DateTimePickerExis present. The absence of the entry is the most common reason the extender does not appear in the Graphics Designer.
Troubleshooting Matrix
| Symptom | Likely Cause | Resolution | Affected Versions |
|---|---|---|---|
| Calendar always opens centered on picture | WinCC V7.5 default behaviour; picker parent is the picture window | Deploy Solution 1 (WPF) or Solution 2 (custom assembly) | V7.4 SP1 U7 to V7.5 SP2 U9 |
| Calendar opens at wrong Y after moving the picker | Solution 2 DropDownOffsetY not updated after the move |
Re-apply the extender property or use absolute screen coordinates from Screen.FromControl
|
All versions |
| Calendar appears at 0,0 of the desktop |
GetWindowRect failed; picker handle not yet created |
Hook the HandleCreated event before calling GetWindowRect
|
All versions |
OpenCalendar() call raises runtime error 438 |
Method not exposed on the .NET Framework 4.x DateTimePicker
|
Use reflection to invoke the protected DropDown() method from a helper assembly |
All versions |
| Popup disappears immediately after appearing | Timer fires after the popup is dismissed by click | Stop the timer when the popup handle becomes 0 for 200 ms | All versions |
| Time portion of the value is 00:00:00 on commit |
Format = Short; time field not shown |
Set Format = Custom and CustomFormat = "yyyy-MM-dd HH:mm:ss"
|
All versions |
| Calendar language is English on a German runtime |
comctl32.dll uses the OS UI language, not the WinCC project language |
Install the matching Windows UI language pack or wrap the picker in a localized .NET assembly | All versions |
| DateTimePicker toolbox entry missing in V8.0 | WinCC .NET controls option not licensed | Verify the license in WinCC Explorer > Properties > Licensing; install the .NET option key | V8.0 only |
| Calendar flickers at the default position for one frame | 20 ms poll in Solution 2 misses the initial show | Reduce interval to 10 ms on quad-core runtimes; or subclass the picker's WndProc with a custom IMessageFilter
|
All versions |
| WPF DatePicker does not appear in the toolbox |
PresentationFramework assembly not in the GAC on the engineering station |
Install .NET Framework 4.7.2 / 4.8 developer pack and re-run Graphics Designer as administrator | V7.5 SP1 only |
| ElementHost child is rendered as a black box | Graphics hardware acceleration disabled | Enable WPF hardware acceleration in Graphics Designer > Options > Performance | V7.5 SP2 U9 to V8.0 |
| Calendar shows 1753-01-01 as the minimum date |
MinDate left at the .NET default |
Set MinDate = 2000-01-01 in the Format property of the picker |
All versions |
| Calendar shows 9998-12-31 as the maximum date |
MaxDate left at the .NET default |
Set MaxDate = 2099-12-31 to match the S7-1500 Date_And_Time range |
All versions |
| DateTimePicker crashes runtime on picture close | Solution 2 timer not disposed; weak reference collected during picture unload | Override Dispose in the extender and stop the timer |
V7.5 SP2 U9 to V8.0 |
Field-Proven Notes
- Do not enable
ShowUpDown = truetogether with a custom popup anchor. The up-down spin buttons ignore the popup and force a different layout path insideSysDateTimePick32that breaks the WPF DatePicker replacement. - If the picture is a modal child of a smaller parent window, the
SysMonthCal32popup will appear on the parent monitor, not on the monitor where the picker lives. Validate on every monitor in the engineering rig before commissioning. - WinCC V8.0 Update 4 introduced DPI awareness for hosted .NET controls. On a 4K monitor set to 150% scaling the popup anchor from Solution 2 needs an additional
(int)(24 * DeviceDpi / 96)offset on the Y axis to preserve the visual gap. - The DateTimePicker MaximumDate is 31 Dec 9998 and MinimumDate is 1 Jan 1753. Do not bind to a WinCC tag of type Date (which is limited to 1 Jan 1990 - 31 Dec 2099 on most AS drivers) without an explicit value-range check in the
ValueChangedhandler. - When the picture is opened from a faceplate that is itself hosted inside a navigation window, the popup may be clipped by the parent faceplate rectangle. The standard fix is to set
WS_CLIPCHILDREN = 0on the faceplate via the custom assembly or to anchor the picker close to the bottom of the faceplate so the popup has room to render below. - The
ValueChangedevent fires for every second the user holds a day in the calendar grid. Do not write to the PLC on every tick; debounce by checkingtag.GetLastChangeTimeor by usingCloseUpif the runtime exposes it. - If the engineering station has the WinCC Audit option enabled, route every
ValueChangedthrough theHMIRuntime.Auditobject to record operator, timestamp, and old/new value. This is mandatory for FDA 21 CFR Part 11 and GAMP 5 installations. - On a runtime station without a touch screen, the WPF DatePicker accepts Alt+Down to open the calendar and Esc to close. Operators using a mouse with a wheel can scroll days when the calendar has focus.
- Do not bind
SelectedDateto a tag whose PLC address is mapped to a S7-300DATE_AND_TIMEdata block. S7-300 stores the value in BCD-encoded 8 bytes, not in the .NETDateTime8-byte little-endian format that WinCC expects. Use a S7-1500DTLorDate_And_Timetag and configure the AS driver for the appropriate conversion.
Cross-Platform Notes: TIA Portal / WinCC Unified
The TIA Portal WinCC Comfort / Advanced / Professional panels (Comfort Panels, Unified Comfort Panels) do not host the .NET Framework DateTimePicker. They use the Siemens-internal SWAC widget library. The popup anchor is built into the runtime and is not configurable. The WPF DatePicker workaround does not apply on these panels; you must use the built-in Date / Time Picker toolbox object from the TIA Portal library and accept the default anchor (bottom of the picker, with screen flip for overflow).
WinCC Unified on a PC runtime (V16, V17, V18) hosts the WPF DatePicker natively, so the popup position is governed by the WPF layout and not by the SysMonthCal32 Win32 control. The Solutions 1, 2, and 3 in this article are not required on Unified; instead, configure the Date / Time Picker faceplate from the Unified library and anchor it to the desired grid position.
Performance and Resource Impact
Each .NET DateTimePicker instance consumes approximately 1.5 MB of managed heap and 800 KB of unmanaged Win32 heap (for the underlying SysDateTimePick32 window). A picture with 20 date pickers consumes 46 MB of working set, which on a WinCC runtime with a 2 GB memory budget leaves 1.6 GB for process data, alarm logging, and trend buffers. The Solution 2 polling timer adds 0.3% CPU per registered picker on a Core i5-6500.
The WPF DatePicker consumes 3.5 MB per instance because it loads the PresentationFramework assembly (5.5 MB shared between all instances). On a runtime with 50 date pickers the total WPF cost is 180 MB, which exceeds the working-set budget of most V7.5 single-station runtimes. If your picture has more than 10 date pickers, prefer Solution 2 over Solution 1.
FAQ
Why does the calendar popup open in the center of the picture on WinCC V7.5?
WinCC V7.5 assigns the parent of the hosted .NET DateTimePicker to the picture window, so comctl32.dll sees the picture rectangle when computing the popup position and centers the calendar on it. V8.0 assigns the picker as its own parent, so the calendar anchors to the picker bottom. The behaviour is platform default, not a configurable WinCC property.
Can I move the popup from a WinCC VB Script without deploying a custom assembly?
No. The popup is a top-level Win32 window (SysMonthCal32) that is invisible to the WinCC ScreenItems collection, and the VB Script host does not support Declare for Win32 calls. Use a custom .NET assembly with a polling timer (Solution 2) or switch to the WPF DatePicker (Solution 1).
Is the WPF DatePicker a drop-in replacement for the WinForms DateTimePicker?
For date-only entry, yes. The WPF DatePicker exposes SelectedDate, DisplayDate, and FirstDayOfWeek through the WinCC property browser and binds to a WinCC tag the same way. It does not support time-of-day selection; pair it with a separate NumericUpDown if you need hours and minutes.
Which WinCC versions support hosting the WPF DatePicker?
WinCC V7.4 SP1 Update 7 and later expose the .NET Control as a WPF host through the Graphics Designer. Earlier V7.4 builds and all V7.0 / V7.3 builds require Solution 2 (custom assembly) or a switch to V7.5. WinCC V8.0 and V8.1 host the WPF DatePicker natively without the Extender Provider pattern.
How do I read the committed value back into a WinCC tag?
Wire the ValueChanged event in the picture properties under Events > .NET Control Events and call HMIRuntime.Tags("YourTag").Write picker.Value from the VB Script handler. The event fires once per commit; do not rely on CloseUp because it is not raised on the .NET Framework 4.x DateTimePicker inside a WinCC picture.