Importing and exporting task data from GanttChartDataGrid as (Excel-supported) tab delimited text files

Fotografie de freestocks.org pe Pexels.com

GanttChartDataGrid component from DlhSoft Gantt Chart Light Library allows developers to set up and display an interactive Gantt chart in their WPF app. But how can they allow end users to export and import task items to and from Excel, one might ask?

Let’s observe first that to copy data from the Gantt chart’s data grid the end user can directly use the Copy command (if exposed by the developer) to save the contents to the clipboard in that specific format. So they can easily paste values directly into an Excel file. (And back, with Paste command of GanttChartDataGrid as well.)

GanttChartDataGrid.SelectAll();
GanttChartDataGrid.Copy();
...
GanttChartDataGrid.Paste();

But Excel also supports tab-delimited text files as input (and output) for single sheet documents. Developers have therefore an alternative through that path, too: they can allow end users to select the tasks that they want to export (or select all tasks, if needed, instead) and get the tab-delimited string output placed into a text file of user’s choice. The latter can then load it in Excel with ease:

using (Stream stream = saveFileDialog.OpenFile())
{
    using (StreamWriter writer = new StreamWriter(stream))
    {
        var data = GanttChartDataGrid.GetCopy(); // tab delimited text formatted
        writer.Write(data);
    }
}

To import data back from tab delimited text files saved from Excel into GanttChartDataGrid, however, things are a bit more tricky:

You’ll need to parse the text file in code and create GanttChartItem objects on the run. Collect the basic data fields (content, start, finish, assignments, etc.) first, load items into the component, and compute completion and set up dependencies (predecessors strings values) only when everything else is ready; that is, if you’d like to make use of the helper members of the item instances and of the component as well. (And it’s important that you keep the asynchronous presentation off if you want to do that, too.)

string[] data;
using (Stream stream = openFileDialog.OpenFile())
{
    using (StreamReader reader = new StreamReader(stream))
    {
        data = reader.ReadToEnd().Split(new[] { '\n', '\r' },
                                        StringSplitOptions.RemoveEmptyEntries);
    }
}
string[] columns = data.First().Split('\t');
string[][] rows = data.Skip(1).Select(row => row.Split('\t')).ToArray();

// Prepare the task data collection.
ObservableCollection items = new ObservableCollection();
foreach (var row in rows)
{
    var item = new GanttChartItem();
    // Load basic values first.
    var cell = 0;
    foreach (var value in row) 
    {
        var column = cell < columns.Length ? columns[cell++] : null;
        if (string.IsNullOrEmpty(value))
            continue;

        switch (column)
        {
            case "Item":
                item.Content = value;
                break;
            case "Indentation":
                item.Indentation = Convert.ToInt32(value);
                break;
            case "Start":
                item.Start = Convert.ToDateTime(value);
                break;
            case "Finish":
                item.Finish = Convert.ToDateTime(value);
                break;
            case "Milestone":
                item.IsMilestone = Convert.ToBoolean(value);
                break;
            case "Assignments":
                item.AssignmentsContent = value;
                break;
            default: break;
        }
    }
    items.Add(item);
}

GanttChartDataGrid.Items = items;

// Load completion values and dependencies after all items have been loaded to be able to use Completion and PredecessorsString helper setters.
// To ensure all items are available set GanttChartDataGrid.IsAsyncPresentationEnabled to false (see XAML).
for (var i = 0; i < items.Count; i++)
{
    var item = items[i];
    var row = rows[i];
    var cell = 0;
    foreach (var value in row)
    {
        var column = cell < columns.Length ? columns[cell++] : null;
        if (string.IsNullOrEmpty(value))
            continue;

        switch (column)
        {
            case "Completion percent":
                item.Completion = Convert.ToDouble(value) / 100;
                break;
            case "Predecessors":
                item.PredecessorsString = value;
                break;
            default: break;
        }
    }
}

The full sample app with source code is available here. Check MainWindow.xaml.cs inside, and here you go: your users will be able to import/export task items with a lot more ease!

Posted in Miscellaneous | Tagged , , , , , | Leave a comment

ASP .NET Core demos for Gantt Chart Web Library (MVC)

Gantt Chart Web Library was a classic .NET Framework package (WebForms first, then MVC as well) until .NET Core 2.1 became available. Since then, however, we’ve also created .NET Core extensions that leverage the same underlying JavaScript components as the original views used (available, by the way. as standalone browser widgets with Gantt Chart Hyper Library, too).

But until today we haven’t had a showcase app to show all main features that the .NET Core components would be able to offer. You had to check out our classic ASP .NET WebForms demos first and convert and adapt their source there to .NET Core and MVC patterns, yourself.

You’ve asked us to create a “Main features”-like sample app showing how developers can allow end users to add and remove tasks, increase and decrease indentation, set up colors, highlight critical path, auto-schedule and level resources for tasks presented in a Gantt Chart view, or even show other views using the same project data (Schedule Chart, Load Chart, PERT Chart and Network Diagram) – so here we go:

We’ve just published this new live .NET Core 3.1 demo with full reference source code on GitHub for you to check out and enjoy! (More samples should come later, too.)

Posted in Development Components | Tagged , , , | Leave a comment

Aligning expander buttons for Gantt chart items when using recent versions of Bootstrap and DlhSoft Gantt Chart Hyper/Web Library

We’ve just noticed that recent versions of Bootstrap inject the following CSS to Web applications (at least under ASP .NET Core MVC projects created from Visual Studio):

svg {
  vertical-align: middle;
}

This may lead to our component showing the expander triangle buttons for Gantt chart items improperly aligned vertically: they are shown centered on the baseline of the text, rather than above it.

To fix the issue, you would simply need to reset the vertical-align setting from your CSS:

svg {
  vertical-align: initial;
}

We’ll also try to address this internally (so you won’t need to do anything afterwards) with a future product update, but until then please use the workaround above.

Posted in Development Components | Tagged , , , , | Leave a comment

Initializing JavaScript GanttChartView component items with start and effort (rather than finish)

If you have tried GanttChartView from Gantt Chart Hyper Library you have probably seen that our component requires initializing items using start and finish date values. (This is in attempt to ensure things are as optimized as possible by default, avoding computations whenever not needed.)

However, if your data source doesn’t store the finish dates at all (so you don’t have such input values), but just items’ start and effort instead, you can still use our component! You need to compute the required finish values at initialization time, yourself. But don’t worry, we’ve still got your back: we offer a “static” getFinish function that may help you with this, too.

Because it is a more “internal” function, though, it does have some important requirements itself: you need to prepare its settings argument in a specific way, with workingWeekStart and -Finish, and visibleDayStart and -Finish fields (note that the Gantt Chart component would generally support different working and visible week intervals, but not day intervals, thus the field name difference), plus an optional specialNonworkingDays array with dates set up as UTC input, with 00:00 time values; you can use getInputDate/getOutputDate functions to convert the dates as needed, and this is true for start and finish arguments, as well:

var GanttChartView = DlhSoft.Controls.GanttChartView;
var specialSettings = {
  workingWeekStart: 1, // Monday
  workingWeekFinish: 5, // Friday
  visibleDayStart: 8 * 60 * 60 * 1000, // 8 AM
  visibleDayFinish: 16 * 60 * 60 * 1000, // 4 PM
  specialNonworkingDays: [
    GanttChartView.getInputDate(new Date(2020, 4-1, 28))] // April 28 is a day off
};
// Known start and effort:
var start = GanttChartView.getInputDate(new Date(2020, 4-1, 27, 8, 0, 0)); // Starting on April 27
var effort = 2.75 * 8 * 60 * 60 * 1000;  // Duration: 2.75 working days
// Compute finish:
var finish = GanttChartView.getOutputDate(
  GanttChartView.getFinish(start, effort, specialSettings));
// Use finish (e.g. initializing item based on start and finish):
alert(finish); // April 30, 14:00 (not April 29, since 28 was a day off!)
Posted in Development Components | Tagged , , , , , , | Leave a comment

Auto-save upon client side changes with GanttChartView for ASP .NET WebForms

If you are (still) using our ASP .NET WebForms-based Gantt Chart components and you need automatic postbacks to the server whenever the end users perform changes on the client side, e.g. to save them to a central database, don’t worry, you’re NOT out of luck: a Save button (triggering “manual” postbacks) isn’t mandatory, although in our opinion the latter would still be the preferred solution from an experience point of view: it would allow people decide when and whether the changes should be actually submitted, and the user interface wouldn’t be refreshed until that time, either.

However, to simply submit the ASP .NET form to the server whenever item changes occur, you can use a snipper like the one presented below. Trying to partially mitigate the downsides described above, we set up some auto-increasing delay for an end user to be able to complete multiple updates before triggering the auto-save postback (to minimize workload, traffic, and à la WebForms interface refreshes too):

// Assumes GanttChartView is declared within a form with id='form1' and runat='server'.
GanttChartView.ItemPropertyChangeHandlerClientCode = @"
  if (isDirect && isFinal)
    var form = document.getElementById('form1');
    if (form.postbackTimeout)
      clearTimeout(form.postbackTimeout);
    form.postbackTimeout = setTimeout(function() { 
      form.submit();
      delete form.postbackTimeout;
    }, 5000); // auto-increasing 5 seconds delay
}";

Enjoy!

Posted in Development Components | Tagged , , , , | Leave a comment

Formatting dates on custom date columns with Gantt Chart Hyper Library

If you try to combine our Custom columns sample app for Gantt Chart Hyper Library – specifically, the baseline start and finish columns –  with Custom date formatters (or you simply want to define custom date-time fields on your items and then display and allow editing their value using specifically added columns), you might find out that the dates are not formatted as you would expect (as the main start and finish dates are.)

To resolve this issue you can use a workaround, though. You need to define a custom date input template that does format the value using settings.dateTimeFormatter (and reads values from the associated input element using dateTimeParser too), and then map it to baselineStart and baselineFinish (or any other custom date-time) fields as follows:

function formattedDateTimeInputColumnTemplateBase(document, width, valueGetter, valueSetter, isEnabledGetter, isVisibleGetter, isBoldGetter) {
    return DlhSoft.Controls.GanttChartView.textInputColumnTemplateBase(document, width,
        function () {
            var value = valueGetter();
            if (value != null)
                return settings.dateTimeFormatter(value);
            return "";
        },
        function (value) {
            if (value != "")
                value = DlhSoft.Controls.GanttChartView.dateTimeParser(value);
            else
                value = null;
            valueSetter(value);
        },
        isEnabledGetter, isVisibleGetter, isBoldGetter
    );
};
function formattedBaselineStartColumnTemplate(inputWidth) {
    return function (item) {
        var ganttChartView = item.ganttChartView, document = ganttChartView.ownerDocument;
        return formattedDateTimeInputColumnTemplateBase(document, inputWidth,
            function () {
                return item.baselineStart;
            },
            function (value) {
                if (value != null)
                    item.baselineStart = value;
                else
                    delete item.baselineStart;
                ganttChartView.onItemPropertyChanged(item, "baselineStart", true, true);
                ganttChartView.refreshItem(item);
            },
            function () { return !(item.isReadOnly || (typeof item.ganttChartView !== "undefined" && typeof item.ganttChartView.settings !== "undefined" && (item.ganttChartView.settings.isReadOnly || item.ganttChartView.settings.isGridReadOnly))); },
            function () { return !(typeof item.isBarVisible !== "undefined" && !item.isBarVisible); },
            function () { return (item.hasChildren && (typeof item.isSummaryEnabled === "undefined" || item.isSummaryEnabled)); }
        );
    }
};
function formattedBaselineFinishColumnTemplate(inputWidth) {
    ...
};
// cellTemplate fields use the functions declared above:
columns.push({ header: 'Plan Start', width: 140, cellTemplate: formattedBaselineStartColumnTemplate(124) });
columns.push({ header: 'Plan End', width: 140, cellTemplate: formattedBaselineFinishColumnTemplate(124) });

We hope it helps. Enjoy!

Posted in Development Components | Tagged , , , , , , | Leave a comment

JavaScript-based Gantt charts: one core fits any backend/frontend combination

Screen Shot 2020-01-15 at 10.44.58

Our browser-supported Gantt charts are here since a long time ago (actually, since 2012!) And as they have been written using pure JavaScript (having TypeScript definitions added later, though), they could be integrated into virtually any type of app that supported HTML5 output, during all this time.

Indeed, we have added AngularJS 1.3 extensions for them ourselves (again, years ago), and later – when Microsoft introduced WinRT 8 apps (later UWP) with support for JavaScript, besides .NET and C++ – we’ve created a separate library targeting that on top of our Web components too.

Of course, as with most JavaScript components, you could also integrate them with a backend server. We’ve done it in a native fashion for ASP .NET WebForms (again as a separate product that actually enclosed it), and also added extensions for MVC and .NET Core 2.1 later. But one can use the core library with data received from a REST API (such as an ASP .NET WebApi-based solution with SQL Server data store) without the need of anything else.

Screen Shot 2020-01-15 at 11.36.03.png

But we didn’t stop here. We’ve made sample apps showing how one can use the client side component when injected from PHP, and recently also Node.js and Python.

And on client side, you can see them bound in all three recently rising frameworks: Angular 8, React, and Vue. And of course, developers may write similar extensions themselves to integrate the components anywhere else, too.

(Some time ago we’ve also added themes – including dark mode – for our HTML5 components, to provide developers with fast styling support. But everything is optional and fully configurable, as you can see in the live demos from our Web site – sample apps with downloadable source code. With or without integrating them to other frameworks.)

So… one core product truly fits them all here! And while generally such an approach could be seen as dangerous, we think that we are safe while we stay within the HTML5 ecosystem. However, make sure you analyze everything well. For example, we don’t recommend you to use JavaScript for mobile development, or at least not if you want to build professional apps; UX dictates other rules there, possibly applying to desktop apps too, up to an extent. For macOS/iOS & Windows charting we do offer better alternatives!

Posted in Development Components | Tagged , , , , , , , | Leave a comment

Auto-scheduling with ScheduleChartView (JavaScript)

With GanttChartView and JavaScript (one item being displayed per row) it’s easy to setup predecessor links between tasks – displaying them as dependency arrows – and then you can simply turn on auto-scheduling (enable dependency constraints) to ensure items are rescheduled accordingly and interactively.

But can you do the same with a ScheduleChartView instance, using the same JavaScript package, DlhSoft Gantt Chart Hyper Library? You asked, we answer:

Of course! Dependency arrows won’t be displayed, but predecessors links will surely be respected. Try it now:

// Get scheduleChartView element reference, define scheduleChartItems tree, and control settings.
var scheduleChartView = …, …;
// Add predecessors from/to correct Gantt Chart items:
scheduleChartItems[1].ganttChartItems[2].predecessors = [
  { item: scheduleChartItems[0].ganttChartItems[0] }];
// Enable auto-scheduling:
settings.areTaskDependencyConstraintsEnabled = true;
settings.areTaskDependencyConstraintsEnabledWhileDragging = true; // optional (test performance!)
// Initialize control:
DlhSoft.Controls.ScheduleChartView.initialize(scheduleChartView, scheduleChartItems, settings);

 

Posted in Development Components | Tagged , , , , , | Leave a comment

Will you port your desktop apps to .NET Core?

keyboard green

Fotografie de Max DeRoin pe Pexels.com

Indeed, with the recent release of .NET Core 3.1 Microsoft offers long time support for WPF “Core”, and we all should consider moving away from the classic .NET Framework 4+ already, as the next major platform iteration (.NET 5) will be entirely Core-based.

If you use DlhSoft’s WPF components from Gantt Chart Light Library and/or Hierarchical Data Light Library, you are completely covered: we’ve ported these packages to .NET Core 3.1 already, so you can grab and try the updates today.

Moreover, we’ve recently updated Project Management Framework to be .NET Standard 2.0 compatible, supporting .NET Core 2.0+ as well. (And upon request we will try to port any older .NET libraries that we offer – for both WPF and Windows Forms – too.)

The only caveats that come with porting your app to .NET Core (in relation to using our libraries) are that you will need to use NuGet package manager – the Core components are not available through a direct download (contact us if you are unable to use NuGet, though, and together we’ll find a solution) – and that for licensing the components you’ll need to call the static SetLicense method directly in your initialization code, i.e. use our alternative licensing method, as the original .lic file-based one isn’t supported anymore, but these are (arguably) both better solutions anyway.

Posted in Development Components | Tagged , , , , | Leave a comment

Ganttis 2.0

Hey there, we have news! We’ve just released a major update for our macOS and iOS Gantt chart components – Ganttis 2.0.

Ganttis demo screenshot

We’ve added a new macOS component that integrates an interactive Gantt chart diagram with a classic Cocoa OutlineView into a very easy to use OutlineGanttChart class.

A lot of other improvements and smaller additions are also included, both for macOS and iOS development.

And it’s the first time for us to release an XCFramework – the new way that Apple recently envisioned for distributing multi-target binaries – finally a package that… well, just works.

Posted in Development Components | Tagged , , , , , | Leave a comment