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

Infragistics WPF Release Notes - June 2019: 18.2, 19.1 Service Release

$
0
0

Release notes reflect the state of resolved bugs and new additions from the previous release. You will find these notes useful to help determine the resolution of existing issues from a past release and as a means of determining where to test your applications when upgrading from one version to the next.

Release notes are available in both PDF and Excel formats. The PDF summarizes the changes to this release along with a listing of each item. The Excel sheet includes each change item and makes it easy for you to sort, filter and otherwise manipulate the data to your liking.

In order to download release notes, use the following links:

WPF 2018 Volume 2 Service Release (Build 18.2.20182.XXXX)

PDF - Infragistics for WPF 2018 Volume 2
Excel - Infragistics for WPF 2018 Volume 2

WPF 2019 Volume 1 Service Release (Build 19.1.20191.XXXX)

PDF - Infragistics for WPF 2019 Volume 1
Excel - Infragistics for WPF 2019 Volume 1

WPF UI Controls


Software Performance [Web]

$
0
0
Performance is one of the most important, if not the most important, vectors that should be considered when producing software products.(read more)

Introducing Product Team Office Hours

$
0
0

Let’s face it, developers don’t really like talking to sales departments or interacting with marketing.  While sales and marketing are very important roles to just about every company in existence, they just don’t have that very low-level knowledge of a product that developers expect. A lot of times, developers can feel frustrated that the questions they have must go though a “middle-man” to be passed along to a more technical person, and wait for the response loop to close. This could take days or weeks in some cases.

I truly empathize with you all, and we want to improve this experience for all Infragistics developers.  Starting this month, I am excited to announce the introduction of the Product Team Office Hours. We’ll be hosting an online, interactive session that anyone can attend.  Are you a customer looking for more information on a recent release or what’s coming next? Are you considering Infragistics and just want to learn what we’re all about and what the most recent updates are?  Everyone is invited!  All of the key players on our side will be available in the meeting, including me, and the product teams responsible for delivering the products that you use every day.  We will talk about what we have been working on, what we are currently working on, and what we plan on working on very soon.  And then of course, anything you want to talk about.  This will be a two-way conversation between you, me, and the product teams.

So how will this work? Very soon, we will be sending emails to our current customers and promoting invites via our social media accounts encouraging everyone interested in attending our Product Team Office Hours to register for the Office Hours mailing list.  You will only receive Product Team Office Hours meeting invites if you have registered for the Office Hours mailing list. Don't worry, you only have to register once and then you're good to go. We just need to know who wants to participate and where to send the meeting invites. In case you're wondering, yes, you can unsubscribe at anytime. But trust me, you won't want to!

Save the Date!  The first Product Team Office Hours is going to be held on July 25th at 9am PST (11am EST).  So make sure you keep an eye on your email, especially the junk folder, as well as your social media accounts, because will be sending out invites in the next week or so.  If you don't get the invite in your email inbox, or don't see the invite come through on social media, please send me an email at blagunas@infragistics.com or connect with me via Twitter, and I'll send you the direct link to the registration page.

So, what do you think? Do you like this idea?  Let me know your feedback by following and engaging with me on Twitter at @brianLagunas.  You can also subscribe to my YouTube channel to be notified of new videos, and follow me on Twitch to watch me stream live.

Data Driven Teams and Organizations

$
0
0
See how easy it is to create data-driven teams with the Reveal business intelligence platform. Find out how Reveal's simplicity brings beautiful visualizations to analytics.(read more)

The Pricing Secret: What Embedded Analytics Vendors Won't Tell You

$
0
0
Find out why many embedded analytics vendors keep their costs hidden. Reveal pricing is simple, fixed and predictable.(read more)

Getting to Know the Reveal Visualization Editor

$
0
0

If you have been using Reveal, you know how easy it is to create dashboards with any number of data sources. Reveal is built by user experience experts and made for business users. It has a familiar drag and drop experience that makes it simple to use. However, the visualization editor is packed with features that you might not even know about. Today we are going to walk you through each section of the editor and show you all the capabilities Reveal has.

Fields


All of the available fields within your data source will appear on the left panel. Each field has an indicator that informs the users what field type each field is: Date, Value, Text. The plus icon in this panel allows you to either blend data sources or calculate a field:

  • Blend Data Source: This is a powerful feature that allows you to bring in fields from another source and join them based on a common field.
  • Calculated Field: Allows you to define new fields built based on expression using the existing fields.

Visualization Fields

Here is where you will drag and drop, or click the + mark to see the available fields and select those you want to use for the visualization you are creating.

Visualization Workspace

Here is where you will be able to see the visualization you are creating or editing as you drag and drop fields. The visualization won't populate until you have all the necessary fields needed to create that chart type.

Data Source

The data source that you are currently working with will be displayed here. With a click you can change between the different sheets, tables or views within your source or change your connection to a new source entirely without having to leave the editor.

Visualization Picker

Switch between any of our 30+ different visualizations using the dropdown picker. As you switch between the different chart types you will notice the visualization fields section change. This is where Reveal takes ease of use to a new level! We will provide you all the necessary fields you need to fill in for a given visualization type – eliminating the need to make you think. Once all the fields needed to create a beautiful chart are there – your chart will display in the visualization workspace section.

Visualization Settings

Each visualization comes with its own settings that allow you to customize what you want to show: 

  • Grid: show title, alignment of your fields, font size, fixed first column
  • Pivot Grid: show title, alignment of your fields, font size, grand totals
  • Column, Bar, Line, Area, Step Area, Step Line, Spline, Spline Area: show title, show legend, start color, chart trendline, axis configuration, axis bounds
  • Stacked Column, Stacked Bar, Stacked Area: show title, show legend, start color, percentage distribution, axis configuration, axis bounds
  • Text: show title, conditional formatting bounds for indicator
  • Text, Web View: show title
  • Pie, Doughnut, Funnel: show title, show legend, start color, start position, slice label formatting
  • Circular Gauge, Linear Gauge, Bullet Graph: show title, limits, conditional formatting bounds for indicator
  • KPI vs Time, KPI vs Target: show title, time period, difference formatting, indicator color
  • OHLC, Candlestick: show title, axis configuration, axis bounds
  • Radial: show title, show legend, start color, chart trendline
  • Sparkline: show title, alignment for fields, font size, chart type, number of months shown, how last two columns, show difference column, indicator color

Within each of these settings screen you will see the option for links. This is a powerful feature that takes drill down to a whole new level. Link a visualization to a totally new dashboard to show more detail with one click. Or link out to a URL that provides deeper insights for your users.

Interested in building your own dashboards? Download a free trial of Reveal now, or contact us to see the wonders it can do for your team’s productivity!

How to Create Your First Business Intelligence Dashboard with Reveal

$
0
0

If you are not familiar with creating dashboards, it can be a little overwhelming trying to figure out how to connect to all the data you have in different systems and build a dashboard to bring all your data together into a full 360-degree view of your business.

Reveal is self-service, business intelligence software that enables you to visualize your significant business metrics, like marketing performance, monitoring operational trends, visualizing KPIs, and optimizing customer portfolios, in one centralized location. To show you how to achieve this quickly this blog will walk you through the following steps using a sample data Excel file provided to you inside the application:

  1. Connect to an Excel file
  2. Create visualizations
  3. Change the theme of a dashboard
  4. Save your dashboard
  5. Share your dashboard with your team

At the end, your dashboard will look like this:

Steps to Data Insights

When you come into Reveal for the first time you will be presented with the different samples that we built for you to explore. To begin creating your own, navigate to the Dashboards section on the left panel. Click the new button in the top right-hand corner and select dashboard.

To add your first visualization click the plus in the upper right corner. Here is where you will be able to choose your first data source to connect to your data: 

Within OneDrive I navigate to the file I am looking to bring into my dashboard. Once I select my excel file Reveal will bring in the different sheets I have within that file with their names (Marketing, Sales). In addition, I can choose how often I want my data to sync to my dashboard. Here you can see I selected once an hour.

Once you select your sheet you will be brought into the widget editor. On the left hand side, you will see all the columns within that excel sheet along with an indicator for what type of field they are (Date, Value, Category). On the top bar is where you can select your visualization types.

As you begin dragging fields over to the columns field you will see your data start to populate on the right. Or, if you know the visualization you want to create you can select that first! Reveal will change the input fields to let you know exactly what you need in order to create that visual.

To show new sales over time follow these steps:

  1. Select line chart from the visualization list                                                                            
  2. Drag Date over to label and New Sales over to Values
  3. Click the Date field you dragged over to change the date aggregation from year to month
  4. Click the New Sales field you dragged over and change the formatting from number to currency and fraction digits to 0
  5. Change the title to New Sales by Month                                                                                
  6. Click the check mark in the upper right corner

Just like that you have your first visualization!

Adding Filters to Dashboards

Now, let's add a dashboard filter so you can view a different date range on the fly.

  1. Click the add filter button on the top left under your dashboard title and select date filter.          *note: You can use this to filter using any field within your data source by selecting add Dashboard Filter
  2. Within the date filter, select a range to set your data to. Use the dropdown to select Trailing 12 Months
  3. Underneath that you will see the visualization you created listed. If you had created more than one prior to adding this filter that would appear here as well. To connect the visualization to your dashboard filter click connect on the visualization thumbnail. Reveal will automatically connect to the date field within your data source.            *note: if you have more than one date field within the excel file and need to switch the one it connects to you can use the overflow menu to edit the connection
  1. Once connected click the create filter button at the bottom of the dialog window and see your data pivot to the filter.

To create another visualization, you have several options:

  1. Click the plus icon on the top right menu bar. Reveal will first list the data you already have within that dashboard. This enables you to create from the same source quickly. You can also add a new source to this dashboard, bringing multiple data sources into one view.
  2. Click the overflow menu on the visualization and select it. This will not only duplicate the fields inside the visualization but also the connection to the dashboard filter if you have one. From here you can quickly go into edit the visualization and change out some fields, change the visualization and more to create a new view.
  3. Click the overflow menu and select copy. You can now paste this visualization right here or navigate to another dashboard to reuse it!

Here are three more powerful visualizations inside the editor to give you ideas on how you can add more to your dashboard:

  1. Leads by Product                                                                                                         
  2. Renewal Seats by Territory                                                                                          
  3. Seats Sold by Sales Rep                                                                                              

 

Once you have your visualizations created, you can begin to adjust the size and order of them within your dashboard. Simply click on a visualization to drag it around or to use the nodes to resize it.

*Note: Auto Layout is on by Default until your resize a visualization

Next, using the overflow menu pick a new theme for your dashboard from any of Reveal's built in options. 

Once you are happy with how your dashboard looks, give it a title and click the check in the upper right corner. You will them be prompted to save it and to choose where you want to save your dashboard. By default, it selects the location where you started creating your dashboard. Along with the option to save to your personal space, (pending permission level), you can save this dashboard to your organization repository or any of the teams that you are a part of.

Just like that you have a beautiful dashboard!

Interested in building your own dashboards? Download a free trial of any of our Reveal platforms now, or contact us to see the wonders it can do for your team’s productivity!

Design elaborate grid experiences with indigo.design and generate Angular apps out of them.

$
0
0

On Monday we have launched yet another amazing update to indigo.design including vast improvements to the UI Kit for Sketch, especially in the area of the Grid component. In the latest release available in your indigo.design cloud account, we also managed to squeeze tree and hierarchical grids with all the features that the regular, flat grid offers. In this short article I will walk you through the creation of a seemingly simple grid design with a lot of feature horsepower under the hood.

  1. We will start by inserting the following grid pattern from the Indigo-Patterns library file "Grid/Pinning+Row Selection+Active Cell". Yes, we have created some feature presets for you available as patterns to speed up your design process and guide you on the proper way to configure features on the grid both in terms of look and generation of code.
  2. Upon performing "Detach from Symbol" on the added pattern we can already discover how some of the grid features have been configured. Row selection, for example, is achieved by inserting an additional column to the left of the grid and using "Checkbox" for the "Type" of the "Body" and "Header" cells of the whole column.
  3. To further elaborate things, we may set the "State" to one of the "Body" cells to "On" and configure all the cells belonging to that row as "RowSelected" cells via the "Grid Feature" override.

  4. The "Header" cells are much more interesting, however, since through them are enabled many of the functionalities on the grid, since they are column-specific. This is the case with column pinning and since we would like to have two narrow pinned columns we will slightly rearrange columns 2,3 and 4 of the grid to achieve the following layout.
  5. After renaming the Status column header to Sr. No. and the Progress one to SKU, we will proceed by selecting both and setting their "Feature Right" to "Pinning", of course, that will show an override for the "State", which should be set to "Unpin"."Feature Right" and "Feature Left" overrides support identical values ("Filtering" "Pinning" "Sorting") allowing for configuration of the corresponding features on the grid and column in particular
  6. We will continue by disabling the pinning on the Subject column via the "Feature Right" being set to "None" and there is one small detail to take care of - the right border. Since the right-most pinned column has a thick right border we need to set the "Right Border" override of all cells belonging to the SKU column to "Pinned Line" and for all cells belonging to the Subject column to "None".

  7. While scrolling down to the "Right Border" override you may have come across a set of overrides for "Editing", "Column Moving", "Column Resizing", and "Column Hiding" that are responsible for the corresponding grid functionalities. Of course, when properly set, all the overrides so far will be interpreted by our code generation engine when creating an Ignite UI for Angular grid.

  8. Before we go on with adding more features to the grid, let's stop for a moment and edit the rest of the headers and all the body cells to contain some actual data. I have decided to depict some typical data for an order and therefore besides Sr. No. and SKU I will add some more columns like Description, Quantity, Price, Final Cost, and Total, as well as, two columns for actions on the record: Comment and Remove. 
  9. After filling in all the body cells with appropriate values, changing the cell "Type" to "Number" for the numeric values and configuring the "Type" of the last two columns' body cells to "Icon" we are more or less ready to go on and add some more features to the grid. Of course, to polish up things for the actions columns we may want to pick an appropriate icon glyph and color for it from the possibilities ensured by the Indigo-Styling library.
                
  10. Before wrapping up our design we will also take a look at configuring the active cell of the grid, it is usually the cell that moves the focus while we browse the grid via the keyboard. This is done very easily as the "State" override of every body cell can be set to "Cell:active" in order for the cell to receive an additional style that is applied on top of any other underlying styles the cell may have.

  11. Now with the data we have used it becomes quite obvious that the grid is sorted according to the Sr. No. column and let's add an indication for that by selecting the header, navigating to "Feature Left" override (we already used the right one for pinning) and setting it to "Sorting". The order of the grids tells us that for the "Sorting State" we should choose "Ascending" and we are ready to add a couple of final elements.

  12. Orders often have a notion of total quantity/size to estimate shipment and total value of the content to estimate insurance or invoice the recipient. We will reflect this by adding a summary row and to achieve this let's insert form "Grid/Features/Sumamries" the symbol denoted as "Comfortable". If we were to click on any of the header and body cells, we will also find the Comfortable signifier for the symbol in the right panel. The grid as well as some other components nave this notion of Display Density, which may be one of these three values: Comfortable, Cosy and Compact. In the case of a grid cell they more or less tell it how high it is and what are its internal padding such that Comfortable cells always have more air than Cosy ones, and the Compact cells are always the most dense arrangements with minimal paddings.
  13. After performing "Detach from Symbol" on the Comfortable summaries create a layout with the cells at hand that show a single row of summaries with "State" configured as "Summary:unavailable" for all columns except for Quantity and Total ones, where appropriate values need to be provided.

The last feature that we will add to the grid will be Export to Excel and CSV, for which we need to insert a "Toolbar" from "Grid/Features" and set the "Action 1" override to none since we don't have column hiding enabled on any of the columns. However, since we enabled pinning on a couple of columns, the rest of the actions will be left intact. Once we set the "Title" of the "Toolbar" to have relevant content for the order like the order number for example, and voilà! our grid design is complete.

Below are some useful link for you to discover... 

 how the attached Sketch design file is arranged
 and inspect the prototype on Indigo.Design Cloud
 the Angular Code on StackBlitz

Get started with Indigo.Design

Don't stop with prototypes; get it in the hands of real users with our 1-click sharing, and the ability to view prototypes on any device. Harness the power of Indigo.Design Cloud for recording user sessions and task analytics

Get Indigo.Design Professional starting at $39/mo for a complete UX prototyping solution. Want Code Generation? Get Indigo.Design Enterprise for $99/month!


How Reveal BI Secures Your Data

$
0
0
The Reveal embedded business intelligence platform is based on a cloud architecture that includes multiple authentication methods , local caching of data to minimize sending of queries to servers and databases, and much more. We'll explore these in this...(read more)

Ignite UI for Angular 8.1.0 Release

$
0
0

Almost one month has passed since we’ve released our last major version and we are already producing a new one   We carefully evaluate our customer’s feature requests and work on the most wanted features not listed in the product Roadmap. And that’s not all, last month we’ve fixed over 60 bugs, added new components styling guides, a series of WPF to WEB migration topics and we’ve started to develop our Ignite UI Medium publication profile (if you are interested in “Software Performance”, check out our latest article on the subject).

Let’s see what we’ve prepared for you this release.

New Components

IgxSparkline - The Ignite UI for Angular Sparkline component is a lightweight charting control. It is intended for rendering within a small scale layout such as within a grid cell, but can also be rendered alone. 

IgxZoomSlider - The ZoomSlider control provides zooming functionality to range-enabled controls. The ZoomSlider features a horizontal scroll bar, a thumbnail of the whole range, and a resizable zoom-range window. The ZoomSlder cannot work as a standalone control and it acts as an enhancement for range-based controls like the igxDataChart. 

New Features

IgxBottomNav now supports an igx-tab declaration mode. Despite the fact that the primary usage of the component is to define panels with content, there may be cases in which you may need to define tab items only. You can use the new mode to apply directives on the tab item, e.g. to achieve routing navigation. You are also allowed to customize tab items with labels, icons, and even templates.

IgxTabs now supports an igx-tab-item declaration mode as well. When defining tab items you have the ability to apply directives on them. For example, you may use this functionality to achieve navigation between views using the Angular Router.

IgxGrid

Clipboard copy operations - This functionality provides a fast, easy and customizable way to copy Grid data into Excel or other external programs.

Group By behavioral change - paging now includes the group rows in the page size. When paging is applied the data is split based on flat records + group records view. If a group spans multiple pages, its group header is rendered only on the first one. Page count and page size include both item types. You may find more information about the change in the GroupBy Specification.

IgxGridFooter– Used to insert a custom footer in the grids.

IgxPaginator– Now can be used as a standalone component.

IgxColumnGroup - Re-templating the column group header is now possible using the headerTemplate @Input property or the igxHeader directive. Each column group can be templated separately. The column group expects ng-template tag decorated with the igxHeader directive. The ng-template is provided with the column group object as a context.

IgxCombo - Input [overlaySettings] allows an object of type OverlaySettings to be passed. These custom overlay settings control how the drop-down list displays.

IgxForOf now offers usage of local variables even, odd, first and last to help with the distinction of the currently iterated element.

IgxSlider has lot of visual enhancements and we’ve implemented adding of custom labels.

IgxSpreadsheet - with the new chart adapter added you can now display charts in your spreadsheet component.   

IgxMap - new Heat map imagery added to the map. You can now show heat-map imagery using the ShapeFileRecords that are generated by a ShapeDataSource by loading geo-spatial data and loading shape files to a tile series.

Enough with the new components/features. What about documentation and understanding how to use everything new? We strive to deliver simple and effortless experience, and we believe that begins with listening to our customers and providing a meaningful content. This is why this release the time spent on writing documentation is more than the actual feature development. Here is why:

Styling sections in topics– we thought about “how can we give visual guidance on what the styling looks like for a control or particular feature“ and “how can we get more code snippets and API docs references”. We aim to give a real way to know what styles are related to a feature and how to implement them.

WPF to Web guidance - This guide aims to help the Desktop developers to convert their skills into Web application skills. If you are a WPF developer, this guide will help you to learn Angular by comparing the differences and similarities between the two platforms. It covers topics like application structure, components, data binding and much more.

New igxTransaction topics We are already using igxTransaction in our grid components (see grid, tree grid and hierarchical editing batch editing topics). But if you want to understand how to use igxTransaction on your own, you can follow our guidance.

More topic for CLI- We have added some more guidance for ourIgnite UI CLI tool and especially how to generate our Ignite UI Angular components using it.

If I can summarize our strive for effortless experience I would quote WP Carey School of Business - “The best companies deliver straightforward, reliable experiences that meet real needs. People want to interact with companies where doing business is personalized, easy and hassle-free.”

Follow us on Medium and stay up to date with the latest Angular related perks that we work on, give us a star on GitHub and help us to continue improving our product by addressing any concerns, questions or feature requests in the issues section. We will give our best to constantly improve our product experience to suits all your needs and build apps with ease

Create Master-Detail app using Ignite UI for React components

$
0
0

Introduction

Have you ever wanted to create a master-detail application or learn how to visualize a large data source with subsets data items? If so, this blog post will show you how to create an application that will visualize the Global Sales Team in a list of people, locations of sales in for React IgrGeographicMap component, and sales details in React IgrLiveGrid component.

Note that the above animation does not represent actual app, where the map and grid components are updated very fast with new data for selected person in sales team.

Master-Detail view design is a great data visualization pattern for presenting large and complex data sets. As the name suggests, Master-Detail design consists of two views: master view and detail view. The master view is usually a selectable list of items such as customers, team members, products. The detail view displays data for the currently selected item in the master view.

Master-View

The master view is built using standard div, span, img, and label components.

However, first we need to generate data source for our application and create an array of items to display in the master view.

import DataUtil from"../data/DataUtil";

// declaring fields in a class:
public salesPeople: any[];
public salesData: any[];
public salesList: JSX.Element[] = [];

// generating data and items:
constructor(props: any) {
    super(props);
    this.salesPeople = DataUtil.getEmployees(100);
    this.salesList = [];
    for (let i = 0; i < this.salesPeople.length; i++) {
        const person = this.salesPeople[i];
        this.salesList.push(this.renderItem(person, i));
    }
}

Next, we can create the master view and render each item of sales list as it is demonstrated below.

<divclassName="masterView">
    <divclassName="masterHeader">
        <imgsrc={this.getHeaderIcon()}/>
        <label>World Sales Team</label>
    </div>
    <divclassName="masterList">
        <div>{this.salesList}</div>
    </div>
</div>

Detail-View

The detail view contains of a map and a grid components that are part of Ignite Ui for React and you can try them for free.

<divclassName="detailView">
    <divclassName="map"></div>
    <divclassName="grid"></div>
</div>

The IgrGeographicMap allows you to display data that contains geographic locations from your data on geographic imagery maps.

<divclassName="detailView">
    <divclassName="map">
        <IgrGeographicMap
            ref={this.onMapRef}
            width="100%"
            height="100%"
            zoomable="true">

            <IgrGeographicProportionalSymbolSeries
            name="sales"
            radiusScale={this.sizeScale}
            fillScale={this.fillScale}
            fillMemberPath="OrderValue"
            radiusMemberPath="OrderValue"
            latitudeMemberPath="Lat"
            longitudeMemberPath="Lon"
            markerOutline="rgba(0,0,0,0.2)"
            markerType="Circle"
            tooltipTemplate={this.onSeriesTooltipCreate} />

        </IgrGeographicMap>
    </div>
</div>

The IgrLiveGrid is a tabular React component that allows you to quickly bind and display your data with little coding or configuration. Features of the React data grid include filtering, sorting, templates, row selection, row grouping, row pinning and movable column.

<divclassName="detailView">
    <divclassName="grid">
        <IgrLiveGrid
            ref={this.onGridRef}
            height="100%"
            width="100%"
            rowHeight="35"
            headerHeight="35"
            autoGenerateColumns="false">

            <IgrTextColumnpropertyPath="ID"width="*>70"/>
            <IgrDateTimeColumnpropertyPath="OrderDate"
            headerText="Date"width="*>100"horizontalAlignment="right" />

            <IgrNumericColumnpropertyPath="OrderPrice"
            headerText="Price"width="*>90"positivePrefix="$"maxFractionDigits="0"/>

            <IgrNumericColumnpropertyPath="OrderCount"
            headerText="Orders"width="*>80"/>

            <IgrNumericColumnpropertyPath="OrderValue"
            headerText="Order Value"width="*>110"positivePrefix="$" />

            <IgrImageColumnpropertyPath="CountryFlag"
            headerText="Country"horizontalAlignment="center"width="90"/>

            <IgrTextColumnpropertyPath="City"width="*>150"/>
        </IgrLiveGrid>
    </div>
</div>

Binding Views

After creating all views, we can bind them by setting data source in a click event of the master list.

public salesData: any[];

constructor(props: any) {
    super(props);

    this.salesPeople = DataUtil.getEmployees(100);
    // defaulting to first person in the array of sales people
    this.salesData = this.salesPeople[0].Sales;
}

public onGridRef(grid: IgrLiveGrid) {
    this.grid = grid;
    this.grid.dataSource = this.salesData;
    this.grid.flush();
    this.grid.scrollToRowByIndex(0);
}

public onMapRef(map: IgrGeographicMap) {
    this.map = map;
    this.map.dataSource = this.salesData;
    this.map.zoomToGeographic({ left: -120, top: -30, width: 180, height: 90});
}

public onMasterItemClick(event: React.MouseEvent) {
    event.preventDefault();
    const newId = event.currentTarget.id;
    this.salesData = this.salesPeople[newId].Sales;

    this.map.dataSource = this.salesData;
    this.grid.dataSource = this.salesData;
    this.grid.flush();
    this.grid.scrollToRowByIndex(0);
}

Final Thoughts

The above code snippets show the most important elements of implementing a master-detail view in React application that visualizes locations of sales in React IgrGeographicMap component, and sales details in React IgrLiveGrid component.

You can download the full source code for this application from this GitHub repository. I hope you found this blog post interesting and got inspired to create your own master-detail application using the Ignite UI for React components.

Happy coding,

Martin

Infragistics Launches Reveal Embedded Analytics Platform

$
0
0
Add beautiful data visualizations to your app with the Reveal embedded business intelligence tool. (read more)

Ignite UI for Angular 8.2.0 Release

$
0
0

 Two months ago we’ve released our 8.1.0 version and now we are ready with the next one – 8.2.0. We are continuing the trend to introduce to you the coolest Angular components.This version includes new features as Grid Advanced Filtering, Enhanced Grid Selection, Multi-view Calendar and new Theme that mimics the Microsoft “fluent” design system.  

 We’ve been also working on the Ignite UI CLI documentation, there are a lot of new topics that will help you gain better understanding on how to easily scaffold Angular applications and use pre-configured templates that helps you get your next app off the ground in no time using our Ignite UI CLI. Check out this:

 Last but not least we have the handy new series "Editing entities without breaking the network tab" published by Alex on Medium.

What we have for this release: 

  • New theme Ignite UI for Angular - Now have a new theme that mimics Microsoft "Fluent" design system. Depending on your use case you can use one of the following mixins: igx-fluent-theme and igx-fluent-dark-theme.

  • igxDrag and igxDrop enhancements - Now it is possible to drag the base element igxDrag is instanced on by setting the new input ghost to false. Drag animation improvements. Drop strategies. Three new drop strategies have been provided - Append, Prepend and Insert. Also an input dropStrategy to the igxDrop which specify which strategy should be used when dropping an element inside the drop area. Custom one can be specified as well.  

  

  • Multi-view Calendar - by using the monthsViewNumber input you can now manage the displayed months in the calendar, it also supports all three types of selection, keyboard navigation and there is a way to hide the days which are not part of the month by using the hideOutsideDays input.

  • Enhanced Selection functionality of the Grids - Introduced new properties cellSelection and rowSelection which accept GridSelection mode enumeration. Grid selection mode could be none, single or multiple. Also hideRowSelectors property is added, which allows you to show and hide row selectors when row selection is enabled. 
  • Custom template for row selectors - Introduced functionality for templating row and header selectors 
  • IgxCombo - Combo selection is now consistent when valueKey is defined. When valueKey is specified, selection is based on the value keys of the items 
  • igxExcelStyleLoading - Directive is added, which can be used to provide a custom loading template for the Excel Style Filtering. If this property is not provided, a default loading template will be used instead. 
  • FilterStrategy - Input that allows you to override the default filtering strategy 
  • uniqueColumnValuesStrategy - Input is added. This property provides a callback for loading unique column values on demand. If this property is provided, the unique values it generates will be used by the Excel Style Filtering (instead of using the unique values from the data that is bound to the grid). 
  • IgxHierarchicalGrid Row Islands - now emit child grid events with an additional argument - owner, which holds reference to the related child grid component instance 
  • IgxCheckbox - introduced a new read only property that doesn't allow user interaction to change the state, but keeps the default active style. Intended for integration in complex controls that handle the interaction and control the checkbox instead through binding. 
  • IgxOverlay - introduced a new ContainerPositionStrategy. The new strategy positions the element inside the containing outlet based on the directions passed in trough PositionSettings. 

All other changes here.

 


Angular Connect London 2019

 The year so far is filled with opportunities and positive experiences, such as the Angular Connect conference that we attended. It was a great conference — it brought together a big group of software developers and industry leaders all sharing a common interest — the present state and the future of Angular web development. As a premium sponsor at the event, Infragistics had the opportunity to connect with not only the delegates of the event but with the wider Angular community. Also having one-on-one chats about what they are working on and how we at Infragistics can help them overcome complex problems with our Ignite UI for Angular product

More about the Angular Connect Conference you can find by reading our Medium post here.


Going Down The Road

One milestone is down and we are after the next one. We have decided to offer you a sneak peek on what is "cooking" in IgniteUI for Angular Sprints through the GitHub Projects. Now you can follow the progress of your issues and be part of the process as you comment, report or request features on GitHub. Do not miss the opportunity to strike while the iron is hot!


Follow us on Medium and stay up to date with the latest Angular related perks that we work on, give us a star on GitHub and help us to continue improving our product by addressing any concerns, questions or feature requests in the issues section. We will give our best to constantly improve our product experience to suits all your needs and build apps with ease

 

Host Sketch Prototypes on Private Server with Usability Testing

$
0
0
Indigo.Design lets you sync Sketch prototypes and run unmoderated usability testing securely on your own private server.(read more)

Ignite UI for Angular 7.3.0 Release

$
0
0

With the 7.3.0 we release we are introducing some new and interesting features that will allow our user to expand the usability of the igxGrid. The two major things we are introducing are the Multi Row Layout and the Row Dragging feature.

Multi Row Layout

Multi-row layouts allow developers to create intricate cell arrangements within the same row by defining a template layout that is applied to header and body cells. This provides flexibility of the arrangement and makes it possible to create responsive web apps where grids would adapt and avoid horizontalcoo scrolling when the available space becomes too narrow

The igxGridComponent now supports Multi Row Layout It which can be configured with the newly added IgxColumnLayoutComponent and the columns in it. IgxColumnComponent now expose four new fields to determine the size and the location of the field into the layout:

  • rowStart
  • colStart
  • rowEnd
  • colEnd
 
 
Row Dragging 

The Drag and Drop allows users to Row drag and pass the data of a grid record on to another surface, which has been configured to process/render this data in a particular way. This is a very useful feature in cases when we have two or more Grids and we won’t to move the row date from one grid to the other. For more details on the feature visit the WIKI pages n Github or the samples on the website (Link)

Additional Enhancements 

There are also a couple of new enhancements to our already released features like igxTreeGird now support load children on demand  and haschildrenkeys input properties.

The IgxListComponent now provides the ability to choose a display density from a predefined set of options: compact, cosy and comfortable (default one). It can be set by using the displayDensity input of the list.

The igxButton now provides the ability to choose a display density from a predefined set of options: compact, cosy and comfortable (default one). It can be set by using the displayDensity input of the button directive.

The Excel Style Filter dialog and its sub-dialogs now have a display density based on the displayDensityinput of their respective grid; the igxDropDown now supports virtualized items. 

Check out our RoadMap and give a star to our Github repo to stay tuned.

 

Infragistics Team visits South Korea again this year!

$
0
0

I am excited to announce the Infragistics Developer Day in South Korea this year again!

Jason Beres, Sr. VP of Developer Tools, Ken Azuma, Managing Director for APAC, and Satoru Yamaguchi, Senior Solution Consultant will be visiting Seoul, and they are going to host workshops for WPF, ASP.NET MVC & JavaScript controls.

Event Overview:

Host

Infragistics, Inc. / BluePort

Date

Three seminars:
- June 26th, 2019 09:00 am to 12:00 pm
- June 26th, 2019 02:00 pm to 05:00 pm
- June 27th, 2019 09:00 am to 12:00 pm

Location

BluePort seminar room

http://www.blueport.co.kr

12F, 5, Seocho-daero 78-gil, Seocho-gu, Seoul, Republic of Korea

Capacity

Morning Session (8:30 am to 12:00 pm) - 30 people

Afternoon Session (1:30 pm to 5:00 pm) - 30 pooeple

Admission Fee

Free

Contact: BluePort (02-567-8920 / sales@blueport.co.kr)

* We provide English to Korean translation.

You can find a detailed schedule and agenda here (Korean).

Registration:

Please pick one of them or sign up for each if you're attending multiple workshops. 

June 26, 2019 - Morning Session - WPF

June 26, 2019 - Afternoon Session - ASP.NET MVC + JavaScript

June 27, 2019 - Morning Session - WPF

We are looking forward to seeing you all in Korea!

Related: Infragistics Developer Day 2018 Recap

Add a range selector calendar in Angular: a step by step guide

$
0
0

In the first week of May, I attended ngConf 2019 and I had the wonderful opportunity to talk to many Angular developers about Ignite UI and Angular in general.

Developers were very impressed by Ignite UI for Angular, which includes an Angular Material-based library consisting of more than 80 components, directives, and services to help you build Angular enterprise applications faster. You can learn more here

One question I was asked frequently:  How to select a date range in a Calendar. In this blog post, I’ll show you how to do that.  You need to use Ignite UI for Angular igx-calendar component  to add a calendar in the application. The igx-calendar component comes in three selection modes

  1. Single
  2. Multi
  3. Range

I’ll use a step-by-step approach to show you how to use igx-calendar in an Angular application.

Step 1:  Add Ignite UI for Angular in Angular Project

There are three ways to add an Ignite UI  to an Angular project:

  1. If starting a new project, use the Ignite UI CLI to scaffold the project. You can use command line options to add the igx-calendar, including dependency installation.
  2. In an existing project, you can use the Ignite UI for Angular Toolbox Extension to add an igx-calendar in the project. Learn how in this blog post.
  3. You can use npm to install Ignite UI for Angular dependencies in your project. You can learn that in details here :  Step-by-Step with Images to Add Ignite UI for Angular in an Existing Angular Project

Step 2:   Add required modules for igx-calendar

To work with igx-calendar, you need to add IgxCalendarModule and BrowserAnimtaionModule.  We will display messages in the igx-dialog, so for that purpose we have also added IgxDialogModule

 Modules can be added as shown in the code listing below:

import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { IgxCalendarModule, IgxDialogModule } from 'igniteui-angular';
import { AppComponent } from './app.component';
 
@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        IgxCalendarModule,
        IgxDialogModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }

 

I have added dependencies in the AppModule, however you can add in it any other features.

Step 3:   Use igx-calendar

You can simply use igxCalendar in the component template as shown in the listing below:

<igx-calendar selection="range" (onSelection)="verifyRange($event)">  </igx-calendar >

There are three selection modes available for the calendar. They are as follows:

  1. Single
  2. Multi
  3. Range

By default, the selection is set to single. To work with date range selection, we have set selection property to range.  When the user selects date onSelection, an event will be fired.  In the event handler, you can work with the selected date range, verifying the range, among other options.

Let us also add igx-dialog component to display messages.

<igx-calendar #calendar selection="range" (onSelection)="verifyRange($event)">   </igx-calendar>   <igx-dialog #alert title="Notification" message="You have selected date" leftButtonLabel="OK"               (onLeftButtonSelect)="alert.close()">   </igx-dialog>

 Note that I have added temp ref variables to both components such that we can read them in the component class.

Step 4:   Reading calendar in component class

Like any other element or component of a template, you can read igx-calendar using ViewChild decorator.

Simplifying ViewChild and ContentChild in Angular

 Start with importing IgxCalendarComponent   and IgxDialogComponent,

import { IgxCalendarComponent, IgxDialogComponent } from 'igniteui-angular';

 Create properties decorated with @ViewChild reading the temp variable name as shown below: 

@ViewChild('calendar') public calendar: IgxCalendarComponent;
@ViewChild('alert') public dialog: IgxDialogComponent;

Now you can read all properties and events of IgxCalendarComponent and IgxDialogComponent in appropriate life cycle of component class such as ngAfterViewInit

 

Step 5:   Handle date selection event

You can handle a date selection event as shown in the next listing :

verifyRange(dates: Date[]) {
 
    if (dates.length > 5) {
        this.calendar.selectDate(dates[0]);
        this.dialog.message = this.calendar.value[0];
        this.dialog.message = 'select at max 5 dates';
        this.dialog.open();
    } else {
        this.dialog.message = 'You have seleceted start date :' + dates[0] + ' end date :' + dates[dates.length - 1];
        this.dialog.open();
    }
 
}

IgxCalendarComponent returns single date object for default value and for range selection it returns date type object array. You can work with returned array like pure JavaScript date object array as per your need.  I am reading the length of the array and, if it is more than 5, I am passing different messages in igx-dialog. If it’s less than 5, I’m passing start and end date.

That’s it. As you can see, it’s quite simple to work with date range selections in Angular applications using igx-calendar component.  You may also want to explore other components in the Ignite UI library  to build an enterprise Angular application faster.

Formatting Data using Pipes in the Ignite UI for Angular Grid

$
0
0

How you present data to the user is essential. Often you cannot present data as it is from the data source to the viewer. Users need a more immersive presentation of the data. Let us consider a data source as listed below:

this.products = [
    { Id: '1', Title: 'Book', ExpiryDate: new Date(), Price: 35, Rating: 3.5 },
    { Id: '2', Title: 'Pen', ExpiryDate: new Date(), Price: 25, Rating: 4.0 },
    { Id: '3', Title: 'Pencil', ExpiryDate: new Date(), Price: 20, Rating: 3.2 },
    { Id: '4', Title: 'Bat', ExpiryDate: new Date(), Price: 135, Rating: 4.0 },
    { Id: '5', Title: 'Ball', ExpiryDate: new Date(), Price: 65, Rating: 3.8 },
];

Let’s begin by defining an instance of the igxGrid in the template and data bind the data property to the product array. It is straightforward to add Ignite UI for Angular Grid as shown in the below code listing:

<igx-grid [data]="products"          [autoGenerate]="true"          width="960px"></igx-grid>

We are setting the autoGenerate property to true; do to this, Ignite UI will auto-generate all the columns by reading from the data source.  The grid will be created as shown in the below image:

As you can see,  data is displayed in a much more immersive way. Also, you may notice that Ignite UI by default has applied date pipes to the ExpiryDate column. If you are new to pipes, Angular pipes take data as input and transforms it into your desired output. The angular library provides many built-in pipes:

  • UpperCasePipe
  • LowerCasePipe
  • CurrencyPipe
  • PercentPipe
  • DatePipe etc.

When you use auto generate true, Ignite UI applies DatePipe on the date object column, without it ExpiryDate will be rendered as shown in below image:

 So, in autogenerate true, Ignite UI applies required pipes on the data, but still, there is some limitation of it. For example, you cannot use custom pipes or manually choose which pipe to be applied.

For better control of columns, you should configure them manually in IgxGrid.  If you want to format the style or data of a particular column, for example, you have to manually configure columns in igxGrid as shown in the code listing below and then use column template.

<igx-grid [data]="products" [autoGenerate]="false" width="960px">        <igx-column field="Id" header="Id"></igx-column>        <igx-column field="Title" header="Title"></igx-column>        <igx-column field="ExpiryDate" header="Expiry Date"></igx-column>        <igx-column field="Price" header="Price"></igx-column>        <igx-column field="Rating" header="Rating"></igx-column> </igx-grid>

For a particular column, now you can configure header, column properties, and data format. Say you want to apply currency pipe to Price column, you can do that as shown in the code listing below:

The ng-template is like an HTML template and reusable, and it replaces the content when rendered. You can use ng-template to provide

  1. Column template
  2. Header template
  3. Pagination template etc.

We are passing two parameters to ng-template

  1. ixgCell : determines that this template will be applied to a particular grid cell
  2. let-value : contains data value passed in the cell

Other possible input parameters for ng-template are

  1. igxHeader : to apply template to column header
  2. let-column : contains column as input data

We will talk about these in detail in another post focused on custom header template.

Now, let us modify Price and ExpiryDate columns with currency and date pipes.

<igx-grid [data]="products" [autoGenerate]="false" width="960px">    <igx-column field="Id" header="Id"></igx-column>    <igx-column field="Title" header="Title"></igx-column>    <igx-column field="ExpiryDate" header="Expiry Date">        <ng-template igxCell let-value>            {{ value | date }}        </ng-template>    </igx-column>    <igx-column field="Price" header="Price">        <ng-template igxCell let-value>            {{ value | currency }}        </ng-template>    </igx-column>    <igx-column field="Rating" header="Rating"></igx-column></igx-grid>

You will get the grid rendered, as shown in the image below:

You can also pass parameters to pipes while using that in IgxGrid.

You can pass any number of parameters to pipes as supported by them, for example, additional parameters can be passed to currency pipe as shown below:

If you are working with date pipe, you can pass parameters as shown below:

If you have created custom pipes, you can also use that, as shown below:

Here firstcharacteruppercase is a custom pipe. If you are not sure how to create it, learn more about it here.

Not only simple pipes, you can also use other Ignite UI for Angular components when formatting column data for better visualization.  I will cover that in separate blog post. Let us put everything together to use data on  igxGrid as shown below:

<igx-grid [data]="products" [autoGenerate]="false" width="960px">    <igx-column field="Id" header="Id"></igx-column>    <igx-column field="Title" header="Title">        <ng-template igxCell let-value>            {{ value | firstcharacteruppercase }}        </ng-template>    </igx-column>    <igx-column field="ExpiryDate" header="Expiry Date">        <ng-template igxCell let-value>            {{ value | date :'fullDate'}}        </ng-template>    </igx-column>    <igx-column [sortable]='true' field="Price" header="Price">        <ng-template igxCell let-value>            {{ value | currency:'CAD':'symbol':'4.2-2'}}        </ng-template>    </igx-column>    <igx-column field="Rating" header="Rating">    </igx-column></igx-grid>

Now you can see the grid is rendered as shown in the image below:

Now you may have a question that what if you are using auto-generated columns, then how you will format data in the desired way. How can you set other properties of the column such as width, sorting, paging, data format, header style, pinning, etc.?  I will cover this in another blog post. As of now, I hope you find this post useful and now know how easy it is to format data using templates in Ignite UI for Angular Grid. You can learn more about Ignite UI for Angular Grid here.  To learn more about pipes, watch the  Desktop to Web: Transforming Data with Angular Pipes video 

9 Ways to Improve Your Data Visualizations with Reveal

$
0
0
Create exciting visualizations of your data with easy-to-use, drag-and-drop Reveal business intelligence software.(read more)

15 WPF Performance Tips for 2019

$
0
0

Are you a WPF developer? Do your WPF apps have areas of poor performance or don’t run as quickly as you would like?  If so, I have 15 tips to help you identify and improve the performance of your WPF applications. 

While WPF is over a decade old and has been improved greatly over the years, there are still several areas that can suffer from poor performance.  The reasons for this poor performance include things such as bad coding practices, broken bindings, complex layouts, the lack of UI virtualization, and much more. Luckily, with a little planning and a solid understanding of the WPF platform, you can have your WPF apps jumping into warp speed and leaping across the universe in milliseconds. 

I have put together these 15 tips to help you improve the performance of your WPF apps.

1. Simplify your Visual Tree

A common source of performance issues is a deep and complex layout. Keep your XAML markup as simple and shallow as possible. When UI elements are drawn onscreen, a “layout pass” is called twice for each element (a measure pass and an arrange pass). The layout pass is a mathematically-intensive process—the larger the number of children in the element, the greater the number of calculations required.  

2. Virtualize your ItemsControls

As mentioned earlier, a complex and deep visual tree results in a larger memory footprint and slower performance. ItemsControls usually increase performance problems with deep visual trees because they are not virtualized. This means they are constantly being created and destroyed for each item in the control. Instead, use the VirtualizingStackPanel as the items host and make use of the VirtualizingStackPanel.IsVirtualizing and set the VirtualizationMode to Recycling in order to reuse item containers instead of creating new ones each time. 

3. Favor StaticResources over DynamicResources

StaticResources provide values for any XAML property attribute by looking up a reference to an already defined resource. Lookup behavior for that resource is the same as a compile-time lookup. DynamicResources will create a temporary expression and defer lookup for resources until the requested resource value is required. Lookup behavior for that resource is the same as a run-time lookup, which imposes a performance impact. Always use a StaticResource whenever possible. 

4. Opacity on Brushes Instead of Elements

If you use a Brush to set the Fill or Stroke of an element, it is better to set the Opacity on the Brush rather than setting the element’s Opacity property. When you modify an element’s Opacity property, it can cause WPF to create temporary surfaces which results in a performance hit. 

5. Avoid Using Run to Set Text Properties

Avoid using Runs within a TextBlock as this results in a much higher performance intensive operation. If you are using a Run to set text properties, set those directly on the TextBlock instead. 

6. Favor StreamGeometries over PathGeometries

The StreamGeometry object is a very light-weight alternative to a PathGeometry. StreamGeometry is optimized for handling many PathGeometry objects. It consumes less memory and performs much better when compared to using many PathGeometry objects. 

7. Use Reduced Image Sizes

If your app requires the display of smaller thumbnails, consider creating reduced-sized versions of your images. By default, WPF will load and decode your image to its full size. This can be the source of many performance problems if you are loading full images and scaling them down to thumbnail sizes in controls such as an ItemsControl. If possible, combine all images into a single image, such as a film strip composed of multiple images. 

8. Lower the BitMapScalingMode

By default, WPF uses a high-quality image re-sampling algorithm that can sometimes consume system resources which results in frame rate degradation and causes animations to stutter. Instead, set the BitMapScalingMode to LowQuality to switch from a “quality-optimized” algorithm to a “speed-optimized” algorithm. 

9. Use and Freeze Freezables

A Freezable is a special type of object that has two states: unfrozen and frozen. When you freeze an object such as a Brush or Geometry, it can no longer be modified. Freezing objects whenever possible improves the performance of your application and reduces its memory consumption. 

10. Fix your Binding Errors

Binding errors are the most common type of performance problem in WPF apps. Every time a binding error occurs, your app takes a perf hit and as it tries to resolve the binding and writes the error out to the trace log. As you can imagine, the more binding errors you have the bigger the performance hit your app will take. Take the time to find and fix all your binding errors. Using a RelativeSource binding in DataTemplates is a major culprit in binding error as the binding is usually not resolved properly until the DataTempate has completed its initialization. Avoid using RelativeSource.FindAncestor at all costs. Instead, define an attached property and use property inheritance to push values down the visual tree instead of looking up the visual tree. 

11. Avoid Databinding to the Label.Content Property

If you are using a Label to data bind to a String property, this will result in poor performance. This is because each time the String source is updated, the old string object is discarded, and a new String is created. If the Content of the Label is simple text, replace it with a TextBlock and bind to the Text property instead. 

12. Bind ItemsControls to IList instead of IEnumerable

When data binding an ItemsControl to an IEnumerable, WPF will create a wrapper of type IList<T> which negatively impacts performance with the creation of a second object. Instead, bind the ItemsControl directly to an IList to avoid the overhead of the wrapper object. 

13. Use the NeutralResourcesLanguage Attribute

Use the NeutralResourcesLanguageAttribute to tell the ResourceManager what the neutral culture is and avoid unsuccessful satellite assembly lookups. 

14. Load Data on Separate Threads

A very common source of performance problems, UI freezes, and apps that stop responding is how you load your data. Make sure you are asynchronously loading your data on a separate thread as to not overload the UI thread. Loading data on the UI thread will result in very poor performance and an overall bad end-user experience. Multi-threading should be something every WPF developer is using in their applications. 

15. Beware of Memory Leaks

Memory leaks are the number one cause of performance problems in most WPF applications.  They are easy to have but can be difficult to find.  For example, using the DependencyPropertyDescriptor.AddValueChanged can cause the WPF framework to take a strong reference to the source of the event that isn’t removed until you manually call DependencyPropertyDescriptor.RemoveValueChanged. If your views or behaviors rely on events being raised from an object or ViewModel (such as INotifyPropertyChanged), subscribe to them weakly or make sure you are manually unsubscribing. Also, if you are binding to properties in a ViewModel which does not implement INotifyPropertyChanged, chances are you have a memory leak. 

Finally, a bonus tip. Sometimes when you have a performance problem it can be very difficult to identify what exactly is causing the issue. I suggest using an application performance profiler to help identify where these performance bottle necks are occurring in your code base. There are a lot of profiler options available to you. Some are paid, and some are free. The one I personally use the most is the Diagnosis Tools built directly into Visual Studio 2019.

Be sure to engage with me on Twitter, subscribe to my YouTube channel to be notified of new video content, and follow me on Twitch to watch me stream live.

Viewing all 2398 articles
Browse latest View live