Write a GUI in Powershell – Part 3

3a. Create data module in C#, This is useful when doing data binding. Don’t know if Powershell is able to create a custom object inherit a C# interface. But Powershell can use Add-Type to add a C# class. Then we just create a simple C# class, and add it to Powershell.

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Dynamic;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.ComponentModel;
using System.Management.Automation;

public class DynamicViewModel : DynamicObject, INotifyPropertyChanged
{
private Hashtable properties;
public event PropertyChangedEventHandler PropertyChanged;
public int debugLevel=0;

public DynamicViewModel()
{
this.properties = new Hashtable();
}

public DynamicViewModel(Hashtable data)
{
this.properties = data;
}

public int Count
{
get
{
return properties.Count;
}
}

public System.Collections.ICollection Keys
{
get
{
return properties.Keys;
}
}

public System.Collections.ICollection Values
{
get
{
return properties.Values;
}
}

// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
DebugPrint("Get: " + binder.Name + " = " +  " | " + binder.Name.GetType());
result = properties.ContainsKey(binder.Name) ? properties[binder.Name] : null;
return true;
}

// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(SetMemberBinder binder, object value)
{
DebugPrint("TrySetMember: " + binder.Name + " = " + value + " | " + binder.Name.GetType() + " = " + value.GetType());
properties[binder.Name] = value;
RaisePropertyChanged(binder.Name);
return true;
}

// Get the property value by index.
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
DebugPrint("TryGetIndex: " + indexes[0] + " = " + " | " + indexes[0].GetType());
result = properties.ContainsKey(indexes[0].ToString()) ? properties[indexes[0].ToString()] : null;
return true;
}

// Set the property value by index.
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
try
{
DebugPrint("TrySetIndex: " + indexes[0] + " = " + value + " | " + indexes[0].GetType() + " = " + value.GetType());
//properties[indexes[0].ToString()] = value;
properties[(String)indexes[0]] = value;
RaisePropertyChanged((String)indexes[0]);
return true;
}
catch (Exception e)
{
DebugPrint("TrySetIndex Exception: " + e);
return false;
}

}

public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
DebugPrint("TryInvokeMember: ");
try
{
if (properties.ContainsKey(binder.Name))
{
DebugPrint("TryInvokeMember Key Found: " + binder.Name + " | " + properties[binder.Name].GetType());
result = ((ScriptBlock)properties[binder.Name]).InvokeReturnAsIs(args);
//result = ((Func<object[], object>)properties[binder.Name]).Invoke(args);
DebugPrint("TryInvokeMember Key Found - result: " + result);
}
else
{
DebugPrint("TryInvokeMember Key Not Found: " + binder.Name);
result = null;
return false;
}
return true;
}
catch (Exception e)
{
DebugPrint("TryInvokeMember Exception: " + e);
result = null;
return false;
}
}

// Converting an object to a specified type.
public override bool TryConvert(ConvertBinder binder, out object result)
{
// Converting to string.
if (binder.Type == typeof(String))
{
result = "DynamicViewModel with " +
((properties.Count > 1) ? ("" + properties.Count + " Dynamic Properties") :
("" + properties.Count + " Dynamic Property"));
return true;
}

// In case of any other type, the binder
// attempts to perform the conversion itself.
// In most cases, a run-time exception is thrown.
return base.TryConvert(binder, out result);
}

public override IEnumerable<String> GetDynamicMemberNames()
{
return properties.Keys.Cast<String>() ;
}

public override string ToString()
{
return "DynamicViewModel with " +
((properties.Count > 1) ? ("" + properties.Count + " Dynamic Properties") :
("" + properties.Count + " Dynamic Property"));
}

public bool Remove(string name)
{
if (properties.ContainsKey(name))
{
properties.Remove(name);
return true;
}
else
{
return false;
}
}

public void Print()
{
foreach (DictionaryEntry pair in properties)
{
if (pair.Value != null)
{
Console.WriteLine(pair.Key + " \t" + pair.Value + " \t" + pair.Value.GetType());
}
else
{
Console.WriteLine(pair.Key + " \t" + pair.Value + " \tNull Value");
}

}

if (properties.Count == 0)
Console.WriteLine("No elements in the dictionary.");
}

protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}

protected void DebugPrint(String s)
{
if (debugLevel == 1)
{
Console.WriteLine(s);
}
}
}

3b. Add DynamicViewModel.cs to Powershell

$csharp1=Get-Content (Join-Path $path "DynamicViewModel.cs") -Raw
Add-Type -TypeDefinition $csharp1

Advertisements
This entry was posted in C#, Powershell, XAML. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s