-
CMFCRibbonBar: change tooltips at runtime
Tooltips gets displayed as the string part after the ' ' char of the matching resource. So in case you were wondering why you don't see tooltips in your new ribbon if you use your existing string IDs, add the newline to the string resource. But how to change tooltips of the MFC ribbon bar at runtime?
Using theOnToolTipNotifydoesn't work with the MFC ribbon bar because no IDs are used.But here is a trick to make it work:
Derive a new class from the CMFCRibbonBar class to override the TTN_NEEDTEXT message.class CMyRibbonBar : public CMFCRibbonBar { protected: //{{AFX_MSG(CMyRibbonBar) afx_msg BOOL OnNeedTipText(UINT id, NMHDR* pNMH, LRESULT* pResult); //}}AFX_MSG DECLARE_MESSAGE_MAP() };
Set the TTN_NEEDTEXT message handler.BEGIN_MESSAGE_MAP(CMyRibbonBar, CMFCRibbonBar) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, &CMyRibbonBar::OnNeedTipText) END_MESSAGE_MAP()
The new TTN_NEEDTEXT message handler gets the original tooltip text, modify the text and sends back the new tooltip text. The MFC ribbon bar does not send the resource ID of the tool. Because of this, the tooltips are matched by string content.BOOL CMyRibbonBar::OnNeedTipText(UINT id, NMHDR* pNMH, LRESULT* pResult) { static CString strTipText; // get tooltip text BOOL ret = CMFCRibbonBar::OnNeedTipText(id, pNMH, pResult); LPNMTTDISPINFO pTTDispInfo = (LPNMTTDISPINFO)pNMH; strTipText = pTTDispInfo->lpszText; // modify tooltip text CString strRes; strRes.LoadString(ID_MY_UI_ELEMENT); strRes.TrimLeft(_T(''));
if(strTipText == strRes) { // new content for ID_MY_UI_ELEMENT strTipText = "New tool tip content2nd Line"; pTTDispInfo->lpszText = const_cast
((LPCTSTR)strTipText); } return ret; }To set tooltip for the drop down menus, simply get the element via the ID, and use the
SetToolTipTextAPI. Here is an example on how it is done for the plugins menu in cPicture:// Add the tooltips. for (vector<FunctionPlugin>::const_iterator it = CRegisterFunctionPlugin::s_vec_function_plugin.begin(); it != CRegisterFunctionPlugin::s_vec_function_plugin.end(); ++it) { const UINT i(static_cast<UINT>(it - CRegisterFunctionPlugin::s_vec_function_plugin.begin())); CMFCRibbonBaseElement* pElement = FindByID(ID_FUNCTION_PLUGINS_START + i, FALSE, TRUE); if (pElement) { pElement->SetToolTipText(it->pluginData.desc); } } -
Unix time in PowerShell
The Unix time is the number of seconds since 1 January 1970.
In PowerShell:((Get-Date "02/05/2013") - (Get-Date "01/01/1970")).TotalSeconds1360022400To get back the date from the number of seconds, use:
(Get-Date "01/01/1970").AddSeconds(1360022400)2/5/2013 12:00:00 AM
If your system has a different locale, use the culture specific writing. For example using German ('de-DE'):((Get-Date "05.02.2013") - (Get-Date "01.01.1970")).TotalSeconds1360022400(Get-Date "01.01.1970").AddSeconds(1360022400)Dienstag, 5. Februar 2013 00:00:00
In case you have a format in a locale that is different from your PowerShell locale:$DateTime = [DateTime]::Parse("05/02/2013", [System.Globalization.CultureInfo]'fr-FR') ($DateTime - (Get-Date "01.01.1970")).TotalSecondsNote the difference between french and american date order:
05/02/2013-02/05/2013 -
Redirect HTML pages
Redirect web pages is common practice and often done with the
meta tag refresh, but there are drawbacks and it is not recommended by the W3C. Using aHTTP redirection status codeis preferred, but often simply not practical.
If you have a pagehttp://oldsite.com/project/index.htmland you need a redirect tohttp://mysite.com/project/, you simply place thisindex.htmlinhttp://oldsite.com/project/. In case JavaScript is disabled, the default meta refresh is used as a default:index.html<!DOCTYPE HTML> <html> <head> <title></title> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <meta http-equiv="refresh" content="1; URL=http://mysite.com/project/" /> <script type="text/javascript"> window.location.href = "http://mysite.com/project/" </script> </head> <body> </body> </html> -
IIS - redirect subdomain to a directory
Here is how to redirect a subdomain to a directory using the rewrite rule in IIS. For example, if you like to have subdomain.mysite.com/ point to mysite.com/subdomain/, you simply add the following domain-rewrite rule to
web.config:<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <rewrite> <rules> <rule name="domain-rewrite"> <!-- subdomain.mysite.com/dir/index.html?abc -> mysite.com/subdomain/dir/index.html?abc --> <match url=".*" /> <!-- {R:0} = dir/index.html --> <conditions> <!-- subdomain is the first capture '(.*)' = {C:1} --> <add input="{HTTP_HOST}" pattern="^(?!www)(.*)\.mysite\.com$" /> </conditions> <action type="Rewrite" url="{C:1}/{R:0}" /> </rule> </rules> </rewrite> </system.webServer> </configuration> -
.NET nullable type
A .NET nullable type is a data type accepting a null value.
So how is it different from assigning a null value in C or C++?
In C/C++ a null is a 0.
This is how the null is defined in C/C++:
#define NULL 0The define statement is a text processor directive to use the new defined value in the pre-parsing stage on the source code before the compiler sees it. BTW: Values like true or false are also int:
#define FALSE 0#define TRUE 1But in .NET a null and a 0 are two different values. In C#, basic data types like int or bool are not nullable types by default.
Promoted to a nullable type adds the null. Take for example a bool: The bool type is an enumeration of the two values true and false. A nullable bool adds a null to the set increasing the cardinality to 3.
Useful? Yes, making them a perfect data type to handle the undefined state besides the boolean result.
Nullableflag = null; Or using the short form (T? = nullable
): bool? flag = null;In Windows Powershell:
[nullable[bool]]$flag = $nullNote: extending the value set can change semantics (the meaning) with existing syntax (the form).
The following is not valid anymore because you cannot cast a nullable bool to a bool to evaluate the expression.
Is flag null or false?
if(!flag) { Console.WriteLine("false"); }You need to be specific in the evaluation because squishing a set of 3 values to a set of 2 values in not possible without data loss.
if(flag == false) { Console.WriteLine("false"); }