Know the Top 9 Differences Between Mac and PC

The fight between Mac and PC users is unending. However, right now, both are almost the same, and it is just the type of computer one prefers or can buy. Before starting, it is essential to determine some terms and definitions that we will be using in this article. 

We will compare macOS and MS Windows. PC means a personal computer and can be used for MacBooks as well.

So, let’s see which of the two, Mac or PC, scores better and in what. Go through the below listed 9 differences to find out for yourself.

1. Operating System

Operating System is one of the key differences between Mac and PC. Apple computers have Mac OS installed, while Microsoft PCs have Windows OS installed. Sometime before, Mac had Intel processors, which allowed those computers to run both Mac and Windows OS. This was quite useful for users who required both OS. 

But that model has come to an end in the 2020s, and now these computers do not run Windows OS, driving users to choose between the two or buy one of each. Windows OS by Microsoft runs on computers and tablets. Microsoft, of course, does its best to compete with tech giants. It continues establishing ways to operate among computers, tablets, and phones.

2. Security

Security from viruses and undesired malware is another major difference between Mac and PC. Many users use Windows PCs, and thus PCs are more likely to be attacked. However, this does not signify that Macs are immune to viruses and malware. 

Moreover, mac create zip with password, which is yet another security feature that protects data against unauthorized access. But for sure, a Mac system that does not have any antivirus or anti-malware software installed is comparatively less likely to be attacked as compared to Windows PC.

3. Cost

The cost has also become one of the most important factors when you compare the two. You can get a custom-built PC for one thousand dollars or less, but there is hardly any Mac that falls within that price range. 

However, this doesn’t mean that you need to overspend on a MacBook. It is only that Mac is built with more costly components. For basic functions like web browsing or word processing, the PC is good enough, and the MacBook is difficult to justify.

4. Choice

Whatever be the difference between Macs and PCs, the ultimate thing is the choice of consumers. Mac provides Mac Pro, MacBook Air, MacBook Pro, Mac mini, and Mac to select from. 

Meanwhile, PCs provide desktops and laptops in different shapes, sizes, and storage specifications. Consumers can choose from multiple PC manufacturers such as Asus, Acer, Dell, HP, Gateway, Lenovo, and Samsung, where each offers a different range of options. With this, consumers have a wide range of PCs to select from that suit their needs.

5. Availability

Then comes the availability of PCs and Macs. Though both can be ordered from stores on the Internet, PCs are available in almost all computer stores while Macs are not. This is because Apple, the Mac manufacturer, is quite selective in choosing stores. Macs are not available at many computer stores.

6. Users

Again, Users are ultimately the choosers. So, it all depends on users as to which of the two, Mac or PC, match their needs and which one they opt for. Mac users choose Mac for features such as design, usability, and security. Whereas PC users choose Windows PCs for price and software compatibility.

7. Software 

Yet another big difference between Mac and PC is the software used. One major reason why Mac has not yet been able to capture a larger share of the computer market is the apparent lack of software written for its operating system. 

Most computer gamers are inclined towards PC as a wide range of recreational software is provided for Windows systems. Also, software developers did not want to port their games to the Mac for a long time.

8. Design

Design is also considered a major difference between Mac and Windows PCs. Macs have a unique outward appearance that is difficult to match. At the moment, PCs have a number of designs that range from the space-age aesthetics of gaming PCs to the practical design of business computers. 

Today, many PC manufacturers make slim and sleek PCs to attract consumers, but few have managed to gain popularity as acclaimed by Apple’s Mac computers. Nevertheless, different users have different preferences, and it all depends on which one they wish to purchase.

9. User Satisfaction

User satisfaction is also quite important when it comes to selection between Mac and PC. Though Both Mac and PC providers provide good customer and tech support, it depends on which service one likes and is satisfied with.

In the end, choosing between PC and Mac depends on the user’s specific preferences more than anything else.

How to Hide or Show Console Windows from WPF App

This post shows how to hide or show console window from your WPF app. The use case for this could be when your WPF app triggers some function that makes the console window visible. You might need to hide the console window programmatically from your WPF app.

If you are using a external functions from C++ app in your C# app then that might trigger a console window to be opened. From user’s point of view they won’t like to see the console window. It makes sense to hide the console window. Here’s how it can be done.

Step 1: Add a Native Methods class to expose the external C++ functions

Add the following class to your project.

static class NativeMethods
    {

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        public const int SW_HIDE = 0;
        public const int SW_SHOW = 5;
    }

The DllImport method uses the following namespace.




using System.Runtime.InteropServices;

If the namespace is not available in your project then add a reference to it by using the Add Reference option.

Step 2: Get the console window

To get a reference to the active console window use the following code snippet. You can put the code after the InitializeComponent() call in the constructor of the MainPage.xaml.cs.

var handle = NativeMethods.GetConsoleWindow();

Step 3: Hide or Show the Console Window

To hide the console window use the following code.

// Hide
NativeMethods.ShowWindow(handle, NativeMethods.SW_HIDE);

Similarly to show the console windows use the following code.

// Show
NativeMethods.ShowWindow(handle, NativeMethods.SW_SHOW);

That’s it. Run the project to see if it works.

How to Zoom Image in WPF app

This post shows how to zoom an image in WPF app. The image can be zoomed by rolling the mouse scroller or by double clicking on the image.

Step 1: Add the ZoomBorder Class to the project

Add the following ZoomBorder class to your project.

public class ZoomBorder : Border
    {
        private UIElement child = null;
        private Point origin;
        private Point start;

        private TranslateTransform GetTranslateTransform(UIElement element)
        {
            return (TranslateTransform)((TransformGroup)element.RenderTransform)
              .Children.First(tr => tr is TranslateTransform);
        }

        private ScaleTransform GetScaleTransform(UIElement element)
        {
            return (ScaleTransform)((TransformGroup)element.RenderTransform)
              .Children.First(tr => tr is ScaleTransform);
        }

        public override UIElement Child
        {
            get { return base.Child; }
            set
            {
                if (value != null && value != this.Child)
                    this.Initialize(value);
                base.Child = value;
            }
        }

        public void Initialize(UIElement element)
        {
            this.child = element;
            if (child != null)
            {
                TransformGroup group = new TransformGroup();
                ScaleTransform st = new ScaleTransform();
                group.Children.Add(st);
                TranslateTransform tt = new TranslateTransform();
                group.Children.Add(tt);
                child.RenderTransform = group;
                child.RenderTransformOrigin = new Point(0.0, 0.0);
                this.MouseWheel += child_MouseWheel;
                this.MouseLeftButtonDown += child_MouseLeftButtonDown;
                this.MouseLeftButtonUp += child_MouseLeftButtonUp;
                this.MouseMove += child_MouseMove;
                this.PreviewMouseRightButtonDown += new MouseButtonEventHandler(
                  child_PreviewMouseRightButtonDown);
            }
        }

        public void Reset()
        {
            if (child != null)
            {
                // reset zoom
                var st = GetScaleTransform(child);
                st.ScaleX = 1.0;
                st.ScaleY = 1.0;

                // reset pan
                var tt = GetTranslateTransform(child);
                tt.X = 0.0;
                tt.Y = 0.0;
            }
        }

        #region Child Events

        private void child_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (child != null)
            {
                var st = GetScaleTransform(child);
                var tt = GetTranslateTransform(child);

                double zoom = e.Delta > 0 ? .2 : -.2;
                if (!(e.Delta > 0) && (st.ScaleX < .4 || st.ScaleY < .4))
                    return;

                Point relative = e.GetPosition(child);
                double abosuluteX;
                double abosuluteY;

                abosuluteX = relative.X * st.ScaleX + tt.X;
                abosuluteY = relative.Y * st.ScaleY + tt.Y;

                st.ScaleX += zoom;
                st.ScaleY += zoom;

                tt.X = abosuluteX - relative.X * st.ScaleX;
                tt.Y = abosuluteY - relative.Y * st.ScaleY;
            }
        }

        private void child_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (child != null)
            {
                var tt = GetTranslateTransform(child);
                start = e.GetPosition(this);
                origin = new Point(tt.X, tt.Y);
                this.Cursor = Cursors.Hand;
                child.CaptureMouse();
            }
        }

        private void child_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (child != null)
            {
                child.ReleaseMouseCapture();
                this.Cursor = Cursors.Arrow;
            }
        }

        void child_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.Reset();
        }

        private void child_MouseMove(object sender, MouseEventArgs e)
        {
            if (child != null)
            {
                if (child.IsMouseCaptured)
                {
                    var tt = GetTranslateTransform(child);
                    Vector v = start - e.GetPosition(this);
                    tt.X = origin.X - v.X;
                    tt.Y = origin.Y - v.Y;
                }
            }
        }

        #endregion
    }

Step 2: Use the ZoomBorder class in your XAML page.

Firstly add a reference to the directory in which the ZoomBorder class in located. For example I have added the ZoomBorder class in Utils folder so i add a reference to this folder in the XAML page.

xmlns:utils="clr-namespace:MyProject.Utils"

Next wrap the image inside the ZoomBorder control.




<utils:ZoomBorder x:Name="border" ClipToBounds="True" Background="Gray">
    <Image Source="/myimage.png"/>
</utils:ZoomBorder>

That’s it. Deploy the project to see if it works. 🙂

Write DataGrid to CSV file in WPF app

This post shows how to write a DataGrid in WPF to a CSV file. We will export the data contained in the DataGrid along with the column headers to a CSV file. Here’s how it can be done.

Step 1: Build a CSV string from the DataGrid

Use the following method to convert a DataGrid to a CSV string.

public static string DataTable2CSV(DataGrid table, string separator=",")
{
    object[,] data = table.PrepareData();
    StringBuilder builder = new StringBuilder(Convert.ToString((char)65279));

    for (int k = 0; k < data.GetLength(0); k++)
    {
        List<string> tempList = new List<string>();
        for (int l = 0; l < data.GetLength(1); l++)
            tempList.Add(data[k, l].ToString());
        builder.Append(string.Join(separator, tempList)).Append(Environment.NewLine);
    }
    return builder.ToString();
}

The method accepts a DataGrid name as a parameter and converts it to a comma separated string value.

Step 2: Write the String to a Excel file.

Next write the above generated string to a excel file. The function WriteToXls takes the string to be written as an input and writes its to a excel file. It actually writes a CSV file which is saved with an .xlsx extension. It will open as an Excel file.

private string WriteToXls(string dataToWrite)
{
    try
    {
        string destination = DateTime.Now.ToString("dd_MM_yyyy_HH_mm") + LotNumber;
        foreach (char c in System.IO.Path.GetInvalidFileNameChars())
        {
            destination = destination.Replace(c, '_');
        }
        destination = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + destination + ".xlsx";
        FileStream fs = new FileStream(destination, FileMode.Create, FileAccess.Write);
        StreamWriter objWrite = new StreamWriter(fs);
        objWrite.Write(dataToWrite);
        objWrite.Close();
    }
    catch (Exception ex)
    {
        return null;
    }
}

Step 3: Use the above Methods to write to CSV

Here’s how you can use the above functions to write to CSV.

WriteToXls(DataTable2CSV(myDataGrid, ","));

Note: myDataGrid is the name of the DataGrid present in your XAML page.

Call C-Sharp from javaScript using CefSharp in WPF app

Here’s how you can invoke a C# function from javaScript while using CefSharp in a WPF app.

Step 1: Create a Class with the Method to be Invoked

Create a CallbackObjectForJs class that contains a showMessage function which would be invoked from javascript.

public class CallbackObjectForJs{
    public void showMessage(string msg){//Read Note
        MessageBox.Show(msg);
    }
}

Step 2: Register the JS object

The next step is to register the JS object. This can be done by adding the following code in the MainPage.xaml.cs file.

private CallbackObjectForJs _callBackObjectForJs;
public MainWindow()
{
    InitializeComponent();
    _callBackObjectForJs= new CallbackObjectForJs();
    ChromiumWebBrowser.RegisterAsyncJsObject("callbackObj", _callBackObjectForJs);
}

Step 3: Invoke the C# function from JavaScript

Next, simply invoke the C# function from your javascript code.

<script>
    callbackObj.showMessage("Hello World!");
</script>

Note: The name of the C# function should start with a small letter.

Using Chromium Web Browser Control in WPF app

WebBroswer control in WPF by default uses IE 7 engine for rendering webpages. This may become an issue while displaying modern websites. There are two alternatives. One is to use browser emulation feature to use a different IE version browser instead of IE 7. How that can be done is explained in this post.

Using Browser Emulation for Web Browser control in WPF app

The other way is to use V8 engine(Chromium) used by Google Chrome. There are various libraries that let you use Chromium browser in your WPF project. We will be using the CefSharp library. You can read more about the various options available for using Chromium engine in WPF app.

CefSharp is a C# import for Cef framework. It is available as a Nuget package too.

Step 1: Install the CefSharp library

Install the CefSharp library using nuget. Here’s the link to the Nuget package.
https://www.nuget.org/packages/CefSharp.Wpf

You could refer to this article if you need assistance in adding a Nuget package to your project in Visual Studio.

Initialize the Cef browser in App.xaml.cs

You need to initialize the browser with some default settings. Here’s the code that you need to add in your project’s App.xaml.cs. This is required because of a known issue (#1634) that makes the screen flicker after the page is loaded.

public App()
{  
    //Perform dependency check to make sure all relevant resources are in our output directory.
    var settings = new CefSettings();
    settings.EnableInternalPdfViewerOffScreen();
    // Disable GPU in WPF and Offscreen examples until #1634 has been resolved
    settings.CefCommandLineArgs.Add("disable-gpu", "1");
    settings.CachePath = "cache";
    
    Cef.Initialize(settings, shutdownOnProcessExit: true, performDependencyCheck: true);
}

Add a reference to CefSharp in MainPage.xaml

Add a reference in MainPage.xaml before you could use it.

xmlns:cefSharp="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"

Add the Chromium Web Browser control in your page

Now you can add the web browser control in your page. Here’s the code that is required.

<cefSharp:ChromiumWebBrowser
        x:Name="ChromiumWebBrowser"
        Address="http://www.google.com" />

That’s it you are done. Try deploying the app to see if it works.

Using Browser Emulation for Web Browser control in WPF app

WebBrowser control in WPF by default uses IE 7 browser engine to render webpages. This may not be desired in some situations as modern websites are not rendered correctly on IR 7. You may get other version of IE working with the WebBrowser control using the browser emulation feature in WPF. This is not a trivial thing to do and requires a couple of registry changes. Here’s how it can be done.

Step 1: Define an enum for the Different Browser Versions

We define an enum that contains the different IE browser versions.

public enum BrowserEmulationVersion
{
    Default = 0,
    Version7 = 7000,
    Version8 = 8000,
    Version8Standards = 8888,
    Version9 = 9000,
    Version9Standards = 9999,
    Version10 = 10000,
    Version10Standards = 10001,
    Version11 = 11000,
    Version11Edge = 11001
}

Step 2: Add Browser Emulation class

Add the following class ie InternetExplorerBrowserEmulation class to your project. We will be calling functions from this class to use browser emulation in our project.

public class InternetExplorerBrowserEmulation
{
    private const string InternetExplorerRootKey = @"Software\Microsoft\Internet Explorer";
    private const string BrowserEmulationKey = InternetExplorerRootKey + @"\Main\FeatureControl\FEATURE_BROWSER_EMULATION";


    public static int GetInternetExplorerMajorVersion()
    {
        int result;

        result = 0;

        try
        {
            RegistryKey key;

            key = Registry.LocalMachine.OpenSubKey(InternetExplorerRootKey);

            if (key != null)
            {
                object value;

                value = key.GetValue("svcVersion", null) ?? key.GetValue("Version", null);

                if (value != null)
                {
                    string version;
                    int separator;

                    version = value.ToString();
                    separator = version.IndexOf('.');
                    if (separator != -1)
                    {
                        int.TryParse(version.Substring(0, separator), out result);
                    }
                }
            }
        }
        catch (SecurityException)
        {
            // The user does not have the permissions required to read from the registry key.
        }
        catch (UnauthorizedAccessException)
        {
            // The user does not have the necessary registry rights.
        }

        return result;
    }

    public static bool SetBrowserEmulationVersion(BrowserEmulationVersion browserEmulationVersion)
    {
        bool result;

        result = false;

        try
        {
            RegistryKey key;

            key = Registry.CurrentUser.OpenSubKey(BrowserEmulationKey, true);

            if (key != null)
            {
                string programName;

                programName = Path.GetFileName(Environment.GetCommandLineArgs()[0]);

                if (browserEmulationVersion != BrowserEmulationVersion.Default)
                {
                    // if it's a valid value, update or create the value
                    key.SetValue(programName, (int)browserEmulationVersion, RegistryValueKind.DWord);
                }
                else
                {
                    // otherwise, remove the existing value
                    key.DeleteValue(programName, false);
                }

                result = true;
            }
        }
        catch (SecurityException)
        {
            // The user does not have the permissions required to read from the registry key.
        }
        catch (UnauthorizedAccessException)
        {
            // The user does not have the necessary registry rights.
        }

        return result;
    }

    public static bool SetBrowserEmulationVersion()
    {
        int ieVersion;
        BrowserEmulationVersion emulationCode;

        ieVersion = GetInternetExplorerMajorVersion();

        if (ieVersion >= 11)
        {
            emulationCode = BrowserEmulationVersion.Version11;
        }
        else
        {
            switch (ieVersion)
            {
                case 10:
                    emulationCode = BrowserEmulationVersion.Version10;
                    break;
                case 9:
                    emulationCode = BrowserEmulationVersion.Version9;
                    break;
                case 8:
                    emulationCode = BrowserEmulationVersion.Version8;
                    break;
                default:
                    emulationCode = BrowserEmulationVersion.Version7;
                    break;
            }
        }

        return SetBrowserEmulationVersion(emulationCode);
    }

    public static BrowserEmulationVersion GetBrowserEmulationVersion()
    {
        BrowserEmulationVersion result;

        result = BrowserEmulationVersion.Default;

        try
        {
            RegistryKey key;

            key = Registry.CurrentUser.OpenSubKey(BrowserEmulationKey, true);
            if (key != null)
            {
                string programName;
                object value;

                programName = Path.GetFileName(Environment.GetCommandLineArgs()[0]);
                value = key.GetValue(programName, null);

                if (value != null)
                {
                    result = (BrowserEmulationVersion)Convert.ToInt32(value);
                }
            }
        }
        catch (SecurityException)
        {
            // The user does not have the permissions required to read from the registry key.
        }
        catch (UnauthorizedAccessException)
        {
            // The user does not have the necessary registry rights.
        }

        return result;
    }


    public static bool IsBrowserEmulationSet()
    {
        return GetBrowserEmulationVersion() != BrowserEmulationVersion.Default;
    }
}

Step 3: Use the Browser Emulation class

Finally use the browser emulation class as follows. You could include the code for browser emulation in MainPage.xaml.cs constructor itself.

if (!InternetExplorerBrowserEmulation.IsBrowserEmulationSet())
{
  InternetExplorerBrowserEmulation.SetBrowserEmulationVersion();
}

Note: This works only if you change the browser version before loading any WebBrowser control.

How to Scan an Image using Interop.WIA in a WPF app

This post shows how to scan an image using a scanner in a WPF app.

Step 1: Add a Reference to WIA dll

Firstly, you need a reference to Interop.WIA.dll in the project. Download the dll file from the following link.

Download Interop.WIA.dll

Once you have downloaded the dll file add a reference to it by right click on the project name and selecting Add > Reference.

Add a reference to Interop.WIA.dll

Step 2: Add the ScannerService class to the project

Here’s the complete code for the ScannerService class that you can directly include in your project.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using WIA;

namespace WPF_Example.Services
{
    public class ScannerService
    {
        public static void Scan()
        {
            try
            {
                CommonDialogClass commonDialogClass = new CommonDialogClass();
                Device scannerDevice = commonDialogClass.ShowSelectDevice(WiaDeviceType.ScannerDeviceType, false, false);
                if (scannerDevice != null)
                {
                    Item scannnerItem = scannerDevice.Items[1];
                    AdjustScannerSettings(scannnerItem, 600, 0, 0, 1010, 620, 0, 0);
                    object scanResult = commonDialogClass.ShowTransfer(scannnerItem, WIA.FormatID.wiaFormatPNG, false);
                    if (scanResult != null)
                    {
                        ImageFile image = (ImageFile)scanResult;
                        SaveImageToJpgFile(image, Constants.ScannedImageLocation);
                     }
                }
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                MessageBox.Show("Problem with scanning device. Please ensure that the scanner is properly connected and switched on", "Inweon Grain Management System");
            }
        }

        private static void AdjustScannerSettings(IItem scannnerItem, int scanResolutionDPI, int scanStartLeftPixel, int scanStartTopPixel,
            int scanWidthPixels, int scanHeightPixels, int brightnessPercents, int contrastPercents)
        {
            const string WIA_HORIZONTAL_SCAN_RESOLUTION_DPI = "6147";
            const string WIA_VERTICAL_SCAN_RESOLUTION_DPI = "6148";
            const string WIA_HORIZONTAL_SCAN_START_PIXEL = "6149";
            const string WIA_VERTICAL_SCAN_START_PIXEL = "6150";
            const string WIA_HORIZONTAL_SCAN_SIZE_PIXELS = "6151";
            const string WIA_VERTICAL_SCAN_SIZE_PIXELS = "6152";
            const string WIA_SCAN_BRIGHTNESS_PERCENTS = "6154";
            const string WIA_SCAN_CONTRAST_PERCENTS = "6155";
            const string WIA_SCAN_BIT_DEPTH = "4104";
            SetWIAProperty(scannnerItem.Properties, WIA_HORIZONTAL_SCAN_RESOLUTION_DPI, scanResolutionDPI);
            SetWIAProperty(scannnerItem.Properties, WIA_VERTICAL_SCAN_RESOLUTION_DPI, scanResolutionDPI);
            SetWIAProperty(scannnerItem.Properties, WIA_HORIZONTAL_SCAN_START_PIXEL, scanStartLeftPixel);
            SetWIAProperty(scannnerItem.Properties, WIA_VERTICAL_SCAN_START_PIXEL, scanStartTopPixel);
            //SetWIAProperty(scannnerItem.Properties, WIA_SCAN_BIT_DEPTH, 48);
            SetWIAProperty(scannnerItem.Properties, WIA_SCAN_BRIGHTNESS_PERCENTS, brightnessPercents);
            SetWIAProperty(scannnerItem.Properties, WIA_SCAN_CONTRAST_PERCENTS, contrastPercents);
        }

        private static void SetWIAProperty(IProperties properties, object propName, object propValue)
        {
            Property prop = properties.get_Item(ref propName);
            prop.set_Value(ref propValue);
        }

        private static void SaveImageToJpgFile(ImageFile image, string fileName)
        {
            ImageProcess imgProcess = new ImageProcess();
            object convertFilter = "Convert";
            string convertFilterID = imgProcess.FilterInfos.get_Item(ref convertFilter).FilterID;
            imgProcess.Filters.Add(convertFilterID, 0);
            SetWIAProperty(imgProcess.Filters[imgProcess.Filters.Count].Properties, "FormatID", WIA.FormatID.wiaFormatJPEG);
            image = imgProcess.Apply(image);
            image.SaveFile(fileName);
        }
    }
}

Use the Scan function

To use ScannerService simply use the following code.

ScannerService.Scan();

What Is a Universal Windows Platform (UWP) App?

The concept of a common application architecture was first introduced in Windows 8 as the Windows Runtime. Windows Runtime (WinRT) was an evolution of the Windows app model, intended to be a common application architecture. When Windows Phone 8.1 became available, the Windows Runtime was aligned between Windows Phone 8.1 and Windows. This enabled developers to create Universal Windows 8 apps that target both Windows and Windows Phone, using a shared codebase. This article introduces you to the Universal Windows Platform.

Introduction

Windows 10 introduces the Universal Windows Platform (UWP), which further evolves the Windows Runtime model and brings it to the Windows 10 unified core. As part of the core, the Universal Windows Platform now provides a common app platform available on every device that runs Windows 10.

Apps that target the Universal Windows Platform can call not only the WinRT APIs that are common to all devices but also APIs (including Win32 and .NET APIs) that are specific to the device family the app is running on.

The Universal Windows Platform provides a guaranteed core API layer across devices. This means you can create a single app package that can be installed on a wide range of devices.

1. Device Families

Windows 8.1 and Windows Phone 8.1 apps target an operating system (OS), Windows or Windows Phone. With Windows 10, an app no longer targets an operating system. Instead, an app targets one or more device families.

A device family identifies the APIs, system characteristics, and behaviors that you can expect across devices within the device family. It also determines the set of devices on which your app can be installed from the Store.

The decision which device family (or families) your app will target determines:

  • the set of APIs that your app can assume to be present when it runs.
  • the set of API calls that are safe only inside conditional statements. To isolate sections of code that are platform-specific, use the #ifdef directive.
  • the set of devices on which your app can be installed from the Store.

Here are some considerations to help you decide which device family to target:

  • Target the universal device family to reach the maximum range of devices.
  • Choose to target your app at one of the child families if it is specialized for, for example, a desktop PC or Xbox.
  • Target two (or more) child device families instead of targeting the universal device family.
  • In some cases, you may want your app to run everywhere except on devices with a particular version of a particular device family.

By default, Microsoft Visual Studio specifies Windows.Universal as the target device family in the app package manifest. To specify the device families for your app, manually configure the TargetDeviceFamily element in the Package.appxmanifest file.

2. User Interface and Universal Input

Windows helps you target your user interface to multiple devices with the following features:

Universal Controls and Layout Panels

Windows 10 includes new controls, such as the calendar and split view. Controls have been updated to work well on larger screens, adapt themselves based on the device’s screen resolution, and work well with multiple input types, such as keyboard, mouse, touch, pen, and controllers, such as the Xbox controller.

To help you adapt the user interface of an app based on the amount of available screen space, Windows 10 introduces adaptive panels and design states.

The new RelativePanel implements a style of layout that is defined by the relationships between its child elements. It is intended for use in creating app layouts that can adapt to changes in screen resolution.

Visual State Triggers

Your app’s user interface may need to adapt to changes in window size. Adaptive visual states allow you to change the visual state in response to changes in the size of the window.

State triggers define a threshold at which a visual state is activated, which then sets layout properties appropriate for the window size that triggered the state change. Here is the XAML for the visual state triggers described above.

Windows 10 introduces an evolution of the existing scaling model. In addition to scaling vector content, there is a unified set of scale factors that provides a consistent size for user interface elements across a variety of screen sizes and display resolutions.

You can build a universal Windows app using universal controls that handle various inputs, such as a mouse, keyboard, touch, pen, and controller (such as the Xbox controller).

3. Writing Code

Your programming language options for your Windows 10 project in Visual Studio include Visual C++, C#, Visual Basic, and JavaScript. For C# and Visual Basic, you can use XAML for a full-fidelity, native user interface experience.

For Visual C++, you can choose to draw with either or use XAML. For JavaScript, your presentation layer will be HTML. Let’s look at these different cases.

Whenever you want to call an API, you’ll need to know whether the API is implemented by the device family that your app is targeting. If you want to call just a small number of APIs, you could use the ApiInformation.IsTypePresent method like this.

A UWP app or Windows Runtime Component is written in C++/CX has access to the Win32 APIs that are part of the UWP. These Win32 APIs are implemented by all Windows 10 device families. Windowsapp.lib is an umbrella lib that provides the exports for the UWP APIs. Linking to Windowsapp.lib will add to your app dependencies on DLLs that are present on all Windows 10 device families.

4. User Experience

A UWP app allows you to take advantage of the unique capabilities of the device on which it is running. It provides a set of built-in features and universal building blocks that make it much easier to create a great user experience for multiple devices.

You can still have one app package that runs on all devices by checking what device family your app is running on before calling an extension API. Here are some of the features that you get when you create a UWP app:

  • When your app runs on a Windows-powered device, the system uses an algorithm to normalize the way controls, fonts, and other UI elements display on the screen. This scaling algorithm takes into account viewing distance and screen density to optimize for perceived size.
  • Although you can design for specific input devices, apps use an input system that uses “smart” interactions. That means that you can design around a click interaction without having to know whether the click comes from an actual mouse click or the tap of a finger.
  • The UWP provides a set of universal controls that are guaranteed to work well on all Windows-powered devices. These controls are input-aware and deploy with the proper set of input affordances, event states, and overall functionality for each device family.
  • Your UWP app automatically gets a default set of styles which can be customized to give your app a personal touch, or can be replaced completely to create a unique visual experience.

Conclusion

Here are some of the characteristics that make UWP apps on Windows 10 different:

  • You target device families, not an OS. A device family identifies the APIs, system characteristics, and behaviors that you can expect across devices within the device family. It also determines the set of devices on which your app can be installed from the store.
  • All UWP apps are distributed as a .appx package, providing a trustworthy installation mechanism and ensures that the apps can be deployed and updated seamlessly.
  • There’s one store for all devices. You can submit and manage all your apps for Windows devices in one place.
  • The UWP core APIs are the same for all Windows device families. App using only the core APIs will run on any Windows 10 device.
  • Extension SDKs are specialized APIs for each device family, which can be used if the app is intended for a particular device family.
  • UI elements use effective pixels, so they automatically adapt themselves based on the number of screen pixels available on the device.

How to Calculate the Difference in Months Between two Dates C#

This code snippet lets you calculate the difference in months between two dates.

If all you want is simply a difference in the months -completely disregarding the date values- then you can use this:

public static int MonthDifference(this DateTime lValue, DateTime rValue)
{
    return (lValue.Month - rValue.Month) + 12 * (lValue.Year - rValue.Year);
}

Note that this returns a relative difference, meaning that if rValue is greater than lValue, then the return value will be negative. If you want an absolute difference, you can use this:

public static int MonthDifference(this DateTime lValue, DateTime rValue)
{
    return Math.Abs((lValue.Month - rValue.Month) + 12 * (lValue.Year - rValue.Year));
}