Wednesday, 22 September 2010

C# List sorting

DirectoryInfo dir = new DirectoryInfo(@"C:\temp");
List<FileInfo> files = new List<FileInfo>(dir.GetFiles());
files.Sort((x, y) => DateTime.Compare(x.LastWriteTime,y.LastWriteTime));

WPF Toolkit DataGrid & Chart example

  • Download WPF Toolkit
  • Create new WPF Project
  • Add References to WPFTookit, WPFTookit.Design (DataGrid)
  • Add Reference to System.Windows.Controls.DataVisualization.Toolkit (Chart)

image

This is XAML

<Window x:Class="WpfDataGrid.Window2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit"
    xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
    Title="WPF Toolkit DataGrid &amp; Chart" Height="357" Width="590">
    <DockPanel LastChildFill="True">                        
            <toolkit:DataGrid ItemsSource="{Binding Path=Data}" Height="118" AutoGenerateColumns="False" DockPanel.Dock="Top">
                <toolkit:DataGrid.Columns>
                    <toolkit:DataGridTextColumn Binding="{Binding Date}" Header="Date"/>
                    <toolkit:DataGridTextColumn Binding="{Binding Value}" Header="Value"/>
                </toolkit:DataGrid.Columns>
            </toolkit:DataGrid>
                    <charting:Chart DockPanel.Dock="Bottom">
                <charting:LineSeries
                    ItemsSource="{Binding Path=Data}"
                    IndependentValuePath="Date"
                    DependentValuePath="Value"/>
                <charting:AreaSeries
                    ItemsSource="{Binding Path=Data}"
                    IndependentValueBinding="{Binding Date}"
                    DependentValueBinding="{Binding Value}"/>
        </charting:Chart>                
    </DockPanel>
</Window>

And the Code Behind

namespace WpfDataGrid
{
    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();
            DataContext = this;
            Init();
        }
        private void Init()
        {
            _data.Add(new Point(new DateTime(2010, 1, 1), 20));
            _data.Add(new Point(new DateTime(2010, 2, 1), 32));
            _data.Add(new Point(new DateTime(2010, 3, 1), 55));
            _data.Add(new Point(new DateTime(2010, 4, 1), 84));
            _data.Add(new Point(new DateTime(2010, 5, 1), 68));
        }
        ObservableCollection<Point> _data = new ObservableCollection<Point>();
        public ObservableCollection<Point> Data
        {
            get{ return _data;}
        }
        public class Point : DependencyObject
        {
            public static readonly DependencyProperty _date = DependencyProperty.Register("Date", typeof(DateTime), typeof(Point));
            public Point(DateTime date, double value)
            {
                Date = date;
                Value = value;
            }
            public DateTime Date
            {
                get { return (DateTime)GetValue(_date); }
                set { SetValue(_date, value); }
            }
            public static readonly DependencyProperty _value = DependencyProperty.Register("Value", typeof(double), typeof(Point));
            public double Value
            {
                get { return (double)GetValue(_value); }
                set { SetValue(_value, value); }
            }
        }
    }
}

Friday, 10 September 2010

C# WCF sample with Callback

  • Create new C# Library Project
  • Add Reference to System.ServiceModel
  • Define your service interface
namespace PubSubLibrary
{
[ServiceContract(
CallbackContract = typeof(IPubSubCallback),
SessionMode=SessionMode.Required)]
public interface IPubSubService
{
[OperationContract(IsOneWay = true)]
void Subscribe(string clientId);
[OperationContract(IsOneWay = true)]
void Publish(string clientId, string message);
}
}
  • Define your callback interface
namespace PubSubLibrary
{
public interface IPubSubCallback
{
[OperationContract(IsOneWay = true)]
void Broadcast(CallbackData callbackData);
}
[DataContract]
public class CallbackData
{
[DataMember]
public string ClientId { get; set; }
[DataMember]
public string Message { get; set; }
}
}
  • Create Server C# Console Project
  • Add Reference to Library project and System.ServiceModel
  • Add App.config item
  • Configure App.config (right click and select Edit WCF Configuration)
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MetadataBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MetadataBehavior" name="PubSubServer.PubSubService">
<clear />
<endpoint address="mex" binding="ws2007HttpBinding" contract="IMetadataExchange"
listenUriMode="Explicit">
</endpoint>
<endpoint address="net.tcp://localhost:8086" binding="netTcpBinding"
contract="PubSubLibrary.IPubSubService" listenUriMode="Explicit">
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8085/pubsub" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
  • Implement your service class
namespace PubSubServer
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class PubSubService : IPubSubService
{
Dictionary<string, Subscription> subscriptions = new Dictionary<string, Subscription>();
public void Subscribe(string clientId)
{
Subscription subscription = new Subscription();
subscription.Callback = OperationContext.Current.GetCallbackChannel<IPubSubCallback>();
subscription.ClientId = clientId;
if(subscriptions.ContainsKey(clientId))
{
subscriptions.Remove(clientId); //remove old connection
}
subscriptions.Add(clientId, subscription);
Console.WriteLine("{0}: Connected", clientId);
}
public void Publish(string clientId, string message)
{
Console.WriteLine("{0}: {1}", clientId, message);
CallbackData callbackData = new CallbackData();            
callbackData.ClientId = clientId;
callbackData.Message = message;
Callback(callbackData);
}
public void Callback(CallbackData callbackData)
{            
for (int i = subscriptions.Count - 1; i >= 0; i--)
{
string key = subscriptions.Keys.ToArray()[i];
Subscription subscription = subscriptions[key];
try
{
subscription.Callback.Broadcast(callbackData);
}
catch (Exception)
{
subscriptions.Remove(subscription.ClientId);
Console.WriteLine("{0}: Disconnected", subscription.ClientId);                    
}
}
}
}
class Subscription
{
public string ClientId { get; set; }
public IPubSubCallback Callback { get; set; }
}
}
  • Host your service
namespace PubSubServer
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(PubSubService));
host.Open();
Console.WriteLine("Server running..");
Console.ReadLine();
}
}
}
  • Start your server
  • Create WPF client project
  • Add Reference to System.ServiceModel and System.Runtime.Serialization
  • Generate stubs
    • Right click on References and select Add Service Reference
    • Specify address http://localhost:8085/pubsub?wsdl
    • Alternatively generate stubs/configuration using command line svcutil tool in visual studio command prompt
svcutil /t:code http://localhost:8085/pubsub?wsdl /out:PubSubServiceProxy.cs /config:App.config /async
    • Add generated App.config and PubSubServiceProxy.cs to your client project
  • Implement Callback
namespace PubSubClient
{
internal class PubSubCallback : IPubSubServiceCallback
{
#region Delegates
public delegate void CallbackEventHandler(object source, CallbackEvent e);
#endregion
#region IPubSubServiceCallback Members
public void Broadcast(CallbackData callbackData)
{
fireCallbackEvent(callbackData);
}
#endregion
public event CallbackEventHandler callback;
private void fireCallbackEvent(CallbackData callbackData)
{
if (callback != null)
{
callback(this, new CallbackEvent(callbackData));
}
}
}
public class CallbackEvent : EventArgs
{
private readonly CallbackData callbackData;
public CallbackEvent(CallbackData callbackData)
{
this.callbackData = callbackData;
}
public CallbackData CallbackData
{
get { return callbackData; }
}
}
}
  • Implement your client WPF application
<Window x:Class="PubSubClient.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="PubSub Client" Height="326" Width="579" ResizeMode="CanResizeWithGrip">
<DockPanel LastChildFill="True">
<StatusBar DockPanel.Dock="Bottom" Height="18"/>
<Grid>
<Grid.ColumnDefinitions>                
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox x:Name="clientId" Grid.Row="0" Grid.Column="0"  HorizontalAlignment="Stretch"  VerticalAlignment="Stretch"></TextBox>
<Button x:Name="subscribe" Grid.Row="0" Grid.Column="1"  HorizontalAlignment="Stretch"  VerticalAlignment="Stretch"  Content="Subscribe" Click="subscribe_Click"></Button>
<TextBox x:Name="message" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" HorizontalAlignment="Stretch"  VerticalAlignment="Stretch" PreviewKeyDown="message_PreviewKeyDown"></TextBox>
<Button x:Name="publish" Grid.Row="1" Grid.Column="3"  HorizontalAlignment="Stretch"  VerticalAlignment="Stretch"  Content="Send" Click="publish_Click"></Button>
<ListBox x:Name="messages" Grid.Row="2" Grid.ColumnSpan="4" />            
</Grid>
</DockPanel>
</Window>
namespace PubSubClient
{
public partial class Window1 : Window
{
private PubSubServiceClient client;
private bool isConnected;
public Window1()
{
InitializeComponent();
PubSubCallback callback = new PubSubCallback();
callback.callback += new PubSubCallback.CallbackEventHandler(callback_callback);
InstanceContext context = new InstanceContext(callback);
client = new PubSubServiceClient(context);
clientId.Text = Environment.UserName;
publish.IsEnabled = false;
}
void callback_callback(object source, CallbackEvent e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate
{
AddMessage(string.Format("{0}: {1}", e.CallbackData.ClientId, e.CallbackData.Message));
}));
}
private void subscribe_Click(object sender, RoutedEventArgs e)
{
Subscribe();
}
private void publish_Click(object sender, RoutedEventArgs e)
{
Publish(message.Text);
}
private void message_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
Publish(message.Text);
e.Handled = true;
}
}
private void Subscribe()
{
try
{                
client.Subscribe(clientId.Text);                
isConnected = true;
clientId.IsReadOnly = true;
subscribe.IsEnabled = false;
publish.IsEnabled = true;
}
catch (Exception ex)
{
MessageBox.Show("Failed to Connect.");
isConnected = false;
}
}
private void Publish(string text)
{
if (isConnected)
{
try
{
client.Publish(clientId.Text, text);
message.Clear();
}catch(Exception ex)
{
MessageBox.Show("Server is not responding");
}                
}
}
private void AddMessage(string message)
{
messages.Items.Add(message);
messages.ScrollIntoView(message);
}
}
}
  • Start your client app, specify clientId (your username by default) and click subscribe. To send a message type a message and click Send.
image
image

Calling F# function from C# application

  • Download and install F#
  • Create new Project Visual F# / F# Library
  • Create a sample Module
module MathLib
    let square x = x*x 
  • Create new C# Console Project
  • Add Reference to F# Library project
  • Call function from F# module
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(MathLib.square(4));
        Console.ReadLine();
    }
}