Quantcast
Channel: Infragistics Community
Viewing all 2223 articles
Browse latest View live

Synchronize items, folders or entire SharePoint lists with SharePlus 4.1.2

$
0
0

In the latest release of SharePlus 4.1.2, you get the ability to keep information locally in your device, allowing you to access information even without an internet connection to SharePoint. This means that you could, for example, open and edit a document stored in SharePoint when visiting a client, regardless of their location or network connectivity. This significant advantage comes with the obvious consequence of having to synchronize your content later with the server. But SharePlus has that covered!

Synchronization Made Easy

To optimize both performance and disk storage capacity, your content is not available by default while offline. In order to navigate your information while disconnected, you must turn on the Offline Support capability for that content.

With the latest release of SharePlus for iOS, version 4.1.2, you can keep any specific content you wish offline. You can even choose to activate the Offline Support per item, per folder or for the entire list as well.


Tweaking the Synchronization Process

In this latest update, the whole SharePlus synchronization experience works even smoother than before, while also providing two flexible and well-rounded approaches to sync your information: Per Item and View Based.


Per Item (default)

Using this new mode, you can synchronize only the content marked to be synchronized. You choose whether to activate it per item, per folder, or you can even select the whole list.

Note: Lists configured with the old Browsed sync mode are switched to the new Per Item mode. All the browsed items belonging to those lists will be automatically synchronized.


View Based (former Background)

In this release, the Background sync mode has been renamed to View Based, but its functionality remains the same. This mode synchronizes all the list items based on a SharePoint List View, such as All DocumentsAll Items, or By Author. This means that while disconnected, you will be able to navigate all the items available in the list view.

We hope you enjoy the latest version of SharePlus! If you have any questions or feedback, or would like to schedule a demo, please don't hesitate to contact us. We look forward to hearing from you!


Five interesting facts about Microsoft F#

$
0
0

Since its 2005 conception at a Microsoft Research Center, use of the F# language has seen steady growth among developers both in the Open Source Community and for enterprise applications. Because it combines safe, simple and robust coding with the option of application on practically any operating system, it makes for an interesting proposition with developers seeking simple solutions to complex problems.

Many consider F# particularly suitable to scientific or big data based applications, but it is actually good when applied to a whole host of problems and applications. Characterized as a functional programming language with strong typing, it is able to express a developer's ideas in a succinct and declarative way.

However, while growing in popularity, F# is a long way from universal adoption. In this post we’re going to look in more detail at what makes F# different and why it might be you worth getting to know better.

1. The importance of community

F# has been open source for years now and as a result there is a strong, friendly and open community behind the language. Development is supported with numerous groups around Europe, the US and beyond with often hundreds of users in each. Members are working collaboratively on everything from fun to finance

Importantly, the community is active - essential for new users with lots of questions - and it has a pragmatic approach to finding solutions. When dealing with complaints and queries about F#, there’s a dedicated group of individuals making serious efforts to build libraries and to advance and improve the language’s capabilities. The backing of such an active community means problems and limits of the code can be solved more rapidly.

2. Five wins for functional programming

F# has some really nice properties, and these five points capture its unique strengths.

  • Concise. F# is a pretty clean language, without a lot of the excess markup of other languages - forget all those curly brackets and semicolons! It has a powerful inference system and it takes less lines of code to solve the same problem as its sister language, C#
  • Simple. The language is designed to simplify a broad range of programming tasks, including creation and use of complex type definitions and comparison operations.
  • Defensive. Developers can sleep easy in the knowledge that F# offers a powerful type systems and thus helps to prevent a lot of common coding errors. For example null references simply aren’t possible with F# (in C# they can cause all kinds of hard to diagnose bugs) and you can therefore feel confident that your coding will contain fewer problems.
  • Concurrent. A real advantage of F# is that it makes asynchronous and parallel programming easy with a number of useful built-in libraries.
  • Compatible. F# was written, in part, to make up for the failures of C# and other similar functional languages. Nonetheless it still allows for compatibility with C#, among other languages.

3. Practical application in a variety of industries

While it began as an academic research project, F# offers practical applications in numerous industries. It’s being increasingly used in finance, gaming, mobile and web development testing, among others. What makes it particularly applicable in these markets is that it has made the switch from an object-oriented to a functional paradigm, and this is more suitable for advanced calculations and manipulations with data. Enterprise apps, especially those focused on manipulating vast quantities of data, can really benefit.

This makes it a really useful language to learn for developers hoping to work in these fields - a solid knowledge of F# will give you a cutting edge over the competition when applying for jobs in these fields.

4. Universal

F# is a high level language and runs well in Linux, Mac OS X, Android, iOS, Windows, GPUs and all browsers - thanks to the trusty .NET Framework. This makes it a great choice because it makes for one simple code available on a broad range of systems and applications. Your developments will consequently be widely applicable.

5. Fun to use

Besides all these practical considerations, let’s not forget that programming can be fun too! Developers highlight time and time again that F# offers an enjoyable, satisfying and relatively stress-free method of writing code. The fact that F# makes writing easier, more concise and less noisy code means you can spend more time designing your projects and less time tinkering.

Hitting the right note

At Infragistics, we’re passionate about developing tools which are secure, straightforward and widely applicable. F# is therefore music to our ears; as a language which helps developers easily write diverse applications.

In an increasingly complex market, with ever more platforms and operating systems, languages which help simplify the process of development across different systems are definitely appealing. F# looks likely to grow and we’re keeping an eye firmly fixed on it.

Infragistics Channel Partner Spotlight: Lifeboat Distribution

$
0
0

In this month’s Channel Partner Spotlight, we’ll take a look at longtime Infragistics channel partner Lifeboat Distribution: a specialty software distributor with a commitment to personalized, friendly, and efficient service.

Known as experts in software for virtualization, security, application lifecycle management, database infrastructure and management, application and network infrastructure, business productivity, and other technically sophisticated products, Lifeboat’s team of energetic, creative professionals help their vendor partners recruit and build multinational solution provider networks. They take pride in being able to power those networks and drive incremental sales revenues that complement their existing sales channels, too.

Worldwide, Lifeboat services thousands of solution providers, systems integrators, VARs, corporate resellers, and consultants, helping them power a rich opportunity stream through exemplary service, targeted leads, and focused selling technical support. The trusted channel navigator also helps resellers expand margin+ services revenues through outsource access to reliable technical engagement services, and builds profitable product and service businesses through tailored market development and promotional opportunities.

With a network of offices in the United States, Canada and The Netherlands, Lifeboat is a knowledgeable, efficient distribution partner that will help initialize, promote, and build the businesses of its partners. Be sure to check them out on Facebook, YouTube, and LinkedIn, and follow them on Twitter too!

How is Microsoft going to replace InfoPath forms in SharePoint?

$
0
0

In January 2014, Microsoft announced that InfoPath 2013 would be the final version of its form building tool. According to Microsoft, industry trends and feedback from customers and partners made it clear that today’s businesses demand an intelligent, integrated forms experience that spans devices.

Microsoft is looking to make investments that allow you to easily design, deploy, and use intelligent, integrated forms across Office clients, servers, and services—forms that everyone can use on their PC, tablet, or phone. Their goal is to deliver tools that are flexible and agile, so you can quickly connect to your data and processes in new and exciting ways. Interestingly Microsoft has not announced a replacement just yet and still advises customers to use InfoPath. The InfoPath 2013 client application will be supported until April 2023. InfoPath forms services for SharePoint 2013 will be supported until April 2023 and InfoPath forms services in Office 365 will be supported until further notice.

InfoPath is an application for building complex business forms. In combination with SharePoint you can design, distribute and maintain forms in your organization. Users can use InfoPath forms services (of the client application InfoPath filler) to fill out the forms.

InfoPath allowed a business or power user to build forms. It enabled the use of external data sources, conditional formatting or, as a developer, the writing of code in forms. That said, InfoPath also had some limitations, so its demise isn’t necessarily a bad thing. In this post we will look at the alternatives to InfoPath.

Forms on SharePoint List (FoSL)

With FoSL there will be a button in the ribbon that enables the (power) user to modify the form in their browser. This will be a lightweight way of making modifications and can be compared to what is often done in InfoPath. It is still unclear if data connections or web service calls will be available. The first demo's of FoSL were very promising but the roadmap is somewhat unclear - there is no release date yet.

Using FoSL gives the power user an easy and quick way to modify their forms. Any business user with sufficient permissions could change the look of the form without installing additional (third party) software. The drawback is that is it still unclear what options will be available. The first demo's were able to edit list forms only and untrained users could do some harm with this solution.

Excel and Access Online services / forms

An already existing way of creating forms is by using Excel services. The forms on spreadsheets use a plain Excel worksheet as backend to store the data you enter. Each form is linked to one spreadsheet. Using Excel as backend makes it easy for business users to stay in their trusted environment. Everyone that can handle Excel can handle the data. When the data is in Excel it is a small step to create powerful visualizations with the data entered in the form. Compared to InfoPath, the Excel forms can only handle very basic logic and there is no option to brand the form.

Next to Excel there are also the Access Apps. You can use Access to build self contained apps with tables and relational data. Building forms is done within the Access application. Access forms can handle relational data and transactions and are rather easy to build, although this approach is not ideal for single lists. It is best suited for self contained apps.

Nintex forms

Nintex Forms is the forms solution of one of the big players in the SharePoint ecosystem. They have a web-based form designer where you can easily build your custom forms and publish them to your SharePoint environment. All these forms can be consumed on most mobile devices from the internet, anywhere and at any time. Nintex forms also integrate well with their Nintex Workflow solutions so that you can build nice forms around your business processes.

The forms solution is built on top of SharePoint so an additional client application is not needed as it uses the same technology as SharePoint. With Nintex forms no knowledge of HTML of JavaScript is needed to build forms and forms are built with drag and drop in the browser. Nintex is a third party tool and needs some investment effort but can have a quick ROI because of its ease of use.

Custom .NET forms

The options mentioned above don’t always fulfill user expectations. As developers it is possible to build custom forms with Visual Studio and publish them to your SharePoint environment. Within these forms all the available .NET libraries can be used on top of the one in the SharePoint object model. When complex forms are needed this is the way to go. Custom forms are highly extensible and reusable and within Visual Studio every technology can be used. As any custom made solution there is the concern about maintainability. Every feature request will result in the need of a developer. This is a major concern when outsourcing these custom form development tasks.

There’s still time to decide

At present it is still somewhat unclear how you can replace InfoPath or if you even need to replace it. Microsoft have announced some valuable replacement options but none of them can really replace InfoPath just yet. Microsoft have promised to announce more news about this topic in Q1 2015.

There are some good third party solutions out there and some build-in solutions that are almost ready too. If your form solution is likely to be there for a long time and need frequent updates then you should choose a new track. However, if the solution is small or very clear then InfoPath is still the right option for you.

Bringing a Mobile SharePoint solution to Your Enterprise

$
0
0

Like SharePlus itself, you have many options when bringing this mobile SharePoint solution to your users’ fingertips. We’ve built SharePlus Enterprise with your business needs in mind, and as such, you’ll be able to securely connect to your SharePoint data thanks to the multiple configurations, security, and deployment options presented here. Let’s explore these options in greater detail:

Connectivity

When connecting to SharePoint, SharePlus takes advantage of several network architectures, which ensures a secure communication through:

  • HTTPS protocol
  • VPNs or MDM-provided tunneling
  • Firewalls, Load Balancers and Proxies (including reverse proxies)
  • SharePoint’s authentication mechanisms including support for Custom Login Forms, Windows, Forms based and Office 365 authentication methods.

Security

To maintain the protection of your data, top-grade security measures are built directly into SharePlus at each layer. For example, the app comes with the following features:

For data at rest:

  • Apple’s iOS Data Protection, which augments the AES 256-bit encryption by requiring a user’s passcode to access data inside the device.
  • Secure Data Wipe, which removes all data from a mobile device without destroying the internal storage, based on triggers such as failed passcode-entry attempts when administrators activate Passcode Lock (described below).

For data in motion:

    • Support for virtual private network (VPN) connectivity through built-in VPN support or an MDM solution.
    • Support for Secure Sockets Layer (SSL), a standard protocol for transmitting data via the Internet.
    • A valuable optional feature is Passcode Lock, which automatically prompts users to enter a four-digit code to open the app when it goes to background or after a specified amount of idle time.
    • SharePlus Authentication, in which user authentication protects access to the app and can be achieved through the combination of several mechanisms, including SharePoint’s authentication mechanisms and the passcode lock feature.
    • Authorization through server permissions grants access to SharePoint resources such as lists and documents through the user’s SharePoint credentials.
    • Application security policies Based on security rules, many restrictions over SharePlus functionality can be included, trimming features like copy/paste or Wi-Fi sharing, specifying the extent of site administration for users, or even restricting the apps that can interact with SharePlus.

Configuration and Optimization

SharePlus Enterprise enables IT Managers to centrally manage the application’s behavior and match corporate and user needs for optimal usage and security, including configuration options around:

  • Look and Feel – change the language, adjust the color and behavior of specific UI components, or go further and personalize the whole SharePlus experience with your brand.
  • Security – set up common Enterprise settings like passcode lock, VPN, or authentication mode, and also advanced security policies like secure data wipe, client-side certificates, data extraction restrictions.
  • App features – turn app features on/off and fine-tune their settings, for example, you can include pre-configured sites and accounts, MDM integration, adjust deployment settings, disable or enable support for specific external editors, and more.
  • App behavior – configure offline settings, the navigation visibility, different visualizations for lists and sites, the networking layer, among others.
  • Personalized views of the information – affecting both app behavior and the look and feel, you are able to configure launchpads to present a customized view for any site or the SharePlus start screen. Launchpads greatly enrich the user experience and display dynamic content from SharePoint such as announcements, events and news, or any other content from the server, even while a user is offline.

Installation / Deployment

From the get-go, setup is a breeze. A corporate IT administrator may enable users to install SharePlus on their smartphones and tablets through:

  1. A corporate mobile device management (MDM) application store. In this method, the user finds SharePlus in the company’s application store and downloads the app.   
  2. A download page on the company’s intranet. If the company uses a Web page to distribute SharePlus, the user may navigate to the installation page from a mobile device and tap the “Install Application” button.
  3. A mailed download link. In this instance, the company may provide the link in an email or text message. The user then clicks on the link or pastes it into a browser to reach the corporate download page and follows instructions described there.  

Once the app is configured, an employee can access, edit and share data and documents on SharePoint, both online or offline. That means they are able to securely view, modify and graphically display content spanning files, lists, calendars, intranets, emails, libraries, announcements, discussion boards and more.

Support

Need help? SharePlus has you covered. Simply tap the Help Center on the application’s sidebar to access In-App Help Documentation, including an FAQ and information on using SharePlus offline. 

And to troubleshoot issues, the Log Recorder generates records that a user can send to the company’s IT helpdesk. The corporate IT staff, in turn, can easily contact the award-winning Infragistics Support Team for assistance.

Conclusion

With a host of great features that allow you to implement SharePlus across your organization, you’ll find it easy to use SharePlus Enterprise to access your SharePoint information, visualize and generate reports from multiple data sources, and to network with colleagues.

Want to try SharePlus Enterprise? Please click here for more information, and share any questions or thoughts in the comments below.

Flexing Xamarin.Android’s Build to Work Around Android’s 65K Method Limitation

$
0
0

I’ve you’ve ever used a few large java libraries in an Android application you may have run into an odd limitation. When the android build process compiles your Java code/classes to work with the Dalvik Virtual Machine, it creates .dex files. During this process you will get interesting errors if your application and all the libraries that it includes result in over 65,536 methods being referenced in the dex file. It will be something like this:

trouble writing output: Too many method references

Given that including just the Google Play Services library alone will result in over 20,000 method references in the dex, if you are using a few other reasonably sized libraries you can very quickly get in a lot of trouble.

Google provides some information about how to avoid the limitation once you reach it: https://developer.android.com/tools/building/multidex.html

(More discussion here: https://medium.com/@rotxed/dex-skys-the-limit-no-65k-methods-is-28e6cb40cf71)

However, if you are using Xamarin.Android, and are including large native Java libraries (very easy to do if taking a dependency on Google Play Services), the guidance doesn’t seem to be especially clear.

One of the recommendations Google makes is to run ProGuard to strip out portions of your application that aren’t going to be directly used at runtime. However getting this tool to run during the Xamarin.Android build process seems to be less straightforward than against a vanilla Android application. Some work has been done by the community to try and smooth the process over, but it seems some work is needed if you want to run it against Google Play Services and the latest SDK version.

So, that really leaves us with the multidex solution described in the articles. The high level view of that process is:

  • Have your application build multiple dex files instead of just one, individual dex files will stay under the limitation threshold.
  • When your application loads, either be running Android L, or call the multidex support library to cause the rest of the dex files to be loaded during initialization.

Pulling this off with traditional Android tooling is somewhat straightforward, because much of the build tooling has been updated to make it a simple option to enable multidex. However, it doesn’t seem Xamarin has created any simple way to enable this yet when using Xamarin.Android.

Well, I’ve given it a go anyway.

Warning: I haven’t been able to verify with Xamarin yet that there is no roadblock to using this approach. I haven’t run into an issue yet, but have only done cursory testing. Proceed with caution. Additionally I’ve inferred a lot of things about how their targets files work, so I could be stepping on things that shouldn’t be stepped on. Nevertheless, here’s an attempt to reconcile what Google describes you should do with Xamarin’s build process for Xamarin.Android.

  1. First of all you need to include the multidex support library in your Xamarin.Android application. Create a folder called Jars in your android project and add a link to: [Android SDK Root]extras\android\support\multidex\library\libs\android-support-multidex.jar (remember to add as link)
  2. Set the build action on that jar file to: AndroidJavaLibrary
  3. Create a new project in your solution, and call it MultiDexTasks. We need to create a few custom MSBuild tasks in order to modify a few interactions with the native Android tooling that Xamarin doesn’t make customizable enough yet.
  4. Add these framework references to the project: Microsoft.Build, Microsoft.Build.Framework, Microsoft.Build.Tasks.v4.0, Microsoft.Build.Utilities.v4.0.
  5. Add a file reference to Xamarin’s android build tasks assembly to the project. This is usually located at: C:\Program Files (x86)\MSBuild\Xamarin\Android\Xamarin.Android.Build.Tasks.dll

Ok, there’s the basic skeleton. Now you should add a new class to the MultiDexTasks project:

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Xamarin.Android.Tasks;

namespace MultiDexTasks
{
    public class MultiDexCompileToDalvik
        : CompileToDalvik
    {
        [Required]
        public string DexesOutputDirectory { get; set; }

        protected override string GenerateCommandLineCommands()
        {
            var baseString = base.GenerateCommandLineCommands();
            var newString = baseString;

            var outputMatch = new Regex("--output=");
            var match = outputMatch.Match(baseString);
            if (match.Length > 0)
            {
                var startIndex = match.Index;
                var eqIndex = baseString.IndexOf('=', startIndex);
                var inQuoted = false;
                int endIndex = startIndex;
                int i = 0;
                for (i = eqIndex; i < baseString.Length; i++)
                {
                    var prevChar = baseString[i - 1];
                    var currChar = baseString[i];

                    if (currChar == '"')
                    {
                        if (prevChar != '\\')
                        {
                            if (inQuoted)
                            {
                                break;
                            }
                            else
                            {
                                inQuoted = true;
                            }
                        }
                    }
                    if (currChar == ' ' & !inQuoted)
                    {
                        i--;
                        break;
                    }
                }

                endIndex = i;

                var toReplace = baseString.Substring(startIndex, (endIndex - startIndex) + 1);
                Log.LogMessage("will replace: " + toReplace);
                var commands = GetExtraCommands();
                Log.LogMessage("replacing with: " + commands);
                newString = newString.Replace(toReplace, commands);
            }

            return newString;
        }

        private string GetExtraCommands()
        {
            var output = DexesOutputDirectory;
            CommandLineBuilder b = new CommandLineBuilder();
            b.AppendSwitchIfNotNull("--output=", output);
            b.AppendSwitch("--multi-dex");
            return b.ToString() + " ";
        }
    }
}

Because Xamarin doesn’t let us fully customize the area where they invoke the command that generates the main dex file for the application, this creates an MSBuild task that inherits from the one that Xamarin defines and will modify the output file so that it is not a single file, but a directory, and it will also make sure to specify the --multi-dex parameter, which informs the dex command to generate multiple dex files.

Next, because Xamarin only expects to put one dex file into the apk when it comes time to build the application package, we need to create a task that can help inject additional dex files into the application package. So create another file:

using Microsoft.Build.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.IO.Compression;

namespace MultiDexTasks
{
    public class AddOtherDexFilesToApk
        : Microsoft.Build.Utilities.Task
    {
        [Required]
        public ITaskItem ApkFile { get; set; }

        [Required]
        public ITaskItem[] Files { get; set; }

        public override bool Execute()
        {
            var fileName = ApkFile.ItemSpec;
            Log.LogMessage("updating apk: " + fileName);

            using (FileStream zipToOpen = new FileStream(fileName, FileMode.Open))
            {
                using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
                {
                    foreach (var file in Files)
                    {

                        var existingEntry = archive.GetEntry(file.GetMetadata("Filename") + file.GetMetadata("Extension"));
                        if (existingEntry != null)
                        {
                            existingEntry.Delete();
                        }

                        Log.LogMessage("adding file to apk: " + file.ItemSpec);
                        ZipArchiveEntry fileEntry = archive.CreateEntry(file.GetMetadata("Filename") + file.GetMetadata("Extension"));
                        using (StreamWriter writer = new StreamWriter(fileEntry.Open()))
                        {
                            using (StreamReader reader = new StreamReader(file.ItemSpec))
                            {
                                reader.BaseStream.CopyTo(writer.BaseStream);
                            }
                        }
                    }                   
                }
            }

            return true;
        }
    }
}

This will just open up the specified apk file (which is a zip file), and dump additional files into it.

Now, you can create a targets file, called EnableMultiDex.targets that will be imported into your project in order to invoke these extra tasks at the right time:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"><UsingTask TaskName="MultiDexTasks.MultiDexCompileToDalvik" AssemblyFile="MultiDexTasks.dll" /><UsingTask TaskName="MultiDexTasks.AddOtherDexFilesToApk" AssemblyFile="MultiDexTasks.dll" /><ItemGroup><MultiDexOutputs Include="$(IntermediateOutputPath)android\bin\*.dex" /></ItemGroup><ItemGroup Condition="'@(MultiDexOutputs)' == ''"><MultiDexOutputs Include="$(IntermediateOutputPath)android\bin\dummy.dex" /></ItemGroup><Target Name="_CompileDex"
  DependsOnTargets="_FindCompiledJavaFiles;_GetMonoPlatformJarPath;_GetAdditionalResourcesFromAssemblies;_GetLibraryImports"
  Inputs="$(MSBuildAllProjects);$(MonoPlatformJarPath);@(_CompiledJavaFiles);@(AndroidJavaSource);@(AndroidJavaLibrary);@(AndroidExternalJavaLibrary);@(ExtractedJarImports);@(_AdditionalJavaLibraryReferences)"
  Outputs="%(MultiDexOutputs.FullPath)"><!-- Compile java code to dalvik --><MultiDexCompileToDalvik
      DxJarPath="$(DxJarPath)"
      JavaToolPath="$(JavaToolPath)"
      JavaMaximumHeapSize="$(JavaMaximumHeapSize)"
      JavaOptions="$(JavaOptions)"
      ClassesOutputDirectory="$(IntermediateOutputPath)android\bin\classes"
      DexesOutputDirectory="$(IntermediateOutputPath)android\bin"
      MonoPlatformJarPath="$(MonoPlatformJarPath)"
      JavaSourceFiles="@(AndroidJavaSource)"
      JavaLibraries="@(AndroidJavaLibrary)"
      ExternalJavaLibraries="@(AndroidExternalJavaLibrary)"
      LibraryProjectJars="@(ExtractedJarImports)"
      DoNotPackageJavaLibraries="@(_ResolvedDoNotPackageAttributes)"
      ToolPath="$(DxToolPath)"
      ToolExe="$(DxToolExe)"
      UseDx="$(UseDx)"
      AdditionalJavaLibraryReferences="@(_AdditionalJavaLibraryReferences)"
	/><ItemGroup><DexOutputs Include="$(IntermediateOutputPath)android\bin\*.dex" /></ItemGroup><Message Text="@(DexOutputs)" /><Touch Files="%(DexOutputs.FullPath)" /></Target><Target Name="AddAdditionalDexes"
          AfterTargets="_PrepareBuildApk"
          Inputs="$(MSBuildAllProjects);@(_ResolvedUserAssemblies);@(_ShrunkFrameworkAssemblies);@(AndroidNativeLibrary);@(MultiDexOutputs)"
          Outputs="$(IntermediateOutputPath)android\bin\packaged_resources"><ItemGroup><OtherDexes Include="$(IntermediateOutputPath)android\bin\*.dex" Exclude="$(IntermediateOutputPath)android\bin\classes.dex" /></ItemGroup><AddOtherDexFilesToApk ApkFile="$(IntermediateOutputPath)android\bin\packaged_resources"
                           Files="@(OtherDexes)" /></Target></Project>

This basically overrides the existing Xamarin.Android target that compiles the dex file and calls our customized version of the dex compilation task, which will generate the multiple dex files.

It also causes additional dex files to be injected into one of the intermediate apk files that gets built, so that all downstream final versions of the apk file should wind up with all the required dex files. There is probably a better place to inject these, but this way required far less overriding of Xamarin’s existing targets and so should be slightly less fragile if they move stuff around…..maybe.

Next, you should set the build output directory for the MultiDexTasks project to be ..\..\Tasks (depending on your project structure you may want to adjust this path, goal is to put Tasks folder at project root level), and make sure that your EnableMultiDex.targets file is set to always copy to the output directory. This puts the task dll and the targets file in an easier to access place to reference from your other project.

Next unload your Xamarin.Android project that needs to get around the limitation. You should now be able to select edit from the right click menu. You need to add this import:

<Import Project="..\..\Tasks\EnableMultiDex.targets" />

You may have to adjust that relative path depending on your project structure. Critically, though, you must add this import AFTER Xamarin.Android’s target file is imported:

<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" /><Import Project="..\..\Tasks\EnableMultiDex.targets" />

Now you can reload the project. The last thing you need to do is to do is to change the application type so that Android knows that you have this multiple dex file scenario, and will cause the other dex files to be loaded.

In order to do this open up your android manifiest at Properties => AndroidManifest.xml and add this attribute to the application tag:

android:name="android.support.multidex.MultiDexApplication"

If this is the first edit you have made to your manifest the application tag should probably look like this now:

<application android:name="android.support.multidex.MultiDexApplication"></application>

You may want to add a project dependency on MultiDexTasks to your Xamarin.Android project since you now have an indirect reference to the tasks and target file it produces. Keep in mind, MSBuild likes to lock assemblies on disk that it loads tasks from, so if you are getting errors that MultiDexTasks.dll can’t be written, you may have to kill any lingering MSBuild.exe processes.

Anyway, now you can build and run the application again.

If you are still getting a build error, make sure you have set Project => Properties => Android Options => Advanced => Java Max Heap Size: 1G

If you have been hitting the 64K method limitation, you probably also need more Java heap space during the build, otherwise you will get out of memory exceptions.

Caveat: Though the application builds, I haven’t extracted any feedback from Xamarin as of yet as to whether they expect any integration issues with Xamarin.Android when combining use with this multidex functionality. They could decide that the above is a bad idea. This should get you up and running though, if this is a blocking issue for you, and I’d be interested to hear what sort of issues you run into. If you think you know a cuter way of sliding these build changes into Xamarin’s process with less violence, I’d love to hear about it in the comments.

Best of luck,

Graham

What to expect in an interview for a .NET job

$
0
0

Around the world there is an urgent need for skilled developers. Even Barack Obama told us that the world needs developers and that kids should start learning programming skills as soon as possible. However, attending a job interview can be a nerve wracking experience and so in this post, we’ll look at what a .NET developer can expect in an interview and how they can prepare.

Many talented developers find they have difficulties with job interviews because they tend to be too focused on what they are passionate about - that is, technology and development - and not on the preparation of their interview skills. Preparing for a job interview can really help boost your career by giving you opportunities you wouldn't get otherwise.

Make your CV stand out

Generally speaking, your biggest chance of getting job interview starts when employers scan your resume. This is an opportunity you simply can’t afford to slip up on. A skilled developer is not a professional resume writer, so to get the largest number of possible opportunities for an interview it is fair to spend some money having your resume improved by an expert. This is a small investment to make for the potential gain of landing a much better job.

Know your CV!

Many interviews begin with a discussion of your CV and experiences. However, a common mistake employers report is that interviewees often seem not to know their own resume. Nothing will make alarm bells ring like a candidate who has a lot of trouble explaining what they’ve done previously. So, make sure you know what you wrote and can speak about what you did when and where.

It’s also essential to be able to provide examples about specific situations, problems or issues. Interviewers often want to know how you’ve dealt with difficult moments, communication problems, heavy workloads and want to hear examples of your successful projects. Think about your experiences before the interview and think how you would explain what you did and what the result of your actions were.

Besides describing your professional and academic successes, it’s also good practice to research the interviewer. It takes only a few minutes to Google this person and read a few blog posts he or she wrote. Show interest in the interviewer by mentioning a blogpost or an article they’ve written or shared. The easiest way to get someone interested in you is to show a genuine interest in them.

A testing experience

In most interviews, the developer needs to solve some algorithm based problems like explaining a sorting algorithm, solving an exercise with arrays or optimising a routine. These questions are intended to test your problem solving skills. It doesn't matter what programming language or technology you use, if you can solve problems, you will be a good developer. Problem solving is the base skill of good software development.

There are some basic steps in solving these kind of problems:

  • Identify the problem
  • List the possible solutions or actions
  • Weigh the possible solutions
  • Choose one solution to try
  • Put the solution into practice
  • Evaluate the solution

What’s your motivation?

During your conversation, the interviewer will check if you can answer questions with passion. Showing a real interest in what you do is important in every job. A carpenter that hates cutting wood is a bad carpenter. A developer should love doing their job and this must be clear when answering questions.

Questions you can expect will be like "why are you a developer?" or "why would you write a web application". Rather than giving a straight technical answer, emphasise that you what you love doing is developing and writing code. Speak about the satisfaction you get from a good build and about how it’s been your dream since you first begun playing with computers.

Getting technical 

Most developer interviews will involve a technical section. You can expect this to check your knowledge of design patterns and practices. Design patterns are general reusable solutions to a commonly occurring problem within a given context in software design. You’re likely to hear questions like:

  • What is an interface?
  • Explain the Facade pattern.
  • Write a singleton class

These questions are programming language independent and gives the developer the chance to show that he or she know the developer basics. Spend some time thinking about how you’d answer this kind of question and remember your answers; your interviewer will be impressed if you can reel off correct explanations without thinking too much.

Besides the general development questions like algorithms and patterns the interviewer will also check your knowledge of the .NET architecture. Questions might include:

  • What is the garbage collector?
  • What is the difference between Webforms and MVC?
  • Explain the lifecycle of an aspx page.

These questions are programming language independent also so try to answer them in an independant way to show the interviewer that you really know the complete framework. When asked you can go language specific by using C# (or any other language) to explain your solution.

Any good developer solves problems in a language independent way and knows that a language can be easily adapted. Of course it is an advantage to be a real expert in, for example, C# but do not get hung up on it. Know that there are other languages out there and know how to use them and show willing to learn them.

Preparation, preparation, preparation

Doing a job interview as a developer need not be a nerve wracking experience. 90% of the interview can be prepared in advance. Make sure you know the company, the job description and the interviewer. Refresh your problem solving algorithmic skills, list the common patterns you know and try to explain them and at last learn the ins and outs of the .NET framework.

Good luck!

11 Things About JavaScript Functions that .NET Developers Should Know: Part 1

$
0
0

I have often seen .NET developers struggle with JavaScript. They try to compare C# functions with JavaScript functions and usually make some minor but conceptual mistakes while using it. We can all agree that JavaScript functions are the backbone of the JavaScript programming language, and if one has a good understanding of the function, then using JavaScript is easier. So in this two parts series, I will focus some important concepts of JavaScript functions.

In this part of the series, we will cover the following six topics:

  1. JavaScript functions as an expression
  2. JavaScript functions as a statement
  3. Return statements in JavaScript functions
  4. Parameters in JavaScript functions
  5. The Arguments object in JavaScript functions
  6. Varargs JavaScript functions

JavaScript functions can be an expression

A JavaScript function can be an expression, as seen below:

var add =function Add(num1, num2){var result = num1 + num2;return result;};
 

A function expression creates an instance of the function object. It can be passed as an argument to a function, it can be returned from a function, and it can be assigned to a variable or an array. A function expression can be created with the name as shown here:

var add =function Add(num1, num2){var result = num1 + num2;return result;};var s = add(34,67);
console.log(s);

A function expression can be created without the name as shown here:

varsub=function(num1, num2){var result = num1 - num2;return result;};var r =sub(5,9);
console.log(r);


We cannot use a function expression before it has been created. So if in above code snippet, we call the sub function before it’s created as shown below:

var s =sub(34,67);
console.log(s);varsub=function(num1, num2){var result = num1 - num2;return result;};
 

We will get an exception as shown below:

To understand why we are getting the above exception, let’s try to understand how var works in the JavaScript. When you assign something to var using an assignment, JavaScript first creates var on the top of the function with the value undefined in it. Essentially var statements get converted in two parts. For every var, at the top of the function, JavaScript will create a variable with undefined value assigned to it. Later the real value will be assigned to the variable.

This is the reason when we try to invoke a function expression before it was created, we got the exception that undefined is not a function.

JavaScript functions can be a statement

A JavaScript function can be created as a statement too, as shown below:

function Factorial(n){if(n <=1){return1;}return n * Factorial(n -1);}

When we create a JavaScript function as statement, it is mandatory to give a name to the function. When we create a function statement, JavaScript creates an object and assigns that to the variable. So usually, when you create a function statement, JavaScript creates a variable with the same name as the function. Unlike the function expression, a function statement can be invoked before it is defined. As you see below, the code will not throw any exceptions.

var result = Add(9,8);
console.log(result);function Add(num1, num2){return num1 + num2;}
 

Function statements are moved to the top of the script, so they can be invoked before they are defined.

Return statements in JavaScript functions

A JavaScript function may or may not have a return statement. By default, a JavaScript function returns value undefined. Explicitly you can return an expression from the JavaScript function. If there is no expression, then the JavaScript function is returned as undefined.

We have seen that the JavaScript function can return an expression as shown below:

function Add(num1, num2){return num1 + num2;}var result = Add(1,2);
console.log(result);
 

And you can also have a JavaScript function without a return statement as shown below:

function Foo(){// function body }var result = Foo();
console.log(result);

The value undefined will be printed on the console because the JavaScript function does not return any value. Another scenario may give you an expressionless return statement in the function. In this case an undefined value will also be returned from the JavaScript function. The function defined below will also return an undefined value.

function Foo(){// function body return;}var result = Foo();
console.log(result);
 

Keep in mind that a JavaScript function constructor, by default, returns the invoking object; not the undefined value.

Parameters in JavaScript functions

JavaScript does not:

  1. Type-check the parameters
  2. Check the number of parameters being passed

However, you can essentially pass any type or number of parameters in a JavaScript function. You can pass fewer parameters than declared or more parameters than declared, and when you invoke a function with less parameters than are declared, the additional parameter values are set to undefined. Let’s see this in action.

Here we have a JavaScript function Add which takes two parameters. However, we are passing only one parameter while invoking the function:

function Add(num1, num2){
    console.log(arguments.length);
    console.log(arguments[0]);
    console.log(arguments[1]);var result = num1 + num2;return result;}var result = Add(8);
console.log(result);
 

As a result, you will see that arguments.length prints 1 and arguments[1] prints undefined, so you can pass less parameters than declared parameters. Additional parameters will have an undefined value. Note: we will discuss the arguments object in my next post.

On the other hand, you can pass more parameters than there are declared, and you can access those additional parameters using the arguments object. There is no way you can refer to additional parameters with a named argument; you can access it only using the arguments object:

function Add(num1, num2){var result = num1 + num2 +arguments[2];return result;}var result = Add(8,9,10);
console.log(result);
 

As the output of the above snippet, you will get 27 printed. JavaScript functions support a variable number of parameters. By default, it will pass undefined for all parameters whose value is not passed, and will simply ignore any additional parameters passed.

The arguments object in JavaScript functions

When we invoke a JavaScript function, along with parameters, the arguments object also gets passed to the function. Let us consider the Add function as defined below:

function Add(num1, num2){
    console.log(arguments.length);return num1 + num2;}var result = Add(1,2);
console.log(result);
 

As you’ll see, inside the Add function, we are printing length of the arguments. Since we are passing two parameters to the function, 2 will be printed for the length of the arguments object. In JavaScript, along with the parameters, the arguments object also gets passed. It allows us to access the parameters with the number rather than the parameter’s name. Using the arguments object, the Add function can be rewritten as shown below, and it will print the exact output.

function Add(num1, num2){
    console.log(arguments.length);returnarguments[0]+arguments[1];}var result = Add(1,2);
console.log(result);
 

The arguments is an array-like object, but it is not a JavaScript array. Any JavaScript array operations on the arguments object will throw an exception. For example, the push and pop method will throw exception. It’s very likely that the code snippet below will throw an exception because that object does not have a pop or push method.

function Add(num1, num2){
    console.log(arguments.length);var a =arguments.pop();arguments.push(45);returnarguments[0]+arguments[1];}var result = Add(1,2);
console.log(result);
 

You can use the arguments object to throw an exception when the user does not pass the expected number of parameters. Let’s say in the add function, you want to throw an exception when users pass less or more than two parameters while invoking the function. This can be done using the arguments object as listed below:

function Add(num1, num2){if(arguments.length !=2){thrownew Error("Pass exactly two parameters");}return num1+num2;}var result = Add(1,2,3);
console.log(result);
 

The arguments object is very useful to fetch additional parameters being passed and restricted to invoke the function with specified numbers of parameters.

Varargs JavaScript function

Varargs functions are those functions which work on any number of parameters. Using the arguments object, all the passed parameters can be iterated and used. Let’s consider the listing shown below, where the add function takes a variable number of parameters and returns a summation of all the passed parameters:

function Add(/* pass any number of parameters */){var sum =0;for(var i =0; i <arguments.length; i++){
        sum = sum +arguments[i];}return sum;}var result = Add(7,8,9);
console.log(result);var result1 = Add(5,6,78,93,5);
console.log(result1);
 

In the Add function, we are passing a different set of parameters and using the arguments object, adding the passed parameters and returning the summation. The Add function is a varargs JavaScript function.

Summary

In this part of the series, we covered the following six topics:

  1. JavaScript functions as an expression
  2. JavaScript functions as a statement
  3. Return statements in JavaScript functions
  4. Parameters in JavaScript functions
  5. The Arguments object in JavaScript functions
  6. Varargs JavaScript functions

The topics we’ve discussed here are vital when using JavaScript functions, and in the next part of this series we’ll cover invocation patterns, high level functions and more.


Five Facts About the Office 365 API

$
0
0

An API is a set of protocols with which a developer can interface with a given system or platform. Late last year Microsoft released the long awaited APIs for Office 365, finally giving developers a standard way to customize the popular collaboration platform. See here for a good overview from the MSDN site on the various ways you can now develop for the Office 365 platform.

For example, it is possible to write a HTML5 and JavaScript based website that reads data from Office 365 and displays it to users. Or you can build a Windows 8 Universal App, which pulls data from a SharePoint Tasks list stored inside SharePoint Online. The possibilities are (almost) endless!

Microsoft is actively encouraging developers to think of Office 365 as a platform and to create awesome applications on a variety of platforms. The recently relaunched Office Dev Center is testament to this.

In this post, we'll look at five interesting or unique ways that the Office 365 API can be used.

1. Build an E-mail app for Android, integrating with Yammer and OneDrive

How cool would it be to see documents, Yammer discussions, and e-mail all in one single application? The Office 365 API makes this possible, and even on Android.

This app could allow users to read their e-mails, see the discussions from Yammer, and access documents stored in OneDrive, all from one single screen. Content could be mapped to themes, metadata, or search results, meaning everything is shown with a much greater level of context. Yammer has proved very successful for Office 365 so far, so putting its data inside an email based app would be very interesting indeed.

2. A custom Intranet app for mobile devices

While Office 365 has a great native mobile view, accessing over the web isn’t the best approach for everyone. Various Microsoft and third party apps exist, including our own, but these can’t always be easily modified and branded. By creating a mobile app, specific for the company's own Office 365 Intranet, users can access a totally bespoke version of the Intranet on the move.

The app could feature a unique user interface that pulls out the features that are important and relevant to that organization, highlighting key aspects or data. Such an option would have a cost impact, but for large scale deployments and systems it could pay real dividends.

3. Chrome extension to enrich content Office 365 content

It would be really interesting if data found on different websites, as people browsed throughout the day, could be enriched with company specific data from Office 365. A Chrome extension is one way to do this.

For example, when Googling for a certain query, this query can be fired against the Office 365 search as well and displayed next to the Google results. Or, when the extension detects the name of an employee, it shows data stored in Office 365 for that person.

4. Make updating or completing tasks fun

Many people work to complete tasks all day, often in SharePoint and Office 366. But a common problem is people tend to forget to update a task once they have worked on it.

To make this process more fun, it could be transformed into a game, developed as a Windows 8.1 or mobile app. People love games and gamification is very popular in enterprise tools. Achievements and rewards can be found in almost any game. Why not bring that to the workplace?

Leaderboards and achievements can be implemented as part of project tasks lists; every time a user completes or updates a task, he gets an achievement. When a user ranks first during a week, he or she can be rewarded sufficiently - a free lunch or coffee. People can track their progress using the app. Going to Office 365 to update a task becomes rewarding, and much more fun!

5. A Windows 8.1 app to work offline with Office 365

Office 365 has one obvious drawback. Like all cloud software it requires a working Internet connection. So users on the move, away from a network connection, or otherwise offline have limited options to stay productive. So, building an app that synchronizes certain data while connected, and provide an offline mode while disconnected, allows the user to work even without a network connection. OneDrive does a good job of this for documents, but an enterprising developer could put together something pulling in a whole raft of Office 365 content.

A world of possibilities

These five ideas presented are just the tip of the iceberg, and there is a whole host of other unique ways the new Office 365 APIs can be put to good use. As we touched on earlier, Microsoft is putting a lot of effort in documentation and guidelines to help the developer community. So be sure to check out the Office Dev Center and our own tools, and get creating!

Using the xamTabControl as a Prism Region and Closing Tab Items

$
0
0

The Microsoft TabControl is a popular control to use as a region in a WPF Prism application.  Unfortunately, the Microsoft TabControl comes with some limitations, such as the inability to close tab items.  If you want to close tab items in the Microsoft TabControl, you need to implement this functionality yourself.  However, you can make this easy on yourself by using the Infragistics xamTabControl.  The xamTabControl extends the Microsoft TabControl and adds a number of features that you would normally have to write yourself otherwise.  For example; closing tab items is built into the control.  Another great thing is that nothing syntactically really changes when you use the xamTabControl as a Prism Region.  So switching out the TabControl for the Infragistics xamTabControl is no big deal.  Everything is the same.

Let’s take a look at a view that uses the xamTabControl as a region and adds support for closing tab items.

<Window.Resources>
    <Style TargetType="{x:Type igWPF:TabItemEx}">
        <Setter Property="Header" Value="{Binding DataContext.Title}" />
    Style>
Window.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    Grid.RowDefinitions>

    <StackPanel Orientation="Horizontal">
        <Button Command="{Binding NavigateCommand}" CommandParameter="ViewA" Content="Navigate A"/>
        <Button Command="{Binding NavigateCommand}" CommandParameter="ViewB" Content="Navigate B"/>
    StackPanel>

    <igWPF:XamTabControl Grid.Row="1" prism:RegionManager.RegionName="TabRegion" />

Grid>

As you can see, this is a very simple view.  It uses the xamTabControl as it’s region and it also has a couple of buttons on it that we will use to navigate to different views in the xamTabControl region.  So when you run the application and click the buttons a couple of times, you will end up with something like this:

image

Okay, it’s nothing special right now.  It looks just like it did if we were to use the Microsoft TabControl.  Now let’s say we want to add support for closing tab items.  Well, no problem!  This is as easy as using a property.  The TabItemCloseButtonVisibility property to be exact.


<igWPF:XamTabControl Grid.Row="1" prism:RegionManager.RegionName="TabRegion" TabItemCloseButtonVisibility="Visible" />

        

Run the application and now we get those cool little close buttons automatically.

xamtabcontrol-as-prism-region

Pretty cool right?  Heck yeah it’s cool!  Run the app and start opening and closing tabs until your heart’s content.  But……  We actually have a major issue here.  We are using Prism.  We have this thing called a Region.  This region holds all of the views we add to it until we remove them from the region.  Unfortunately, when you click on that pretty little close button, the view seems to be removed from the control, but in actuality it is still hanging around in our Region.  This is because the close button has no idea that we are using Prism, or that we need to remove the view we just closed form the Region.

Solution

So how do we fix this?  Simple… we need a custom behavior.  This one right here:

publicclassTabItemRemoveBehavior : Behavior<XamTabControl>
{
    protectedoverridevoid OnAttached()
    {
        base.OnAttached();
        AssociatedObject.AddHandler(TabItemEx.ClosingEvent, newRoutedEventHandler(TabItem_Closing));
        AssociatedObject.AddHandler(TabItemEx.ClosedEvent, newRoutedEventHandler(TabItem_Closed));
    }

    protectedoverridevoid OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.RemoveHandler(TabItemEx.ClosingEvent, newRoutedEventHandler(TabItem_Closing));
        AssociatedObject.RemoveHandler(TabItemEx.ClosedEvent, newRoutedEventHandler(TabItem_Closed));
    }

    void TabItem_Closing(object sender, RoutedEventArgs e)
    {
        IRegion region = RegionManager.GetObservableRegion(AssociatedObject).Value;
        if (region == null)
            return;

        var args = (TabClosingEventArgs)e;

        args.Cancel = !CanRemoveItem(GetItemFromTabItem(args.OriginalSource), region);
    }

    void TabItem_Closed(object sender, RoutedEventArgs e)
    {
        IRegion region = RegionManager.GetObservableRegion(AssociatedObject).Value;
        if (region == null)
            return;

        RemoveItemFromRegion(GetItemFromTabItem(e.OriginalSource), region);
    }

    object GetItemFromTabItem(object source)
    {
        var tabItem = source asTabItemEx;
        if (tabItem == null)
            returnnull;

        return tabItem.Content;
    }

    bool CanRemoveItem(object item, IRegion region)
    {
        bool canRemove = true;

        var context = newNavigationContext(region.NavigationService, null);

        var confirmRequestItem = item asIConfirmNavigationRequest;
        if (confirmRequestItem != null)
        {
            confirmRequestItem.ConfirmNavigationRequest(context, result =>
            {
                canRemove = result;
            });
        }

        FrameworkElement frameworkElement = item asFrameworkElement;
        if (frameworkElement != null&& canRemove)
        {
            IConfirmNavigationRequest confirmRequestDataContext = frameworkElement.DataContext asIConfirmNavigationRequest;
            if (confirmRequestDataContext != null)
            {
                confirmRequestDataContext.ConfirmNavigationRequest(context, result =>
                {
                    canRemove = result;
                });
            }
        }

        return canRemove;
    }

    void RemoveItemFromRegion(object item, IRegion region)
    {
        var context = newNavigationContext(region.NavigationService, null);

        InvokeOnNavigatedFrom(item, context);

        region.Remove(item);
    }

    void InvokeOnNavigatedFrom(object item, NavigationContext navigationContext)
    {
        var navigationAwareItem = item asINavigationAware;
        if (navigationAwareItem != null)
        {
            navigationAwareItem.OnNavigatedFrom(navigationContext);
        }

        FrameworkElement frameworkElement = item asFrameworkElement;
        if (frameworkElement != null)
        {
            INavigationAware navigationAwareDataContext = frameworkElement.DataContext asINavigationAware;
            if (navigationAwareDataContext != null)
            {
                navigationAwareDataContext.OnNavigatedFrom(navigationContext);
            }
        }
    }
}

Now simply apply the Behavior to our xamTabControl by using System.Windows.Interactivity.  Like so:

<igWPF:XamTabControl Grid.Row="1" prism:RegionManager.RegionName="TabRegion" TabItemCloseButtonVisibility="Visible" >
    <i:Interaction.Behaviors>
        <core:TabItemRemoveBehavior />
    i:Interaction.Behaviors>
igWPF:XamTabControl>

What this Behavior does is hooks into the TabItemEx.Closing and TabItemEx.Closed events so that we can execute our Prism logic during the tab item closing process.  First, we need to respect whether we can even close the tab.  This is done by checking the IConfirmNavigationRequest interface on the view we are trying to remove in the Closing event.  If our View or ViewModel returns false during the ConfirmNavigationRequest method call, then the tab item cannot be closed.  Otherwise, we will allow the tab item to be closed.  For example; let’s say I had some rule that wouldn’t allow ViewB to be closed.  I simply pass “false” in the continuationCallback within the ConfirmNavigationRequest method, and prompt the user letting them know why this tab couldn’t be closed.

image

This bring us to the TabItemEx.Closed event.  Now that we know if we can or cannot close a tab, we simply get the view from the tab item, and then remove it from the region.  But, before we remove it, we want to invoke the NavigatedFrom method on the INavigationAware interface so that we can respond to when a tab is closed from within our View or ViewModel to do any last minute clean up or state management.

That’s it!  You have now added complete Prism Navigation support for closing tab items when using the xamTabControl as a Prism region.  Hopefully you will find this useful, and maybe even use this in your WPF Prism applications.  Be sure to check out the source code, and start playing with it.  As always, feel free contact me on my blog, connect with me on Twitter (@brianlagunas), or leave a comment below for any questions or comments you may have.

How to use NodeJS, Express, and Bower to Create AngularJS apps

$
0
0

Recently I heard someone say that “IDE makes you ignorant, so don’t rely on it”. The thought behind this is that as .NET developers, we cannot think of life beyond Visual Studio, so we become ignorant and don’t care about the behind the scenes complexities. We create a project by selecting a specific project template and manage the different required packages using the NuGet package manager. Super simple, right? Well, not necessarily.

In this article, we’ll explore another way to create an application using JavaScript at the server and at the client, by having NodeJS run it on the server and Angular run it on the client.

Note: Image taken from the web. A special thanks to original image creator.

We will start with creating an angular application in Visual Studio, and then proceed to create the same Angular application using a few components of the MEAN stack: NodeJS, Express, and Bower. Specifically, this post will cover the following topics:

  • Creating an AngularJS application in Visual Studio
  • Installing NodeJS on Windows
  • Setting up the sublime text for JavaScript development
  • Installing Bower
  • Installing Angular dependencies using Bower
  • Creating an Angular application
  • Installing Express
  • Creating a web server using Express to serve the Angular app

Creating an AngularJS application in Visual Studio

We can create an AngularJS app in Visual Studio by going to File-New Project and then selecting ASP.NET Web Application project template from the Web tab. We are going to create an AngularJS application running on IIS express, so we will choose the Empty template.

I am using Visual Studio 2013 for the purpose of this blog. Once the project is created, we can add an Angular library using the NuGet package manager.

After successful installation of the Angular library you can see Angular files in the Scripts folder of the project.

 

We are all set to write the first AngularJS app using Visual Studio. Let’s go ahead and add an HTML file and the required reference on that to write our first Angular app. In the image below you’ll see that I’ve added Index.html, a reference to the Aangular library, and I’ve created a simple app as shown below:

 

On F5, the Angular app will run in ISS Express, which is Visual Studio’s default web server. We should see the application as it appears below:

Right now, our application is running on the local host and at port 53520. Very easily, we can configure the port number by right clicking on the project, and from the context menu in the web tab, we can edit the Project Url as shown below:

 

As you can see, using Visual Studio, it’s very simple to create an Angular app. Like I mentioned earlier in this post, the use of IDE sometimes makes us ignorant - many complexities have been taken care of by Visual Studio so that we don’t even have to think about them. For us, writing an Angular app was very easy.

Okay, but now how do I create an Angular App on Windows without Visual Studio?

There are many ways to create an Angular app on Windows without using Visual Studio - or any IDE for that matter.  Next I’m going to show you how an Angular app can be created using:

  • NodeJS as the web server
  • Bower to install any client side dependencies
  • Sublime text as the code editor

Install NodeJS

We’ll start by installing NodeJS on Windows. To do that, navigate to http://nodejs.org/ and click on INSTALL to get an MSI file to be installed on Windows. Make sure that the NodeJS variable has been added to the environment variable of windows. To verify that NodeJS installed successfully, open the command prompt and type the command node. Then you’ll get a node shell in which you can run JavaScript code:


Configure SublimeText for JavaScript development

After successfully installing NodeJS, let’s configure Sublime Text for the JavaScript development. To do this we need to create a build system for the JavaScript in Sublime Text. To create the build, in Sublime Text navigate to Tools->Build Systems->New Build System, and enter the code as shown below:

 

After saving the file, you will find a build for JavaScript in Tool->Build System. You’ll need to select that to perform JavaScript development. After selecting the JavaScript build, in Sublime Text you can run JavaScript by using Ctrl+B.

Creating an Application folder and using Bower to install Angular dependency

As of now we have set up NodeJS and Sublime Text. Now we need to install bower. Using Bower we can manage all of the client side dependencies. To do that, let’s create a new folder on the file system and install Bower inside that. In my case, I’ve created a folder named HelloWorld2. In the newly created folder, first run the following command: npm init

This command will ask you few questions, but if you’re unsure of any answers, simply leave the default value there. This command will create a file named package.json in the folder.  

Next run the command npm –nstall –g bower to install Bower as shown in the image below:

After successful installation of Bower, we need to install all Angular dependencies. These can be installed by executing the command bower install angular.

 

After successfully installing the command, you will find a subfolder named bower components. Inside the bower_components sub folder, you will find an Angular folder. This folder will contain all the required Angular files.

As of now, we have installed NodeJS, Sublime Text and we’re using the Bower-required Angular dependencies. Now let’s go inside the root folder (the folder we created in the previous step) and create a file named Index.html. To do this, let’s add a folder to the project by clicking Project-> Add Folder to Project and add the HelloWorld2 folder we created in the previous step.

Once that folder is added to the project, you can find that in the left of the Sublime text.

 

Right click on HelloWorld2 and create a new file, press Ctrl+S to save it, and name it as Index.html:

In Index.html, we will add the reference to Angular and create an Angular application.

Installing Express

So far we’ve created the Angular application using NodeJS and Bower. Now we need a web server to serve HTML, CSS and JavaScript. In this step we’ll create a simple web server using Express. We can install Express using npm install express. Run the command as such:

npm install express --save

After successful installation of Express, you will find that package.json has been updated as shown here:

Next add a file server.js in the root of the folder.

As you’ll see in the code, Express will serve files from the root directory and then the app subdirectory. So make sure to put the Angular app file and Bower components file inside the app subfolder. Your folder structure should more or less look like this:

Next, go ahead and run the node application using the node command. Run the command node server.js  - this will start the server on port 1001:

Now we can run the Angular application using the web server created using Express on port 10001.

Now we have an Angular application running on the web server, using JavaScript on the server and at the client!

I hope this article will help you in getting started with the MEAN stack - and help you realize that using open source is not as tough as it seems!

Developer News - What's IN with the Infragistics Community? (1/26-2/1)

$
0
0

The last Developer News of January has some awesome articles, ranging from a podcast roundup to testing tips for Java developers. Take a look at what's hot and see if you have anything to add.

5. Top 5 Podcasts for .NET Devs (.NET Zone)

4. Internet of Things: What About C# There? (MSDN Blogs)

3. Technical Leadership for Agile Teams (InfoQ)

2. Using Grunt.js to Merge and Minify Javascript files in an ASPNET MVC Application (DotNetCurry)

1. Top Testing Tips for Discriminating Java Developers (ZeroTurnAround)

No more NPAPI support for Chrome: What are the alternatives?

$
0
0

As of January 2015 Chrome will be effectively dropping support for NPAPI, rendering it more or less obsolete. Google announced they would be phasing out the plugin in September 2013 and over the last fifteen months have been gradually reducing support on their browser, while simultaneously making it harder for developers to build components with it.

The Internet is constantly evolving and, according to Google, NPAPI was well past its sell by date. Blamed for hangs, vulnerable to threats and overtaken by more sophisticated APIs, NPAPI seems to have had its day. Some developers have been less than impressed by Google’s decision, citing specific programming tools that still depend on NPAPI, the potential problems around different browsers using different APIs and the general critique of the ‘Corporation as a behemoth crushing diversity’. Nonetheless, the vast majority of developers have already moved on from NPAPI, and Chrome supports a number of alternative extensions to fill in the gaps.

In this blog we’ll be taking a longer look at support for NPAPI, why Google is dropping it, and what alternatives are out there.

Not happy with NPAPI

NPAPI was developed for Netscape in the 1990s to allow users to run unusual files (such as video and audio) within their browsers without having to open them on a third platform. Quickly adopted by all major browsers, the plugin has more recently been made redundant by HMTL5, thanks to the code’s ability to play media without the help of a plugin. The big three web browsers have now dropped NPAPI plugins - first was Internet Explorer (which only ever partially adopted it) more recently followed by Mozilla and now Chrome.

In their September 2013 announcement, Google explained that they’d seen a steady decline in use of the plug-in, pointing out that only six NPAPI plugins had been used by more than five percent of users in the previous month and reiterated its decreasing utility:

“Today’s browsers are speedier, safer, and more capable than their ancestors. Meanwhile, NPAPI’s 90s-era architecture has become a leading cause of hangs, crashes, security incidents, and code complexity.”(Emil Protalinski)

Google has been hammering nails into the coffin ever since. The phase out schedule began with blocking the addition of new NPAPI supported apps on the Chrome Web store, rendering it more difficult to use apps supported by NPAPI and discouraging development. From April 2014 all NPAPI supported apps where unpublished from the webstore (although earlier purchases continued to function).

Google did produce an official whitelist of the most popular NPAPI plugins which would be spared the chop until January 2015 which included:

  • Silverlight (launched by 15 percent of Chrome users in the month to September 2013)
  • Unity (9.1 percent)
  • Google Earth (9.1 percent)
  • Java (8.9 percent, but already blocked for security reasons)
  • Google Talk (8.7 percent)
  • Facebook Video (6.0 percent)

Beyond this original list, Google also allowed developers to add their own apps to the whitelist for the sake of ongoing projects. While new NPAPI apps are now blocked on Chrome, support will remain for developers making the last minute transition away from the plugin. However, in April support will be totally dropped and it will be impossible to use installed extensions with the plugin by September 2015.

So, what now?

Recognizing developer’s concerns about installed extensions, Chrome has handily provided details on alternatives to NPAPI in their blog. By and large, HTML, CSS and JS will continue to be the main tools in the developer’s sandbox, fulfilling most coding needs. Meanwhile, HTML5 was designed to bypass the risks inherent in plugins by allowing developers to include video and music files within code (rather than as an add-on). HTML5 avoids many of the risks posed by using a plugin and makes the page viewing experience more seamless.

More complicated functionality can be achieved through the use of a new generation of web extensions. Google recommends in particular:

  • For browser to browser voice calling, video chat and p2p filesharing, Chrome recommend WebRTC (supported by most browsers other than Internet Explorer and Safari which still require a plugin)
  • Adaptive streaming and time-shifting live streams  - allowing JavaScript to generate responsive media streams for playback - can be achieved with Media Source Extensions
  • Digital Rights Management is covered by Encrypted Media Extensions, standardised over different browsers to allow seamless interaction with Content Decryption Modules. This extension type permits anything from simple Clear Key Decryption to high value video
  • Extensions for communication between native apps are also available. Users are required to download APIs which support tasks of escalating complexity - from one-time requests to long-lived connections and cross-extension messages

Google have good reasons for dropping NPAPI, and the improvements offered by HTML5 and related extensions clearly outweigh any benefits with sticking to the old technology. Most developers have already moved on, and those that haven’t will find NPAPIs descendants are more polished and performant than anything that has gone before. We are looking forward to seeing what these next gen tools are capable of.

Developer News - What's IN with the Infragistics Community? (2/9-2/15)

Upcoming Webinar: How to Choose the Right Chart for Your Data

$
0
0

When building out complex data visualizations, it’s easy to get overwhelmed by the virtually endless array of options around how to sort, filter, and display your data. Where do you even start? Check out our upcoming webinar: How to Choose the Right Chart for Your Data.

Infragistics Senior VP of Developer Tools, Jason Beres, will walk you through many of the various chart types found in the iOS, Windows Forms and jQuery controls of Infragistics Ultimate – he’ll even go over some data viz do’s and don’ts. And as an added bonus, every attendee will be entered into a raffle to win a free iPad!

Space is limited, so reserve your spot today. We’ll see you on March 11th!


Exploring the Windows Forms controls in our new Cashflow Dashboard

$
0
0

This month, Infragistics takes you through the creation of a financial cash flow dashboard using our Windows Forms controls, but without looking like a typical clunky Windows Forms application.

[youtube] width="560" height="315" src="http://www.youtube.com/embed/SBPobvWdkQ8" [/youtube]

To start with, Infragistics designers came up with a mockup of what they wanted the application to look like:

After all was said and done, the finished application looks like this:

The biggest challenge implementing this was the chart on top in the ‘total cashflow’ section. The new Infragistics UltraDataChart is a powerful control, but it could not achieve the desired effect here right out of the box. As you can see, the total cashflow chart has two different Y Axes, and the middle section is really nothing but a series of labels. This took some creative coding.

In fact, that top chart is really 3 separate chart controls that are cleverly styled to appear as one.

The first chart is a simple Line Series.

 

The second is a chart that only displays Axis labels and no data.

And the third chart contains 4 Column Series – two for inflow and outflow and two more for the projected values (which display as circles).

This required the addition of a separate UltraScrollBar control to allow synchronized scrolling of all three charts. And the highlight of the ‘active’ item was achieved using the Paint event of the controls to draw a semi-transparent overlay and a border.

The bottom section of the dashboard displays details of inflow and outflow using either a StackSeries or an AreaSeries, depending on the user’s selection:

And we round things out with an UltraWinGrid to show the actual numbers.

The summary blocks on the left side of the dashboard are UserControls which contain Infragistics UltraLabel controls. They are arranged inside the UltraGridBagLayoutPanel so that they size proportionally along with the form.

When you start off by seeing just how much data we needed to include in this dashboard, it's pretty impressive to see the finished product. 

Inspired to build your own dashboard next? Grab your free trial of Infragistics Ultimate, check out our making of the app video, and get the code for yourself so you can start creating some in-depth visualizations like this one. Happy coding!

Common Business Scenarios with Infragistics UltraDataChart

$
0
0

Infragistics UltraDataChart Control has been engineered to dramatically simplify the way in which you visually present information to your end-users. Optimized for both performance and flexibility, the WinForms DataChart is a highly customizable control library which can be leveraged in a nearly endless number of business scenarios, be it real-time charting or analysis of multi-dimensional data.

The updated Windows Forms Data Chart is fast, fully-featured, and arguably the most modern Windows Forms chart on the market. Smoothly animate data over time using the innovative Motion Framework, create composite charts, and use multiple series, featuring a range of series that include Line, Stacked Line, Stacked Area, Stacked 100-Bar, Column, Waterfall, Candlestick and more.

 

Using the UltraDataChart

The UltraDataChart offers powerful ways to interact with data, such as zooming, trendlines and chart synchronization. In addition to all the types supported by the XamChart, UltraDataChart supports polar and radial series types. It enables developers to not only visualize the data, but also enable users to interact with it. The UltraDataChart only supports 2D chart types, and chart types which do not require an axis, such as a pie, and funnel will be implemented by separate controls like the Pie Chart, Funnel Chart etc.

 

How do you use the UltraDataChart

  • Declare the axes (the UltraDataChart supports string (CategoryXAxis, CategoryYAxis, CategoryAngleAxis), numeric (NumericXAxis, NumericYAxis, NumericRadiusAxis, NumericAngleAxis), and date (CategoryDateTimeAxis). In this case we’d like to have dates along the X axis, and numeric values along the Y axis, so we’re using the CategoryDateTimeXAxis and the NumericYAxis.
  • Declare the series, referencing the two axes
  • Declare tooltips

 

Infragistics Windows Forms UltraDataChart High Performance Scenarios

When you’re dealing with real-time or large volumes of data, the three most critical factors for the user experience of your application are performance, performance and…performance! Customers are often interested in the performance of the UltraDataChart (the fast chart component featuring zooming and panning in Infragistics Windows Forms controls). Rather than just say “well, they’re capable of handling millisecond-based updates without noticeable delay in rendering, and are in use at mission-critical applications handling real-time and high-volume data", let's see the chart in action in a few different high performance scenarios!

 

UltraDataChart real-time data scenario

This scenario shows the UltraDataChart bound to a real-time data feed. You can start or stop the real-time data feed by clicking the Toggle Live Data button, and can modify the speed of data update and the amount of data displayed in the chart control using the two sliders above. You can see the time it takes to layout the points in the chart in the label above it, just so you can get an idea of how fast the UltraDataChart really is.

UltraDataChart-Scenarios-Pic01[1]

The source code is available below:

 1:using System;
 2:using System.Collections;
 3:using System.Collections.Generic;
 4:using System.Collections.ObjectModel;
 5:using System.Drawing;
 6:using System.Globalization;
 7:using System.Linq;
 8:using System.Windows.Forms;
 9:using Infragistics.Controls.Charts;
 10:using Infragistics.Extension.Models;
 11:using Infragistics.Extension.Services;
 12:using Infragistics.Win.DataVisualization;
 13:using HorizontalAlignment = Infragistics.Portable.Components.UI.HorizontalAlignment;
 14:  
 15:namespace Infragistics.Samples
 16: {
 17:publicpartialclass SampleForm : Form
 18:     {
 19:#region Default constructor
 20:public SampleForm()
 21:         {
 22:             InitializeComponent();
 23:             Load += OnFormLoaded;
 24:             btnReset.Click += btnReset_Click;
 25:         }
 26:#endregion// Default constructor
 27:  
 28:#region Protected Members
 29:protected DataStockService StockService;
 30:protected UltraDataChart PriceChart;
 31:protected UltraDataChart VolumeChart;
 32:#endregion// Protected Members
 33:  
 34:#region Events
 35:  
 36:#region OnFormLoaded
 37:privatevoid OnFormLoaded(object sender, EventArgs e)
 38:         {
 39:             InitializeForm();
 40:  
 41:             StockService = new DataStockService();
 42:             StockService.DataStockReceived += StockService_DataStockReceived;
 43:  
 44:             var data = StockService.DataPoints;
 45:  
 46:             PriceChart = CreatePriceChart(data);
 47:             VolumeChart = CreateVolumeChart(data);
 48:  
 49:             var table = new TableLayoutPanel
 50:             {
 51:                 Dock = DockStyle.Fill,
 52:                 AutoSizeMode = AutoSizeMode.GrowOnly,
 53:                 GrowStyle = TableLayoutPanelGrowStyle.AddRows
 54:             };
 55:             table.Controls.Add(PriceChart, 0, 1);
 56:             table.Controls.Add(VolumeChart, 0, 2);
 57:  
 58:             PanelCenter.ClientArea.Controls.Add(table);
 59:         }
 60:#endregion// OnFormLoaded
 61:  
 62:#region btnReset_Click
 63:void btnReset_Click(object sender, EventArgs e)
 64:         {
 65:             PriceChart.ResetZoom();
 66:             VolumeChart.ResetZoom();
 67:         }
 68:#endregion// btnReset_Click
 69:  
 70:#region StockService_DataStockReceived
 71:void StockService_DataStockReceived(object sender, DataStockReceivedEventArgs e)
 72:         {
 73://var data = StockService.DataPoints;
 74:             var data = new DataStockList();
 75:             data.AddRange(StockService.DataPoints);
 76:  
 77:             UpdatePriceChart(data);
 78:             UpdateVolumeChart(data);
 79:         }
 80:#endregion// StockService_DataStockReceived
 81:  
 82:#region OnAxisXFormatLabel
 83:string OnAxisXFormatLabel(AxisLabelInfo info)
 84:         {
 85:             var item = info.Item as DataStockPoint;
 86:if (item != null) return item.Date.ToString("yyyy/MM/dd");
 87:  
 88:return info.ToString();
 89:         }
 90:#endregion// OnAxisXFormatLabel
 91:  
 92:#region OnAxisYFormatLabel
 93:string OnAxisYFormatLabel(AxisLabelInfo info)
 94:         {
 95:             var axisValue = info.Value;
 96:if (axisValue < 1000)
 97:returnstring.Format("{0:0.#}", axisValue);
 98:if (axisValue < 1000000)
 99:returnstring.Format("{0:#,0,.#} K", axisValue);
 100:if (axisValue < 1000000000)
 101:returnstring.Format("{0:#,0,,.#} M", axisValue);
 102:if (axisValue < 1000000000000)
 103:returnstring.Format("{0:#,0,,,.#} B", axisValue);
 104:  
 105:return axisValue.ToString();
 106:         }
 107:#endregion// OnAxisYFormatLabel
 108:  
 109:#endregion
 110:  
 111:#region Methods
 112:  
 113:#region InitializeForm
 114:publicvoid InitializeForm()
 115:         {
 116:             speedEditor.ValueChanged += speedEditor_ValueChanged;
 117:             btnStartService.Click += btnStartService_Click;
 118:  
 119:// Add the form's caption as the sample name
 120:             ultraFormManager1.FormStyleSettings.Caption = Properties.Resources.SampleTitle;
 121:  
 122:// Add button images on the form
 123:this.LoadImagesFor(SplitterTop, SplitterRight);
 124:  
 125:// Add the sample description
 126:             sampleInfo.SampleDescription = Resources.SamplesBrowser.SamplesBrowser.SampleDescription;
 127:             sampleInfo.SampleCodeCSharp = Properties.Resources.CS_CodeView;
 128:             sampleInfo.SampleCodeVBasic = Properties.Resources.VB_CodeView;
 129:             sampleInfo.SampleTitle = Properties.Resources.CodeViewerTitle;
 130:  
 131:             speedEditor.PropertyName = Properties.Resources.SpeedEditor_Label;
 132:         }
 133:#endregion// InitializeForm
 134:  
 135:#region CreatePriceChart
 136:public UltraDataChart CreatePriceChart(DataStockList data)
 137:         {
 138:             var chart = new UltraDataChart
 139:             {
 140:                 Width = 400,
 141:                 Height = 200,
 142:                 Dock = DockStyle.Fill,
 143:                 BackColor = System.Drawing.Color.White,
 144:                 PlotAreaBackground = new SolidColorBrush { Color = Color.White },
 145:                 Title = data.CompanyName,
 146:                 Subtitle = Properties.Resources.StockPrice,
 147:                 VerticalZoomable = true,
 148:                 HorizontalZoomable = true
 149:             };
 150:  
 151:             var xAxis = new CategoryXAxis
 152:             {
 153:                 Label = "Date",
 154:                 DataSource = data,
 155:                 LabelLocation = AxisLabelsLocation.OutsideBottom,
 156:                 UseClusteringMode = true
 157:             };
 158:             xAxis.FormatLabel += OnAxisXFormatLabel;
 159:  
 160:             var yAxis = new NumericYAxis
 161:             {
 162:                 LabelExtent = 50,
 163:                 LabelHorizontalAlignment = HorizontalAlignment.Right
 164:             };
 165:             yAxis.FormatLabel += OnAxisYFormatLabel;
 166:  
 167:             var yAxis2 = new NumericYAxis
 168:             {
 169:                 LabelExtent = 20,
 170:                 LabelLocation = AxisLabelsLocation.OutsideRight
 171:             };
 172:  
 173:             var series = new AreaSeries
 174:             {
 175:                 DataSource = data,
 176:                 ValueMemberPath = "Open",
 177:                 XAxis = xAxis,
 178:                 YAxis = yAxis,
 179:                 MarkerType = MarkerType.None,
 180:                 IsHighlightingEnabled = true
 181:             };
 182:  
 183:             chart.Axes.Add(xAxis);
 184:             chart.Axes.Add(yAxis);
 185:             chart.Axes.Add(yAxis2);
 186:             chart.Series.Add(series);
 187:return chart;
 188:         }
 189:#endregion// CreatePriceChart
 190:  
 191:#region CreateVolumeChart
 192:public UltraDataChart CreateVolumeChart(DataStockList data)
 193:         {
 194:             var chart = new UltraDataChart
 195:             {
 196:                 BackColor = System.Drawing.Color.White,
 197:                 PlotAreaBackground = new SolidColorBrush { Color = Color.White },
 198:                 Dock = DockStyle.Fill,
 199:                 Width = 400,
 200:                 Height = 200,
 201:                 Padding = new Padding(0, 0, 20, 0),
 202:                 Subtitle = Properties.Resources.StockVolume,
 203:                 VerticalZoomable = true,
 204:                 HorizontalZoomable = true
 205:             };
 206:  
 207:             var xAxis = new CategoryXAxis
 208:             {
 209:                 Label = "Date",
 210:                 DataSource = data,
 211:                 LabelLocation = AxisLabelsLocation.OutsideBottom
 212:             };
 213:             xAxis.FormatLabel += OnAxisXFormatLabel;
 214:  
 215:             var yAxis = new NumericYAxis
 216:             {
 217:                 LabelExtent = 50,
 218:                 LabelHorizontalAlignment = HorizontalAlignment.Right
 219:             };
 220:             yAxis.FormatLabel += OnAxisYFormatLabel;
 221:  
 222:             var yAxis2 = new NumericYAxis
 223:             {
 224:                 LabelExtent = 20,
 225:                 LabelLocation = AxisLabelsLocation.OutsideRight
 226:             };
 227:  
 228:             var series = new ColumnSeries
 229:             {
 230:                 DataSource = data,
 231:                 ValueMemberPath = "Volume",
 232:                 XAxis = xAxis,
 233:                 YAxis = yAxis,
 234:                 IsHighlightingEnabled = true,
 235:                 IsTransitionInEnabled = false
 236:             };
 237:  
 238:             chart.Axes.Add(xAxis);
 239:             chart.Axes.Add(yAxis);
 240:             chart.Axes.Add(yAxis2);
 241:             chart.Series.Add(series);
 242:return chart;
 243:         }
 244:#endregion// CreateVolumeChart
 245:  
 246:#region UpdatePriceChart
 247:privatevoid UpdatePriceChart(IEnumerable data)
 248:         {
 249:             var DataSource = data asobject[] ?? data.Cast<object>().ToArray();
 250:  
 251:             var series = PriceChart.Series.FirstOrDefault();
 252:if (series != null)
 253:             {
 254:                 series.DataSource = DataSource;
 255:                 series.RenderSeries(false);
 256:             }
 257:  
 258:             var xAxis = PriceChart.Axes[0] as CategoryXAxis;
 259:if (xAxis != null)
 260:             {
 261:                 xAxis.DataSource = DataSource;
 262:                 xAxis.RenderAxis();
 263:             }
 264:         }
 265:#endregion// UpdatePriceChart
 266:  
 267:#region UpdateVolumeChart
 268:privatevoid UpdateVolumeChart(IEnumerable data)
 269:         {
 270:             var DataSource = data asobject[] ?? data.Cast<object>().ToArray();
 271:  
 272:             var series = VolumeChart.Series.FirstOrDefault();
 273:if (series != null)
 274:             {
 275:                 series.DataSource = DataSource;
 276:                 series.RenderSeries(false);
 277:             }
 278:  
 279:             var xAxis = VolumeChart.Axes[0] as CategoryXAxis;
 280:if (xAxis != null)
 281:             {
 282:                 xAxis.DataSource = DataSource;
 283:                 xAxis.RenderAxis();
 284:             }
 285:         }
 286:#endregion// UpdateVolumeChart
 287:  
 288:#region speedEditor_ValueChanged
 289:void speedEditor_ValueChanged(object sender, EventArgs e)
 290:         {
 291:             var value = speedEditor.PropertyValue;
 292:             StockService.UpdateInterval = TimeSpan.FromMilliseconds(value);
 293:         }
 294:#endregion// speedEditor_ValueChanged
 295:  
 296:#region btnStartService_Click
 297:void btnStartService_Click(object sender, EventArgs e)
 298:         {
 299:if (StockService.IsEnabled)
 300:                 StockService.Stop();
 301:else
 302:                 StockService.Start();
 303:         }
 304:#endregion// btnStartService_Click
 305:  
 306:#endregion// Methods
 307:     }
 308:  
 309:#region StockInformation class
 310:publicclass StockInformation
 311:     {
 312:publicstring CompanyName;
 313:publicstring StockSymbol;
 314:     } 
 315:#endregion// StockInformation class
 316: }

 

UltraDataChart high-volume data scenario

The UltraDataChart high-volume data scenario allows the user to set the number of points to be bound to the chart control. You can use big amount of data - this chart can fit more than a year’s worth of data readings taken each second - but feel free to increase that according to the requirements of your scenario. You can try the zooming and panning using the mouse and zoombars to see the level of performance this component delivers when bound to such a high-volume dataset.

When changing only one or two points in data that is bound to the Series object’s DataSource property, you should avoid sending the Reset event from the INotifyCollectionChanged interface. In the prior version of the UltraDataChart control, sending one refresh event instead of several smaller events was preferable.

This code snippet shows how to notify about changes in custom collection using the Add event action instead of the Reset event action when a new data point is added to the collection.

 1:using System.Collections;
 2:using System.Collections.Generic;
 3:using System.Collections.Specialized;
 4:using NotifyEventArgs = System.Collections.Specialized.NotifyCollectionChangedEventArgs;
 5:using NotifyAction = System.Collections.Specialized.NotifyCollectionChangedAction;
 6:  
 7:publicclass DataCollection : INotifyCollectionChanged, IEnumerable
 8: {
 9:protected List Data = new List();
 10:publicevent NotifyCollectionChangedEventHandler CollectionChanged;
 11:protectedvoid OnCollectionChanged(NotifyEventArgs e)
 12:         {
 13:if (CollectionChanged != null)
 14:             {
 15:                 CollectionChanged(this, e);
 16:             }
 17:         } 
 18:public IEnumerator GetEnumerator()
 19:         {
 20:returnthis.Data.GetEnumerator();
 21:         } 
 22:publicvoid Add(DataPoint dataPoint)
 23:         {
 24:this.Data.Add(dataPoint);
 25:             NotifyEventArgs e = new NotifyEventArgs(NotifyAction.Add, dataPoint);
 26:// use the Add event action instead of the Reset event action 
 27:// when adding only one or two points to the collection
 28://NotifyEventArgs e = new NotifyEventArgs(NotifyAction.Reset);
 29:this.OnCollectionChanged(e);
 30:         } 
 31: } 

 

Motion Framework

You can animate data over time using the innovative Motion Framework, create composite charts, and use multiple series with our new Windows Forms Data Chart control. This approach is used mainly when you have multidimensional data and one of the dimensions is time. You can demonstrate how values are changed during the time using awesome animations.

 

UltraDataChart-Scenarios-Pic02[1]

 

This sample demonstrates how to use the Motion Framework™ with the DataChart control to build highly engaging visualizations and provide smooth playback of changes in data over time.

 1:using Infragistics.Extension;
 2:  
 3:namespace Infragistics.Samples
 4: {
 5:partialclass MotionFramework
 6:     {
 7:/// 
 8:/// Required designer variable.
 9:/// 
 10:private System.ComponentModel.IContainer components = null;
 11:  
 12:/// 
 13:/// Clean up any resources being used.
 14:/// 
 15:///true if managed resources should be disposed; otherwise, false.
 16:protectedoverridevoid Dispose(bool disposing)
 17:         {
 18:if (disposing && (components != null))
 19:             {
 20:                 components.Dispose();
 21:             }
 22:base.Dispose(disposing);
 23:         }
 24:  
 25:#region Windows Form Designer generated code
 26:  
 27:/// 
 28:/// Required method for Designer support - do not modify
 29:/// the contents of this method with the code editor.
 30:/// 
 31:privatevoid InitializeComponent()
 32:         {
 33:this.components = new System.ComponentModel.Container();
 34:             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MotionFramework));
 35:this.ultraFormManager1 = new Infragistics.Win.UltraWinForm.UltraFormManager(this.components);
 36:this._CardView_UltraFormManager_Dock_Area_Left = new Infragistics.Win.UltraWinForm.UltraFormDockArea();
 37:this._CardView_UltraFormManager_Dock_Area_Right = new Infragistics.Win.UltraWinForm.UltraFormDockArea();
 38:this._CardView_UltraFormManager_Dock_Area_Top = new Infragistics.Win.UltraWinForm.UltraFormDockArea();
 39:this._CardView_UltraFormManager_Dock_Area_Bottom = new Infragistics.Win.UltraWinForm.UltraFormDockArea();
 40:this.MainPanel = new Infragistics.Win.Misc.UltraPanel();
 41:this.PanelCenter = new Infragistics.Win.Misc.UltraPanel();
 42:this.SplitterRight = new Infragistics.Win.Misc.UltraSplitter();
 43:this.PanelRight = new Infragistics.Win.Misc.UltraPanel();
 44:this.btnToggleAnimation = new Infragistics.Win.Misc.UltraButton();
 45:this.SplitterTop = new Infragistics.Win.Misc.UltraSplitter();
 46:this.PanelTop = new Infragistics.Win.Misc.UltraPanel();
 47:this.sampleInfo = new Infragistics.Extension.SampleInfoControl();
 48:             ((System.ComponentModel.ISupportInitialize)(this.ultraFormManager1)).BeginInit();
 49:this.MainPanel.ClientArea.SuspendLayout();
 50:this.MainPanel.SuspendLayout();
 51:this.PanelCenter.SuspendLayout();
 52:this.PanelRight.ClientArea.SuspendLayout();
 53:this.PanelRight.SuspendLayout();
 54:this.PanelTop.ClientArea.SuspendLayout();
 55:this.PanelTop.SuspendLayout();
 56:this.SuspendLayout();
 57:// 
 58:// ultraFormManager1
 59:// 
 60:this.ultraFormManager1.Form = this;
 61:this.ultraFormManager1.FormStyleSettings.FormDisplayStyle = Infragistics.Win.UltraWinToolbars.FormDisplayStyle.StandardWithRibbon;
 62:this.ultraFormManager1.UseOsThemes = Infragistics.Win.DefaultableBoolean.False;
 63:// 
 64:// _CardView_UltraFormManager_Dock_Area_Left
 65:// 
 66:this._CardView_UltraFormManager_Dock_Area_Left.AccessibleRole = System.Windows.Forms.AccessibleRole.Grouping;
 67:this._CardView_UltraFormManager_Dock_Area_Left.BackColor = System.Drawing.SystemColors.Control;
 68:this._CardView_UltraFormManager_Dock_Area_Left.DockedPosition = Infragistics.Win.UltraWinForm.DockedPosition.Left;
 69:this._CardView_UltraFormManager_Dock_Area_Left.ForeColor = System.Drawing.SystemColors.ControlText;
 70:this._CardView_UltraFormManager_Dock_Area_Left.FormManager = this.ultraFormManager1;
 71:this._CardView_UltraFormManager_Dock_Area_Left.InitialResizeAreaExtent = 8;
 72:             resources.ApplyResources(this._CardView_UltraFormManager_Dock_Area_Left, "_CardView_UltraFormManager_Dock_Area_Left");
 73:this._CardView_UltraFormManager_Dock_Area_Left.Name = "_CardView_UltraFormManager_Dock_Area_Left";
 74:// 
 75:// _CardView_UltraFormManager_Dock_Area_Right
 76:// 
 77:this._CardView_UltraFormManager_Dock_Area_Right.AccessibleRole = System.Windows.Forms.AccessibleRole.Grouping;
 78:this._CardView_UltraFormManager_Dock_Area_Right.BackColor = System.Drawing.SystemColors.Control;
 79:this._CardView_UltraFormManager_Dock_Area_Right.DockedPosition = Infragistics.Win.UltraWinForm.DockedPosition.Right;
 80:this._CardView_UltraFormManager_Dock_Area_Right.ForeColor = System.Drawing.SystemColors.ControlText;
 81:this._CardView_UltraFormManager_Dock_Area_Right.FormManager = this.ultraFormManager1;
 82:this._CardView_UltraFormManager_Dock_Area_Right.InitialResizeAreaExtent = 8;
 83:             resources.ApplyResources(this._CardView_UltraFormManager_Dock_Area_Right, "_CardView_UltraFormManager_Dock_Area_Right");
 84:this._CardView_UltraFormManager_Dock_Area_Right.Name = "_CardView_UltraFormManager_Dock_Area_Right";
 85:// 
 86:// _CardView_UltraFormManager_Dock_Area_Top
 87:// 
 88:this._CardView_UltraFormManager_Dock_Area_Top.AccessibleRole = System.Windows.Forms.AccessibleRole.Grouping;
 89:this._CardView_UltraFormManager_Dock_Area_Top.BackColor = System.Drawing.SystemColors.Control;
 90:this._CardView_UltraFormManager_Dock_Area_Top.DockedPosition = Infragistics.Win.UltraWinForm.DockedPosition.Top;
 91:this._CardView_UltraFormManager_Dock_Area_Top.ForeColor = System.Drawing.SystemColors.ControlText;
 92:this._CardView_UltraFormManager_Dock_Area_Top.FormManager = this.ultraFormManager1;
 93:             resources.ApplyResources(this._CardView_UltraFormManager_Dock_Area_Top, "_CardView_UltraFormManager_Dock_Area_Top");
 94:this._CardView_UltraFormManager_Dock_Area_Top.Name = "_CardView_UltraFormManager_Dock_Area_Top";
 95:// 
 96:// _CardView_UltraFormManager_Dock_Area_Bottom
 97:// 
 98:this._CardView_UltraFormManager_Dock_Area_Bottom.AccessibleRole = System.Windows.Forms.AccessibleRole.Grouping;
 99:this._CardView_UltraFormManager_Dock_Area_Bottom.BackColor = System.Drawing.SystemColors.Control;
 100:this._CardView_UltraFormManager_Dock_Area_Bottom.DockedPosition = Infragistics.Win.UltraWinForm.DockedPosition.Bottom;
 101:this._CardView_UltraFormManager_Dock_Area_Bottom.ForeColor = System.Drawing.SystemColors.ControlText;
 102:this._CardView_UltraFormManager_Dock_Area_Bottom.FormManager = this.ultraFormManager1;
 103:this._CardView_UltraFormManager_Dock_Area_Bottom.InitialResizeAreaExtent = 8;
 104:             resources.ApplyResources(this._CardView_UltraFormManager_Dock_Area_Bottom, "_CardView_UltraFormManager_Dock_Area_Bottom");
 105:this._CardView_UltraFormManager_Dock_Area_Bottom.Name = "_CardView_UltraFormManager_Dock_Area_Bottom";
 106:// 
 107:// MainPanel
 108:// 
 109:// 
 110:// MainPanel.ClientArea
 111:// 
 112:this.MainPanel.ClientArea.Controls.Add(this.PanelCenter);
 113:this.MainPanel.ClientArea.Controls.Add(this.SplitterRight);
 114:this.MainPanel.ClientArea.Controls.Add(this.PanelRight);
 115:this.MainPanel.ClientArea.Controls.Add(this.SplitterTop);
 116:this.MainPanel.ClientArea.Controls.Add(this.PanelTop);
 117:             resources.ApplyResources(this.MainPanel, "MainPanel");
 118:this.MainPanel.Name = "MainPanel";
 119:// 
 120:// PanelCenter
 121:// 
 122:this.PanelCenter.BorderStyle = Infragistics.Win.UIElementBorderStyle.None;
 123:             resources.ApplyResources(this.PanelCenter, "PanelCenter");
 124:this.PanelCenter.Name = "PanelCenter";
 125:// 
 126:// SplitterRight
 127:// 
 128:this.SplitterRight.BackColor = System.Drawing.SystemColors.Control;
 129:             resources.ApplyResources(this.SplitterRight, "SplitterRight");
 130:this.SplitterRight.Name = "SplitterRight";
 131:this.SplitterRight.RestoreExtent = 250;
 132:// 
 133:// PanelRight
 134:// 
 135:this.PanelRight.AutoScroll = true;
 136:this.PanelRight.BorderStyle = Infragistics.Win.UIElementBorderStyle.None;
 137:// 
 138:// PanelRight.ClientArea
 139:// 
 140:this.PanelRight.ClientArea.Controls.Add(this.btnToggleAnimation);
 141:             resources.ApplyResources(this.PanelRight, "PanelRight");
 142:this.PanelRight.Name = "PanelRight";
 143:// 
 144:// btnToggleAnimation
 145:// 
 146:             resources.ApplyResources(this.btnToggleAnimation, "btnToggleAnimation");
 147:this.btnToggleAnimation.Name = "btnToggleAnimation";
 148:this.btnToggleAnimation.ShowFocusRect = false;
 149:// 
 150:// SplitterTop
 151:// 
 152:this.SplitterTop.BackColor = System.Drawing.SystemColors.Control;
 153:             resources.ApplyResources(this.SplitterTop, "SplitterTop");
 154:this.SplitterTop.Name = "SplitterTop";
 155:this.SplitterTop.RestoreExtent = 100;
 156:// 
 157:// PanelTop
 158:// 
 159:this.PanelTop.BorderStyle = Infragistics.Win.UIElementBorderStyle.None;
 160:// 
 161:// PanelTop.ClientArea
 162:// 
 163:this.PanelTop.ClientArea.Controls.Add(this.sampleInfo);
 164:             resources.ApplyResources(this.PanelTop, "PanelTop");
 165:this.PanelTop.Name = "PanelTop";
 166:this.PanelTop.Tag = "Top";
 167:// 
 168:// sampleInfo
 169:// 
 170:             resources.ApplyResources(this.sampleInfo, "sampleInfo");
 171:this.sampleInfo.BackColor = System.Drawing.Color.Transparent;
 172:this.sampleInfo.Name = "sampleInfo";
 173:this.sampleInfo.SampleCodeCSharp = resources.GetString("sampleInfo.SampleCodeCSharp");
 174:this.sampleInfo.SampleCodeVBasic = null;
 175:this.sampleInfo.SampleDescription = null;
 176:this.sampleInfo.SampleTitle = "Code Viewer";
 177:// 
 178:// MotionFramework
 179:// 
 180:             resources.ApplyResources(this, "$this");
 181:this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
 182:this.Controls.Add(this.MainPanel);
 183:this.Controls.Add(this._CardView_UltraFormManager_Dock_Area_Left);
 184:this.Controls.Add(this._CardView_UltraFormManager_Dock_Area_Right);
 185:this.Controls.Add(this._CardView_UltraFormManager_Dock_Area_Top);
 186:this.Controls.Add(this._CardView_UltraFormManager_Dock_Area_Bottom);
 187:this.Name = "MotionFramework";
 188:             ((System.ComponentModel.ISupportInitialize)(this.ultraFormManager1)).EndInit();
 189:this.MainPanel.ClientArea.ResumeLayout(false);
 190:this.MainPanel.ResumeLayout(false);
 191:this.PanelCenter.ResumeLayout(false);
 192:this.PanelRight.ClientArea.ResumeLayout(false);
 193:this.PanelRight.ResumeLayout(false);
 194:this.PanelTop.ClientArea.ResumeLayout(false);
 195:this.PanelTop.ClientArea.PerformLayout();
 196:this.PanelTop.ResumeLayout(false);
 197:this.ResumeLayout(false);
 198:  
 199:         }
 200:  
 201:#endregion
 202:  
 203:private Infragistics.Win.UltraWinForm.UltraFormManager ultraFormManager1;
 204:private Infragistics.Win.UltraWinForm.UltraFormDockArea _CardView_UltraFormManager_Dock_Area_Left;
 205:private Infragistics.Win.UltraWinForm.UltraFormDockArea _CardView_UltraFormManager_Dock_Area_Right;
 206:private Infragistics.Win.UltraWinForm.UltraFormDockArea _CardView_UltraFormManager_Dock_Area_Top;
 207:private Infragistics.Win.UltraWinForm.UltraFormDockArea _CardView_UltraFormManager_Dock_Area_Bottom;
 208:private Infragistics.Win.Misc.UltraPanel MainPanel;
 209:private Infragistics.Win.Misc.UltraSplitter SplitterTop;
 210:private Infragistics.Win.Misc.UltraPanel PanelTop;
 211:private Infragistics.Win.Misc.UltraSplitter SplitterRight;
 212:private Infragistics.Win.Misc.UltraPanel PanelRight;
 213:private Infragistics.Win.Misc.UltraPanel PanelCenter;
 214:private SampleInfoControl sampleInfo;
 215:private Win.Misc.UltraButton btnToggleAnimation;
 216:     }
 217: }

 

Summary

The UltraDataChart is a powerful charting control, enabling users to browse and interact with data in a much richer way using zooming, inter-chart synchronization and tooltips. With a variety of series types and built-in trendlines, it’s fully capable of handing your charting scenarios. Talk to users of your applications and ask them where they can benefit from browsing their data in a visual way.

The Infragistics Windows Forms Data Visualization controls also offer a wide range of options to create almost any dashboard that you need. In this post we discussed how to use Infragistics UltraDataChart , but you can see samples of how to use any of other data visualization components on the Infragistics Windows Forms Samples Browser. There, you'll find detailed information about the control and its features and how to configure its separate parts in the API documentation as well as the online help documentation.

To play around with the Infragistics Windows Forms dashboards on your own, be sure to get Infragistics Ultimate and see the chart in action in our latest sample application by clicking the banner below!

Developer News - What's IN with the Infragistics Community? (2/16-2/22)

Open source .NET: A progress report

$
0
0

Microsoft surprised both their friends and rivals when they announced they would open source .NET Core in November 2014. Although now widely available on GitHub, it’s worth noting that not everything is open source just yet and is still work in progress.

However, before we get ahead of ourselves, we should ask the question, just what is .NET Core? To be clear, it is not the entire .NET Framework. Microsoft decided to rebuild their .NET Framework gradually as an open source project and has named that .NET Core. The probable reason is that the code for their .NET Framework is not suitable to release as open source at this stage.

.NET Core is a modular development stack that is the foundation of all future .NET platforms. However, it’s not a replacement for the .NET Framework; it offers only a subset of functionality currently available in the .NET Framework. Developers should therefore bear in mind that when building large enterprise applications for example, the .NET Framework is still the way to go.

A follow up blog post here explains in detail .NET Core and its relationship with the .NET Framework. In Visual Studio 2015, .NET Core will be a pure subset of the .NET Framework. Anything available in .NET Core is therefore also available in the .NET Framework. However, as .NET Core is open source, it will most likely evolve quicker than the .NET Framework. It might happen that .NET Core will have features that are not available in the .NET Framework.

How to contribute to .NET Core?

You may well be thinking about contributing to .NET Core, indeed Microsoft is actively encouraging users to do so; one reason for making .NET Core open source was to benefit from the contribution of the community. However, just as with any major open source project, not all contributions can be accepted. There is still a road map and not every contribution will fit in this road map.

This post in the Visual Studio magazine outlines five excellent tips for those planning on contributing to .NET Core. It includes important links to external websites, for example to Microsoft’s GitHub repository and the .NET contribution guidelines.

The first and most important rule for contributions is: "unless it is a trivial change, make sure that there is a corresponding issue for your change first. If there is none, create one”. An issue is very important, so the reason behind a change can be recorded and, more importantly, it gives an insight as to how popular an issue is - it doesn’t make sense to introduce a breaking change to fix an issue nobody cares about.

The .NET Foundation - some background

As there are many open source .NET projects on the web, the .NET Foundation organization was created. It provides a developer forum, a test bed, and a practice ground for the very rapidly growing community that contributes to open source .NET projects like .NET Core. Another great benefit is that it allows for direct access to .NET project teams at Microsoft and across the community.

Overall the idea of the .NET Foundation is to streamline the contribution to open source .NET projects and to improve the quality of the processes and developed products. Read this “Get involved” page for more information or jump straight to the forums.

Roslyn: the next compiler

As part of the introduction of open source .NET Core, a new compiler was presented: The Roslyn compiler, which is also available on GitHub. The idea of making the compiler open source is to allow contributions from non-Windows compilers. Creating and running .NET projects always previously required a Windows based operating system. With the compiler becoming open source, this is no longer a limitation. It is now even possible to create a .NET application in Linux, written in vi, and compiled from the Linux terminal!

Another great benefit is the option for developers to create custom components for the compiler. It’s easier to investigate the compiler and create custom components when it’s open source. Take a look at some of the samples and walkthroughs.

What’s next?

Microsoft has clearly changed their strategy and one of the results of this shift is the open sourcing of .NET Core and the Roslyn compiler. This is quite different from a couple of years ago, where everything was “Microsoft only” and closed source. For developers this is particularly interesting, as it’s now possible to contribute to the very popular .NET Core.

And, what’s next? Will Microsoft release more (or even all) of their code as open source project? Will Windows be made open source? Many voices have been saying for some time that Internet Explorer should be made open source and it’s interesting to see if there will be an open source element to the new Spartan browser too. We wait and see.

Developer Humor: Salary Concerns

$
0
0

This series needs no introduction... one of my favorite new comics for 2015, and definitely worth at least a hump-day smirk: Salary Concerns!

Salary Concerns by Infragistics WinForms Controls

Share With The Code Below!

<a href="http://www.infragistics.com/products/windows-forms"><img src="http://www.infragistics.com/community/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/d-coding/8664.Tech-toon-_2D00_-2015-_2D00_-med-res-01.jpg" height="825" width="636" /> </a><br /><br /><br />Conversion Confusion by Infragistics <a href="http://www.infragistics.com/products/windows-forms">WinForms Controls</a>

Conversion Confusion by Infragistics WinForms Controls
Viewing all 2223 articles
Browse latest View live