using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Media.Imaging;
using Caliburn.Micro;
using WixSharp;
using WixSharp.UI.Forms;
using WixSharp.UI.WPF;
namespace Sai.RvKits_Setup
{
///
/// The standard FeaturesDialog.
/// Follows the design of the canonical Caliburn.Micro View (MVVM).
/// See https://caliburnmicro.com/documentation/cheat-sheet
///
///
///
///
public partial class FeaturesDialog : WpfDialog, IWpfDialog
{
///
/// Initializes a new instance of the class.
///
public FeaturesDialog()
{
InitializeComponent();
}
///
/// This method is invoked by WixSHarp runtime when the custom dialog content is internally fully initialized.
/// This is a convenient place to do further initialization activities (e.g. localization).
///
public void Init()
{
ViewModelBinder.Bind(new FeaturesDialogModel(ManagedFormHost), this, null);
}
}
///
/// ViewModel of the feature tree node.
///
///
internal class Node : PropertyChangedBase
{
private bool @checked;
public string Name { get; set; }
public ObservableCollection Nodes { get; set; } // with list and observable collection same results
public bool Checked { get => @checked; set { @checked = value; NotifyOfPropertyChange(() => Checked); } }
public bool DefaultChecked { get; set; }
public object Data { get; set; }
public bool IsEditable { get; set; } = true;
}
///
/// ViewModel for standard FeaturesDialog.
/// Follows the design of the canonical Caliburn.Micro ViewModel (MVVM).
/// See https://caliburnmicro.com/documentation/cheat-sheet
///
///
internal class FeaturesDialogModel : Caliburn.Micro.Screen
{
ManagedForm Host;
ISession session => Host?.Runtime.Session;
IManagedUIShell shell => Host?.Shell;
string selectedNodeDescription;
public ObservableCollection RootNodes { get; set; } = new ObservableCollection();
public FeaturesDialogModel(ManagedForm host)
{
this.Host = host;
BuildFeaturesHierarchy();
}
public BitmapImage Banner => session?.GetResourceBitmap("WixSharpUI_Bmp_Banner").ToImageSource();
public string SelectedNodeDescription
{
get => selectedNodeDescription;
set { selectedNodeDescription = value; NotifyOfPropertyChange(() => SelectedNodeDescription); }
}
///
/// The collection of the features selected by user as the features to be installed.
///
public static List UserSelectedItems { get; set; }
///
/// The initial/default set of selected items (features) before user made any selection(s).
///
static List InitialUserSelectedItems { get; set; }
public void GoPrev()
{
SaveUserSelection();
shell?.GoPrev();
}
/*https://msdn.microsoft.com/en-us/library/aa367536(v=vs.85).aspx
* ADDLOCAL - list of features to install
* REMOVE - list of features to uninstall
* ADDDEFAULT - list of features to set to their default state
* REINSTALL - list of features to repair*/
public void GoNext()
{
if (Host == null) return;
bool userChangedFeatures = UserSelectedItems?.JoinBy(",") != InitialUserSelectedItems.JoinBy(",");
if (userChangedFeatures)
{
string itemsToInstall = features.Where(x => (x.View as Node).Checked)
.Select(x => x.Name)
.JoinBy(",");
string itemsToRemove = features.Where(x => !(x.View as Node).Checked)
.Select(x => x.Name)
.JoinBy(",");
if (itemsToRemove.Any())
session["REMOVE"] = itemsToRemove;
if (itemsToInstall.Any())
session["ADDLOCAL"] = itemsToInstall;
}
else
{
session["REMOVE"] = "";
session["ADDLOCAL"] = "";
}
SaveUserSelection();
shell.GoNext();
}
public void Cancel()
=> shell?.Cancel();
public void Reset()
{
features.ForEach(x => (x.View as Node).Checked = x.DefaultIsToBeInstalled());
}
FeatureItem[] features;
void BuildFeaturesHierarchy()
{
features = session.Features; // must make a copy of the features as they cannot be modified in the session
// build the hierarchy tree
var visibleRootItems = features.Where(x => x.ParentName.IsEmpty())
.OrderBy(x => x.RawDisplay)
.ToArray();
var itemsToProcess = new Queue(visibleRootItems); // features to find the children for
while (itemsToProcess.Any())
{
var item = itemsToProcess.Dequeue();
// create the view of the feature
var view = new Node
{
Name = item.Title,
Data = item, // link view to model
IsEditable = !item.DisallowAbsent,
DefaultChecked = item.DefaultIsToBeInstalled(),
Checked = item.DefaultIsToBeInstalled()
};
item.View = view; // link model to view
if (item.Parent != null && item.Display != FeatureDisplay.hidden)
(item.Parent.View as Node).Nodes.Add(view); //link child view to parent view
// even if the item is hidden process all its children so the correct hierarchy is established
// find all children
features.Where(x => x.ParentName == item.Name)
.ForEach(c =>
{
c.Parent = item; //link child model to parent model
itemsToProcess.Enqueue(c); //schedule for further processing
});
if (UserSelectedItems != null)
view.Checked = UserSelectedItems.Contains((view.Data as FeatureItem).Name);
}
// add views to the treeView control
visibleRootItems
.Where(x => x.Display != FeatureDisplay.hidden)
.Select(x => (Node)x.View)
.ForEach(node => RootNodes.Add(node));
InitialUserSelectedItems = features.Where(x => (x.View as Node).Checked)
.Select(x => x.Name)
.OrderBy(x => x)
.ToList();
}
void SaveUserSelection()
{
UserSelectedItems = features.Where(x => x.IsViewChecked())
.Select(x => x.Name)
.OrderBy(x => x)
.ToList();
}
}
}