Magnus LindheMagnus Lindhehttp://www.magnuslindhe.com/2016-03-24T16:56:41+01:00Magnus Lindhehttp://www.magnuslindhe.commagnus@org.orgSandra.Snow Atom Generatorhttp://www.magnuslindhe.com/2016/03/default-value-for-language-property-in-wpf-applications/Default value for the Language property in WPF applications<p>Most WPF controls you will use are derived from <a href="https://msdn.microsoft.com/en-us/library/system.windows.frameworkelement(v=vs.110).aspx">FrameworkElement</a> and use the <a href="https://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.language(v=vs.110).aspx">Language</a> property to format values according to the corresponding culture. By setting the default value for this property you get consistent formatting for all controls in your application.</p>
2016-03-23T23:00:00Z2016-03-23T23:00:00Z<p>Most WPF controls you will use are derived from <a href="https://msdn.microsoft.com/en-us/library/system.windows.frameworkelement(v=vs.110).aspx">FrameworkElement</a> and use the <a href="https://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.language(v=vs.110).aspx">Language</a> property to format values according to the corresponding culture. By setting the default value for this property you get consistent formatting for all controls in your application.</p>
<!--excerpt-->
<pre><code>FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
</code></pre>
<p>There are also some controls, or rather elements, in the <a href="https://msdn.microsoft.com/en-us/library/system.windows.documents(v=vs.110).aspx">System.Windows.Documents</a> namespace that you might encounter. One example is <a href="https://msdn.microsoft.com/en-us/library/system.windows.documents.run(v=vs.110).aspx">Run</a>, which can be used inside a <a href="https://msdn.microsoft.com/en-us/library/system.windows.controls.textblock(v=vs.110).aspx">TextBlock</a>. These elements all derive from <a href="https://msdn.microsoft.com/en-us/library/system.windows.frameworkcontentelement(v=vs.110).aspx">FrameworkContentElement</a>. Fine, we just override the default language dependency property on this type as well? Wrong... For some reason this throws an exception so you need to override the property for each derived type that you care about. </p>
<p>In order to get the WPF application to use the formatting provided by the regional settings in Windows I execute this code during startup:</p>
<pre><code>public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
FrameworkContentElement.LanguageProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
}
}
</code></pre>
<p>In this example I am only caring about the <code>Run</code> element, derived from <code>TextElement</code>. You might need to override more properties. </p>
<p>Sadly enough, <a href="https://msdn.microsoft.com/en-us/library/system.windows.dependencyproperty.overridemetadata(v=vs.110).aspx">OverideMetadata</a> will throw an exception if you try to call this method twice. This makes it hard to use this method to let the user change the language at runtime. This has not been a requirement or issue for me so far but there are solutions that can help you out:</p>
<ul>
<li><a href="http://rhyous.github.io/WPFSharp.Globalizer">Wpfsharp.Globalizer</a></li>
<li><a href="https://github.com/SeriousM/WPFLocalizationExtension">WPFLocalizationExtension</a></li>
</ul>
http://www.magnuslindhe.com/2016/03/host-station-port-number-expressed-using-hexadecimal-number/Host station port number is expressed using a hexadecimal number<p>Just a quick reminder to my self in case I make this mistake in the future. The configuration of the built-in ethernet port open settings in GX Developer IEC requires port numbers to be expressed in hex. </p>
<p>This can be confusing if the configured port number only use digits between 0 and 9 like my current configuration. I managed to get confused by this even though the dialog explicitly states that you need to use hexadecimal numbers for the port configuration. </p>
<p><img src="http://www.magnuslindhe.com/images/2016-03-24-built-in-ethernet-port-open-settings-hexadecimal.png" alt="Built-in ethernet port open settings" /></p>
<p>If you take a quick look at it and try to send a request to port 1392 you will not succeed:</p>
<pre><code>client.Open("192.168.0.1", 1392);
client.ReadWords("D0", 1);
</code></pre>
<p>The correct code also needs to use the hexadecimal number:</p>
<pre><code>client.Open("192.168.0.1", 0x1392);
</code></pre>
<p>Or use the correct decimal number:</p>
<pre><code>client.Open("192.168.0.1", 5010);
</code></pre>
2016-03-23T23:00:00Z2016-03-23T23:00:00Z<p>Just a quick reminder to my self in case I make this mistake in the future. The configuration of the built-in ethernet port open settings in GX Developer IEC requires port numbers to be expressed in hex. </p>
<p>This can be confusing if the configured port number only use digits between 0 and 9 like my current configuration. I managed to get confused by this even though the dialog explicitly states that you need to use hexadecimal numbers for the port configuration. </p>
<p><img src="http://www.magnuslindhe.com/images/2016-03-24-built-in-ethernet-port-open-settings-hexadecimal.png" alt="Built-in ethernet port open settings" /></p>
<p>If you take a quick look at it and try to send a request to port 1392 you will not succeed:</p>
<pre><code>client.Open("192.168.0.1", 1392);
client.ReadWords("D0", 1);
</code></pre>
<p>The correct code also needs to use the hexadecimal number:</p>
<pre><code>client.Open("192.168.0.1", 0x1392);
</code></pre>
<p>Or use the correct decimal number:</p>
<pre><code>client.Open("192.168.0.1", 5010);
</code></pre>
http://www.magnuslindhe.com/2016/02/two-cases-of-whenanyvalue/Two cases of WhenAnyValue<p><code>WhenAnyValue</code> is a method on <code>ReactiveObject</code> that can turn <code>INotifyPropertyChanged.PropertyChanged</code> events into an <code>IObservable</code>. </p>
<pre><code>var layerNotes = this
.WhenAnyValue(vm => vm.LayerViewModel)
.Select(vm => vm.Notes)
.ToProperty(this, vm => vm.Notes);
</code></pre>
<p>The code above will actually only push property changes through when the <code>LayerViewModel</code> property is changed. Not when its <code>Notes</code> property changes.</p>
<p>The correct way is to use the complete property chain in the call to <code>WhenAnyValue</code> like the following code:</p>
<pre><code>var layerNotes = this
.WhenAnyValue(vm => vm.LayerViewModel.Notes)
.ToProperty(this, vm => vm.Notes);
</code></pre>
<p>The code above will push property changes containing the content of the <code>LayerViewModel.Notes</code> every time the <code>LayerViewModel</code> property changes or its <code>Notes</code> property changes.</p>
2016-02-16T23:00:00Z2016-02-16T23:00:00Z<p><code>WhenAnyValue</code> is a method on <code>ReactiveObject</code> that can turn <code>INotifyPropertyChanged.PropertyChanged</code> events into an <code>IObservable</code>. </p>
<pre><code>var layerNotes = this
.WhenAnyValue(vm => vm.LayerViewModel)
.Select(vm => vm.Notes)
.ToProperty(this, vm => vm.Notes);
</code></pre>
<p>The code above will actually only push property changes through when the <code>LayerViewModel</code> property is changed. Not when its <code>Notes</code> property changes.</p>
<p>The correct way is to use the complete property chain in the call to <code>WhenAnyValue</code> like the following code:</p>
<pre><code>var layerNotes = this
.WhenAnyValue(vm => vm.LayerViewModel.Notes)
.ToProperty(this, vm => vm.Notes);
</code></pre>
<p>The code above will push property changes containing the content of the <code>LayerViewModel.Notes</code> every time the <code>LayerViewModel</code> property changes or its <code>Notes</code> property changes.</p>
http://www.magnuslindhe.com/2016/02/configure-file-registers-in-qcpu-using-gx-iec-developer/Configure file registers in QCPU using GX IEC Developer<p>If you get the error code 0x4031 when using MC Protocol to communicate with a QCPU it means that you are trying to read or write to a device address that is out of range. You might as, I did, forgot to setup the file registers in GX IEC Developer.</p>
<p><img src="http://www.magnuslindhe.com/..\images\2016-02-16-q-parameter-setting.png" alt="Q Parameter Setting" /></p>
2016-02-15T23:00:00Z2016-02-15T23:00:00Z<p>If you get the error code 0x4031 when using MC Protocol to communicate with a QCPU it means that you are trying to read or write to a device address that is out of range. You might as, I did, forgot to setup the file registers in GX IEC Developer.</p>
<p><img src="http://www.magnuslindhe.com/..\images\2016-02-16-q-parameter-setting.png" alt="Q Parameter Setting" /></p>
http://www.magnuslindhe.com/2016/02/content-before-and-after-tabs-using-dragablz/Content before and after tabs using Dragablz<p>The <code>TabablzControl</code> in <a href="http://dragablz.net/" title="Tearable TabControl for WPF">Dragablz</a> is capable of displaying content before and after the tab headers in a simple way.
Use the <code>HeaderPrefixContent</code> and <code>HeaderSuffixContent</code> properties on <code>TabablzControl</code>. Use <code>HeaderPrefixContentTemplate</code> and <code>HeaderSuffixContentTemplate</code> respectively to provide a template to your content in case it is something else than XAML.</p>
<pre><code><dragablz:TabablzControl HeaderSuffixContent="After">
<TextBlock Text="Tab 1"/>
<TextBlock Text="Tab 2"/>
<dragablz:TabablzControl.HeaderPrefixContent>
<TextBlock>Before</TextBlock>
</dragablz:TabablzControl.HeaderPrefixContent>
<dragablz:TabablzControl.HeaderSuffixContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" ToolTip="You can easily insert content here using HeaderSuffixContent"/>
</DataTemplate>
</dragablz:TabablzControl.HeaderSuffixContentTemplate>
</dragablz:TabablzControl>
</code></pre>
2016-02-07T23:00:00Z2016-02-07T23:00:00Z<p>The <code>TabablzControl</code> in <a href="http://dragablz.net/" title="Tearable TabControl for WPF">Dragablz</a> is capable of displaying content before and after the tab headers in a simple way.
Use the <code>HeaderPrefixContent</code> and <code>HeaderSuffixContent</code> properties on <code>TabablzControl</code>. Use <code>HeaderPrefixContentTemplate</code> and <code>HeaderSuffixContentTemplate</code> respectively to provide a template to your content in case it is something else than XAML.</p>
<pre><code><dragablz:TabablzControl HeaderSuffixContent="After">
<TextBlock Text="Tab 1"/>
<TextBlock Text="Tab 2"/>
<dragablz:TabablzControl.HeaderPrefixContent>
<TextBlock>Before</TextBlock>
</dragablz:TabablzControl.HeaderPrefixContent>
<dragablz:TabablzControl.HeaderSuffixContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" ToolTip="You can easily insert content here using HeaderSuffixContent"/>
</DataTemplate>
</dragablz:TabablzControl.HeaderSuffixContentTemplate>
</dragablz:TabablzControl>
</code></pre>
http://www.magnuslindhe.com/2015/09/reboot-qcpu-plc-after-editing-built-in-ethernet-port-open-settings/Reboot Mitsubishi QCPU PLC after editing built in ethernet port open settings<p>Just a quick reminder that you need to reboot your Mitsubishi QCPU PLC after you have edited and downloaded the ethernet port open settings. </p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-15-reboot-qcpu-plc-after-editing-built-in-ethernet-port-open-settings.gif" alt="Ethernet Diagnostics" /></p>
2015-09-14T22:00:00Z2015-09-14T22:00:00Z<p>Just a quick reminder that you need to reboot your Mitsubishi QCPU PLC after you have edited and downloaded the ethernet port open settings. </p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-15-reboot-qcpu-plc-after-editing-built-in-ethernet-port-open-settings.gif" alt="Ethernet Diagnostics" /></p>
http://www.magnuslindhe.com/2015/09/link-icon-in-google-sheets/Display link icon for hyperlink in Google Sheets<p>Google Sheets can display hyperlinks in cells but sometimes you do not want to see the whole hyperlink in the cell. Why not display a nice icon instead? Let me explain how to do it.</p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-14-link-icon-instead-of-text-url-in-google-sheets.png" alt="Link icon instead of text url" /></p>
<p>The following formula insert a icon that is hyperlinked to an issue on <a href="http://www.gitlab.com" title="GitLab">GitLab</a>. The cell <code>A17</code> should contain the issue number on GitLab. If <code>A17</code> is blank the icon will not be displayed.</p>
<pre><code>=IF(ISBLANK(A17);;HYPERLINK(CONCAT("https://gitlab.com/gitlab-org/omnibus-gitlab/issues/";A17);IMAGE("https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-link.svg")))
</code></pre>
<p>I use the <a href="https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-link.svg">link icon</a> from the <a href="http://zurb.com/playground/foundation-icon-fonts-3">foundicons library</a> hosted on <a href="https://cdnjs.com/">cdnjs</a>.</p>
<p><img src="https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-link.svg" alt="" /></p>
2015-09-13T22:00:00Z2015-09-13T22:00:00Z<p>Google Sheets can display hyperlinks in cells but sometimes you do not want to see the whole hyperlink in the cell. Why not display a nice icon instead? Let me explain how to do it.</p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-14-link-icon-instead-of-text-url-in-google-sheets.png" alt="Link icon instead of text url" /></p>
<p>The following formula insert a icon that is hyperlinked to an issue on <a href="http://www.gitlab.com" title="GitLab">GitLab</a>. The cell <code>A17</code> should contain the issue number on GitLab. If <code>A17</code> is blank the icon will not be displayed.</p>
<pre><code>=IF(ISBLANK(A17);;HYPERLINK(CONCAT("https://gitlab.com/gitlab-org/omnibus-gitlab/issues/";A17);IMAGE("https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-link.svg")))
</code></pre>
<p>I use the <a href="https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-link.svg">link icon</a> from the <a href="http://zurb.com/playground/foundation-icon-fonts-3">foundicons library</a> hosted on <a href="https://cdnjs.com/">cdnjs</a>.</p>
<p><img src="https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-link.svg" alt="" /></p>
http://www.magnuslindhe.com/2015/09/multiple-cpu-configuration-errors/Multiple CPU Configuration errors<p>I am writing a client API in C# for the MELSEC Communication Protocol and wanted to perform a communication test to a PLC. The PLC system I had available was a two CPU system and I used GX IEC Developer to create a simple test program. Since it was a simple communication test to see if the client API was reading and writing devices correctly I was not interested in the second CPU at all.</p>
<p>However, I could not get the PLC program running because of a <code>CPU LAY ERROR</code>. This can be fixed by configuring the correct number of CPU in the system. I then received a <code>MULTI CPU DOWN</code> error which seemed to occur because the default setting is to share memory between multiple CPU. When this setting was removed I got the program running and could proceed with the communication test. </p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-10-multiple-cpu-settings.png" alt="Multiple CPU settings in GX IEC Developer" /></p>
<ul>
<li>Make sure the correct "No. of CPU" is specified.</li>
<li>Make sure the "Host CPU number" is specified</li>
<li>Make sure that "Use multiple CPU high speed transmission" is unchecked. </li>
</ul>
<p>Hopefully this post will be of use to me or somebody else in the future.</p>
2015-09-09T22:00:00Z2015-09-09T22:00:00Z<p>I am writing a client API in C# for the MELSEC Communication Protocol and wanted to perform a communication test to a PLC. The PLC system I had available was a two CPU system and I used GX IEC Developer to create a simple test program. Since it was a simple communication test to see if the client API was reading and writing devices correctly I was not interested in the second CPU at all.</p>
<p>However, I could not get the PLC program running because of a <code>CPU LAY ERROR</code>. This can be fixed by configuring the correct number of CPU in the system. I then received a <code>MULTI CPU DOWN</code> error which seemed to occur because the default setting is to share memory between multiple CPU. When this setting was removed I got the program running and could proceed with the communication test. </p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-10-multiple-cpu-settings.png" alt="Multiple CPU settings in GX IEC Developer" /></p>
<ul>
<li>Make sure the correct "No. of CPU" is specified.</li>
<li>Make sure the "Host CPU number" is specified</li>
<li>Make sure that "Use multiple CPU high speed transmission" is unchecked. </li>
</ul>
<p>Hopefully this post will be of use to me or somebody else in the future.</p>
http://www.magnuslindhe.com/2015/09/install-mitsubishi-easysocket-usb-drivers-on-windows-8/Install Mitsubishi Easysocket USB Drivers on Windows 8<p>After installing GX Works 2 1.501X on my Windows 8 development laptop I found out that I was not able to communicate with the PLC through the USB cable as usual. After some troubleshooting I found out that the Mitsubishi Easysocket USB drivers has not been installed properly:</p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-09-melsec-usb-driver-warning.png" alt="Mitsubishi Easysocker USB Driver not installed correctly on Windows 8" /></p>
<p>This issue can easily be fixed by updating the drivers. Just follow these steps:</p>
<ol>
<li>Open Device Manager</li>
<li>Locate the USB driver named "MELSEC" as depicted in the image above</li>
<li>Right click on the driver and select "Update Driver Software" from the context menu.</li>
<li>Click on "Browse my computer for dirver software"</li>
<li>Browse to the installation directory of Easysocket and select the sub folder "USBDrivers". My location was "C:\Program Files (x86)\MELSOFT\Easysocket\USBDrivers" but it could depend on where GX Works2 was installed.</li>
<li>Click "Install" when Device Manager identifies the driver as "Easysocket USB Drivers" from Mitsubishi Electric Corporation.</li>
</ol>
<p><img src="http://www.magnuslindhe.com/images/2015-09-09-melsec-usb-driver-found.png" alt=""Easysocket USB Drivers" from Mitsubishi Electric Corporation" /></p>
<p>Device Manager should be able to find the driver and update it successfully. When the installation is done the driver should appear with the name "MITSUBISHI Easysocket Driver" like this in Device Manager:</p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-09-melsec-usb-driver-ok.png" alt="Working installation of "Easysocket USB Drivers"" /></p>
2015-09-08T22:00:00Z2015-09-08T22:00:00Z<p>After installing GX Works 2 1.501X on my Windows 8 development laptop I found out that I was not able to communicate with the PLC through the USB cable as usual. After some troubleshooting I found out that the Mitsubishi Easysocket USB drivers has not been installed properly:</p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-09-melsec-usb-driver-warning.png" alt="Mitsubishi Easysocker USB Driver not installed correctly on Windows 8" /></p>
<p>This issue can easily be fixed by updating the drivers. Just follow these steps:</p>
<ol>
<li>Open Device Manager</li>
<li>Locate the USB driver named "MELSEC" as depicted in the image above</li>
<li>Right click on the driver and select "Update Driver Software" from the context menu.</li>
<li>Click on "Browse my computer for dirver software"</li>
<li>Browse to the installation directory of Easysocket and select the sub folder "USBDrivers". My location was "C:\Program Files (x86)\MELSOFT\Easysocket\USBDrivers" but it could depend on where GX Works2 was installed.</li>
<li>Click "Install" when Device Manager identifies the driver as "Easysocket USB Drivers" from Mitsubishi Electric Corporation.</li>
</ol>
<p><img src="http://www.magnuslindhe.com/images/2015-09-09-melsec-usb-driver-found.png" alt=""Easysocket USB Drivers" from Mitsubishi Electric Corporation" /></p>
<p>Device Manager should be able to find the driver and update it successfully. When the installation is done the driver should appear with the name "MITSUBISHI Easysocket Driver" like this in Device Manager:</p>
<p><img src="http://www.magnuslindhe.com/images/2015-09-09-melsec-usb-driver-ok.png" alt="Working installation of "Easysocket USB Drivers"" /></p>
http://www.magnuslindhe.com/2015/08/one-way-of-cancelling-commands-using-reactiveui/One way of cancelling commands using ReactiveUI<p>I was looking for a way to cancel a <code>ReactiveCommand<T></code> in <a href="http://reactiveui.net/" title="ReactiveUI website">ReactiveUI</a> but could not find any good official documentation on this. Instead I came up on <a href="http://stackoverflow.com/a/31636333/966">Gluck's solution on StackOverflow</a> (surprise!).
2015-08-27T22:00:00Z2015-08-27T22:00:00Z<p>I was looking for a way to cancel a <code>ReactiveCommand<T></code> in <a href="http://reactiveui.net/" title="ReactiveUI website">ReactiveUI</a> but could not find any good official documentation on this. Instead I came up on <a href="http://stackoverflow.com/a/31636333/966">Gluck's solution on StackOverflow</a> (surprise!).
<!--excerpt-->
This is one way you can cancel a command using ReactiveUI 6:</p>
<pre><code>public class ThisViewModelCanCancelCommands
{
public ReactiveCommand<Unit> Poll { get; private set; }
public ReactiveCommand<object> Cancel { get; private set; }
private IPoller poller = new Poller(); // Dummy service for example;
public ThisViewModelCanCancelCommands()
{
Poll = ReactiveCommand.CreateAsyncObservable<Unit>(
this.WhenAnyObservable(vm => vm.Poll.IsExecuting).Select(v => v == false), // In order to disable button when executing
_ => Observable.StartAsync(PollHandler).TakeUntil(Cancel)
);
Cancel = this.WhenAnyObservable(vm => vm.Poll.IsExecuting).ToCommand();
}
private Task PollHandler(CancellationToken ct)
{
return poller.RunAsync(ct);
}
}
</code></pre>