Real singleton approach in WPF application
One of the most common problems in WPF is memory/processor time consumption. Yes, WPF is rather greedy framework. It become even greedier when using unmanaged resources, such as memory files or interop images. To take care on it, you can implement singleton pattern for the application and share only one unmanaged instance among different application resources. So today we’ll try to create one large in-memory dynamic bitmap and share it between different instances of WPF controls. Let’s start
First of all let’s create our single instance source. The pattern is straight forward. Create a class derived from INotifyPropertyChanged, create private constructor and static member returns the single instance of the class.
public class MySingleton : INotifyPropertyChanged {
#region Properties
public BitmapSource Source { get { return _source; } }
public static MySingleton Instance {
get {
if (_instance == default(MySingleton)) _instance = new MySingleton();
return _instance;
}
}
#endregion#region ctor
private MySingleton() { _init(); }
#endregion
Now we need to create this single instance of this class inside our XAML program. To do this, we have great extension x:Static
<Window.DataContext>
<x:StaticExtension Member="l:MySingleton.Instance" />
</Window.DataContext>
Now we need to find a way to do all dirty work inside MySingleton and keep classes using it as simple is possible. For this purpose we’ll register class handler to catch all GotFocus routed events, check the target of the event and rebind the only instance to new focused element. How to do this? Simple as 1-2-3
Create class handler
EventManager.RegisterClassHandler(typeof(FrameworkElement), FrameworkElement.GotFocusEvent, (RoutedEventHandler)_onAnotherItemFocused);
Check whether selected and focused item of the right type
private void _onAnotherItemFocused(object sender, RoutedEventArgs e) {
DependencyPropertyDescriptor.FromProperty(ListBoxItem.IsSelectedProperty, typeof(ListBoxItem)).AddValueChanged(sender, (s, ex) => {}
and reset binding
var item = s as ListBoxItem;
var img = item.Content as Image;
if (_current != null && _current.Target is Image && _current.Target != img) {
((Image)_current.Target).ClearValue(Image.SourceProperty);
}
if (img != null) {
_current = new WeakReference(img);
img.SetBinding(Image.SourceProperty, _binding);
}
We almost done. a bit grease to make the source bitmap shiny
var count = (uint)(_w * _h * 4);
var section = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0×04, 0, count, null);
_map = MapViewOfFile(section, 0xF001F, 0, 0, count);
_source = Imaging.CreateBitmapSourceFromMemorySection(section, _w, _h, PixelFormats.Bgr32, (int)(_w * 4), 0) as InteropBitmap;
_binding = new Binding {
Mode = BindingMode.OneWay,
Source = _source
};
CompositionTarget.Rendering += (s, e) => { _invalidate(); };
private void _invalidate() {
var color = (uint)((uint)0xFF << 24) | (uint)(_pixel << 16) | (uint)(_pixel <<| (uint)_pixel;
_pixel++;unsafe {
uint* pBuffer = (uint*)_map;
int _pxs = (_w * _h);
for (var i = 0; i < _pxs; i++) {
pBuffer[i] = color;
}
}
_source.Invalidate();
OnPropertyChanged("Source");
}
And we done. The usage of this approach is very simple – there is no usage at all. All happens automagically inside MySingleton class, all you need is to set static data context and add images
<StackPanel>
<Button Click="_addAnother">Add another…</Button>
<ListBox Name="target" />
</StackPanel>
…
private void _addAnother(object sender, RoutedEventArgs e) {
var img = new Image { Width=200, Height=200, Margin=new Thickness(0,5,0,5) };
target.Items.Add(img);
this.Height += 200;
}
To summarize: in this article we learned how to use singletons as data sources for your XAML application, how to reuse it across WPF, how to connect to routed events externally and also how to handle dependency property changed from outside of the owner class. Have a nice day and be good people.
Source code for this article (21k) >>
To make it works press number of times on “Add another…” button and then start selecting images used as listbox items. Pay attention to the working set of the application. Due to the fact that only one instance is in use it is not growing.
August 24th, 2009 · Comments (4)
INotifyPropertyChanged auto wiring or how to get rid of redundant code
For the last week most of WPF disciples are discussing how to get rid of hardcoded property name string inside INotifyPropertyChanged implementation and how to keep using automatic properties implementation but keep WPF binding working. The thread was started by Karl Shifflett, who proposed interesting method of using StackFrame for this task. During this thread other methods were proposed including code snippets, R#, Observer Pattern, Cinch framework, Static Reflection, Weak References and others. I also proposed the method we’re using for our classes and promised to blog about it. So the topic today is how to use PostSharp to wire automatic implementation of INotifyPropertyChanged interface based on automatic setters only.
So, I want my code to looks like this:
public class AutoWiredSource {
public double MyProperty { get; set; }
public double MyOtherProperty { get; set; }
}
while be fully noticeable about any change in any property and makes me able to bind to those properties.
<StackPanel DataContext="{Binding Source={StaticResource source}}">
<Slider Value="{Binding Path=MyProperty}" />
<Slider Value="{Binding Path=MyProperty}" />
</StackPanel>
How to achieve it? How to make compiler to replace my code with following?:
private double _MyProperty;
public double MyProperty {
get { return _MyProperty; }
set {
if (value != _MyProperty) {
_MyProperty = value; OnPropertyChanged("MyProperty");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
internal void OnPropertyChanged(string propertyName) {
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");var handler = PropertyChanged as PropertyChangedEventHandler;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
Simple: to use aspect oriented programming to inject set of instructions into pre-compiled source.
First of all we have to build some attribute will be used for marking classes requires change tracking. This attribute should be combined (compound) aspect to include all aspects used for change tracking. All we’re doing here is to get all set methods to add composition aspect to
[Serializable, DebuggerNonUserCode, AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false, Inherited = false),
MulticastAttributeUsage(MulticastTargets.Class, AllowMultiple = false, Inheritance = MulticastInheritance.None, AllowExternalAssemblies = true)]
public sealed class NotifyPropertyChangedAttribute : CompoundAspect {
public int AspectPriority { get; set; }public override void ProvideAspects(object element, LaosReflectionAspectCollection collection) {
Type targetType = (Type)element;
collection.AddAspect(targetType, new PropertyChangedAspect { AspectPriority = AspectPriority });
foreach (var info in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(pi => pi.GetSetMethod() != null)) {
collection.AddAspect(info.GetSetMethod(), new NotifyPropertyChangedAspect(info.Name) { AspectPriority = AspectPriority });
}
}
}
Next aspect is change tracking composition aspect. Which is used for marking only
[Serializable]
internal sealed class PropertyChangedAspect : CompositionAspect {
public override object CreateImplementationObject(InstanceBoundLaosEventArgs eventArgs) {
return new PropertyChangedImpl(eventArgs.Instance);
}public override Type GetPublicInterface(Type containerType) {
return typeof(INotifyPropertyChanged);
}public override CompositionAspectOptions GetOptions() {
return CompositionAspectOptions.GenerateImplementationAccessor;
}
}
And the next which is most interesting one, we will put onto method boundary for tracking. There are some highlights here. First we do not want to fire PropertyChanged event if the actual value did not changed, thus we’ll handle the method on it entry and on it exit for check.
[Serializable]
internal sealed class NotifyPropertyChangedAspect : OnMethodBoundaryAspect {
private readonly string _propertyName;public NotifyPropertyChangedAspect(string propertyName) {
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");
_propertyName = propertyName;
}public override void OnEntry(MethodExecutionEventArgs eventArgs) {
var targetType = eventArgs.Instance.GetType();
var setSetMethod = targetType.GetProperty(_propertyName);
if (setSetMethod == null) throw new AccessViolationException();
var oldValue = setSetMethod.GetValue(eventArgs.Instance,null);
var newValue = eventArgs.GetReadOnlyArgumentArray()[0];
if (oldValue == newValue) eventArgs.FlowBehavior = FlowBehavior.Return;
}public override void OnSuccess(MethodExecutionEventArgs eventArgs) {
var instance = eventArgs.Instance as IComposed<INotifyPropertyChanged>;
var imp = instance.GetImplementation(eventArgs.InstanceCredentials) as PropertyChangedImpl;
imp.OnPropertyChanged(_propertyName);
}
}
We almost done, all we have to do is to create class which implements INotifyPropertyChanged with internal method to useful call
[Serializable]
internal sealed class PropertyChangedImpl : INotifyPropertyChanged {
private readonly object _instance;public PropertyChangedImpl(object instance) {
if (instance == null) throw new ArgumentNullException("instance");
_instance = instance;
}public event PropertyChangedEventHandler PropertyChanged;
internal void OnPropertyChanged(string propertyName) {
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");var handler = PropertyChanged as PropertyChangedEventHandler;
if (handler != null) handler(_instance, new PropertyChangedEventArgs(propertyName));
}
}
We done. The last thing is to reference to PostSharp Laos and Public assemblies and mark compiler to use Postsharp targets (inside your project file (*.csproj)
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<DontImportPostSharp>True</DontImportPostSharp>
</PropertyGroup>
<Import Project="PostSharp\PostSharp-1.5.targets" />
Now we done. We can use clear syntax like following to make all our properties has public setter to be traceable. The only disadvantage is that you’ll have to drag two Post Sharp files with your project. But after all it much more convenience than manual notify change tracking all over your project.
[NotifyPropertyChanged]
public class AutoWiredSource {
public double MyProperty { get; set; }
}
Have a nice day and be good people. Also try to thing what other extremely useful things can be done with PostSharp (or any other aspect oriented engine)
Source code for this article (1,225 KB)>>
August 9th, 2009 · Comments (6)
How to calculate CRC in C#?
First of all, I want to beg your pardon about the frequency of posts last time. I’m completely understaffed and have a ton of things to do for my job. This why, today I’ll just write a quick post about checksum calculation in C#. It might be very useful for any of you, working with devices or external systems.

CRC – Cyclic Redundancy Check is an algorithm, which is widely used in different communication protocols, packing and packaging algorithms for assure robustness of data. The idea behind it is simple – calculate unique checksum (frame check sequence) for each data frame, based on it’s content and stick it at the end of each meaningful message. Once data received it’s possible to perform the same calculating and compare results – if results are similar, message is ok.
There are two kinds of CRC – 16 and 32 bit. There are also less used checksums for 8 and 64 bits. All this is about appending a string of zeros to the frame equal in number of frames and modulo two device by using generator polynomial containing one or more bits then checksum to be generated. This is very similar to performing a bit-wise XOR operation in the frame, while the reminder is actually our CRC.
In many industries first polynomial is in use to create CRC tables and then apply it for performance purposes. The default polynomial, defined by IEEE 802.3 which is 0xA001 for 16 bit and 0×04C11DB7 for 32 bit. We’re in C#, thus we should use it inversed version which is 0×8408 for 16 bit and 0xEDB88320 for 32 bit. Those polynomials we’re going to use also in our sample.
So let’s start. Because CRC is HashAlgorithm after all, we can derive our classes from System.Security.Cryptography.HashAlgorithm class.
public class CRC16 : HashAlgorithm {
public class CRC32 : HashAlgorithm {
Then, upon first creation we’ll generate hashtables with CRC values to enhance future performance. It’s all about values table for bytes from 0 to 255 , so we should calculate it only once and then we can use it statically.
[CLSCompliant(false)]
public CRC16(ushort polynomial) {
HashSizeValue = 16;
_crc16Table = (ushort[])_crc16TablesCache[polynomial];
if (_crc16Table == null) {
_crc16Table = CRC16._buildCRC16Table(polynomial);
_crc16TablesCache.Add(polynomial, _crc16Table);
}
Initialize();
}[CLSCompliant(false)]
public CRC32(uint polynomial) {
HashSizeValue = 32;
_crc32Table = (uint[])_crc32TablesCache[polynomial];
if (_crc32Table == null) {
_crc32Table = CRC32._buildCRC32Table(polynomial);
_crc32TablesCache.Add(polynomial, _crc32Table);
}
Initialize();
}
Then let’s calculate it
private static ushort[] _buildCRC16Table(ushort polynomial) {
// 256 values representing ASCII character codes.
ushort[] table = new ushort[256];
for (ushort i = 0; i < table.Length; i++) {
ushort value = 0;
ushort temp = i;
for (byte j = 0; j < 8; j++) {
if (((value ^ temp) & 0×0001) != 0) {
value = (ushort)((value >> 1) ^ polynomial);
} else {
value >>= 1;
}
temp >>= 1;
}
table[i] = value;
}
return table;
}private static uint[] _buildCRC32Table(uint polynomial) {
uint crc;
uint[] table = new uint[256];// 256 values representing ASCII character codes.
for (int i = 0; i < 256; i++) {
crc = (uint)i;
for (int j = 8; j > 0; j–) {
if ((crc & 1) == 1)
crc = (crc >> 1) ^ polynomial;
else
crc >>= 1;
}
table[i] = crc;
}return table;
}
The result will looks like this for 32 bits
0x00, 0x31, 0x62, 0x53, 0xC4, 0xF5, 0xA6, 0x97,
0xB9, 0x88, 0xDB, 0xEA, 0x7D, 0x4C, 0x1F, 0x2E,
0x43, 0x72, 0x21, 0x10, 0x87, 0xB6, 0xE5, 0xD4,
0xFA, 0xCB, 0x98, 0xA9, 0x3E, 0x0F, 0x5C, 0x6D,
0x86, 0xB7, 0xE4, 0xD5, 0x42, 0x73, 0x20, 0x11,
0x3F, 0x0E, 0x5D, 0x6C, 0xFB, 0xCA, 0x99, 0xA8,
0xC5, 0xF4, 0xA7, 0x96, 0x01, 0x30, 0x63, 0x52,
0x7C, 0x4D, 0x1E, 0x2F, 0xB8, 0x89, 0xDA, 0xEB,
0x3D, 0x0C, 0x5F, 0x6E, 0xF9, 0xC8, 0x9B, 0xAA,
0x84, 0xB5, 0xE6, 0xD7, 0x40, 0x71, 0x22, 0x13,
0x7E, 0x4F, 0x1C, 0x2D, 0xBA, 0x8B, 0xD8, 0xE9,
0xC7, 0xF6, 0xA5, 0x94, 0x03, 0x32, 0x61, 0x50,
0xBB, 0x8A, 0xD9, 0xE8, 0x7F, 0x4E, 0x1D, 0x2C,
0x02, 0x33, 0x60, 0x51, 0xC6, 0xF7, 0xA4, 0x95,
0xF8, 0xC9, 0x9A, 0xAB, 0x3C, 0x0D, 0x5E, 0x6F,
0x41, 0x70, 0x23, 0x12, 0x85, 0xB4, 0xE7, 0xD6,
0x7A, 0x4B, 0x18, 0x29, 0xBE, 0x8F, 0xDC, 0xED,
0xC3, 0xF2, 0xA1, 0x90, 0x07, 0x36, 0x65, 0x54,
0x39, 0x08, 0x5B, 0x6A, 0xFD, 0xCC, 0x9F, 0xAE,
0x80, 0xB1, 0xE2, 0xD3, 0x44, 0x75, 0x26, 0x17,
0xFC, 0xCD, 0x9E, 0xAF, 0x38, 0x09, 0x5A, 0x6B,
0x45, 0x74, 0x27, 0x16, 0x81, 0xB0, 0xE3, 0xD2,
0xBF, 0x8E, 0xDD, 0xEC, 0x7B, 0x4A, 0x19, 0x28,
0x06, 0x37, 0x64, 0x55, 0xC2, 0xF3, 0xA0, 0x91,
0x47, 0x76, 0x25, 0x14, 0x83, 0xB2, 0xE1, 0xD0,
0xFE, 0xCF, 0x9C, 0xAD, 0x3A, 0x0B, 0x58, 0x69,
0x04, 0x35, 0x66, 0x57, 0xC0, 0xF1, 0xA2, 0x93,
0xBD, 0x8C, 0xDF, 0xEE, 0x79, 0x48, 0x1B, 0x2A,
0xC1, 0xF0, 0xA3, 0x92, 0x05, 0x34, 0x67, 0x56,
0x78, 0x49, 0x1A, 0x2B, 0xBC, 0x8D, 0xDE, 0xEF,
0x82, 0xB3, 0xE0, 0xD1, 0x46, 0x77, 0x24, 0x15,
0x3B, 0x0A, 0x59, 0x68, 0xFF, 0xCE, 0x9D, 0xAC
Now, all we have to do is to upon request to lookup into this hash table for related value and XOR it
protected override void HashCore(byte[] buffer, int offset, int count) {
for (int i = offset; i < count; i++) {
ulong ptr = (_crc & 0xFF) ^ buffer[i];
_crc >>= 8;
_crc ^= _crc32Table[ptr];
}
}
new public byte[] ComputeHash(Stream inputStream) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.Read(buffer, 0, 4096)) > 0) {
HashCore(buffer, 0, bytesRead);
}
return HashFinal();
}
protected override byte[] HashFinal() {
byte[] finalHash = new byte[4];
ulong finalCRC = _crc ^ _allOnes;
finalHash[0] = (byte)((finalCRC >> 0) & 0xFF);
finalHash[1] = (byte)((finalCRC >>
& 0xFF);
finalHash[2] = (byte)((finalCRC >> 16) & 0xFF);
finalHash[3] = (byte)((finalCRC >> 24) & 0xFF);
return finalHash;
}
We done. Have a good time and be good people. Also, I want to thank Boris for helping me with this article. He promised to write here some day…
April 6th, 2009 · Comments (1)
Making TFS better or what is TITS?
Those days me and my team work very hard toward new version of “The System”. This includes massive refactoring of all solutions, hard work with TFS (which not restricted to only adding files, but also deleting, moving, etc. other words, all stuff, which TFS is not really love). Because of this, we need a bunch of handy tools to make our dreams come true and to decrease unnecessary number of clicks inside Team System Explorer and Visual Studio. You do not really think, that we have no tools to make our everyday job easier. We have. However, we never package and release it. Let me introduce “TITS” – Tools, Invaluable for Team System. This suite I’m planning to release as another open source project within couple of months.
What “TITS” includes? First of all –
“QOF” – Quick Open File
This tools is absolutely invaluable if you have big solutions. While all it knows to do is to search. But, wait, what’s wrong with build-in search of Visual Studio? First of all, it does not search Solution items and files, are in solution directory, but not in project. Also it cannot fix your typos and errors. Also it does not know to move you quickly to found solution item in Solution Explorer or in Source Editor.
Basic set of QOF features:
- No mouse – open any file
- No mouse – locate any file in solution explorer
- Highlighting found items
- Multiple files open
- Filter by source files only, resources, owner or any other kind of filters
- Search inside TFS, including history, changesets, shelves (either private and public)
- …and much much more
Next tool is:
“WIBREW” – Who Is Breaking What
Absolutely invaluable tool to know who actually breaking what file inside TFS. For example, I do not want to lock files, while I still want to know who holds what file. TFS provides such feature out-of-the-box, however from command prompt only. You can add it even as macro. Like this:
However it not user friendly and impossible for use, ‘cos it looks as following:
You do not know what actually developer doing, where and why. With “WIBREW”, you can know:
- When developer started to break files
- What exactly he’s doing
- Is the breaking file locked or now
- Where the developer breaks it (workspace and computer name of the user)
- …and much much more
Another tool is:
“WITCH” – What I have To Check-in
If you ever worked with Team Force, you know what this tool is doing. It shows you a preview of all changed files, you’ll check-in. For some reason, TFS has no such feature. Let’s imagine, that your work method is to check out everything, change something and check-in only changed files. Until here TFS does everything, however if you want to preview changeset (for example in order to compare with “WIBREW” output), you can not. Here “WITCH” comes to help.
[Here should be a screenshot of “WITCH”, but it looks exactly the same as “WIBREW” with shameless blurring]
Another invaluable tool is:
“VOCUS” – VOid CUstom Settings for check in
This tool is absolutely UI-less. It allows developers to work with their own custom settings in Visual Studio, while for check-in and check-out it format all documents, according predefined custom settings (for example indentation). How many times, you tried to merge files, when all the difference is indentation it tab size? Well, this tool solves this problem.
It stores custom settings for each user (BTW, it also makes able for each developer to restore his settings fluently in any computer) and reformat documents on check-in action toward corporate settings, when on check-out toward custom developer’s setting.
“SHMOC” – SHow MOre Code
This is not actually tool, works with TFS. It rather works with your Visual Studio Development Environment. It’s UI-less as well and makes able to hide and restore all docking windows in VS. It makes you able to write in “Dark Room” mode (which is full screen, distraction free environment) and return to Visual Studio within one button press. It can also change VS color scheme, if required.
There are some other tools should be inside this suite, however, I still have no names for them
Also, if you have something interesting, and you want to contribute it to this suite, you’re highly welcome.
PS: This blog is about code, but this post is 6th in row without even one line of code, so I have to fix it as soon as possible. Thus, I’ll example how WIBREW works under the hood. Other words, small example of how to work with TFS API from Visual Studio plugin.
First of all, as in any VS plugin, you need to acquire DTE2 application object:
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
When you have it, you need to detect what TFS server you’re working with and what are user credentials for this session. The common problem of WIBREW for poor men, was how to work with this tool over VPN (when your connected session is only inside VS). So each time, you tried to run it, you had to enter your domain credentials – very inconvenience way of work.
In order to prevent it, let’s ask your environment about Team Foundation information:
private TeamFoundationServerExt _tfsExt;
…
_tfsExt = (TeamFoundationServerExt)_applicationObject.GetObject("Microsoft.VisualStudio.TeamFoundation.TeamFoundationServerExt");
Also, you can be notified when your work project context was changed. To do this, just subscribe to ProjectContextChanged event and handle it inside:
_tfsExt.ProjectContextChanged += OnProjectContextChanged;
…
public void OnProjectContextChanged(object sender, EventArgs e) {
if (!string.IsNullOrEmpty(_tfsExt.ActiveProjectContext.ProjectName)) {
Now when we know, that we have out active project context, all we have to do is to ask about changes
private VersionControlExt _vcExt;
…
_vcExt = (VersionControlExt)_applicationObject.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt");
Inside VersionControlExt object you have following self-descriptive properties and methods: FindChangeSet, History, PendingChanges, SolutionWorkspace etc. however it works only with TFS solution explorer. To handle pending changes for the project without tickling TFS, we can use it internal methods. All the difference is with references. To work with Visual Studio TFS explorer methods, you should reference:
Microsoft.VisualStudio.TeamFoundation.dll, Microsoft.VisualStudio.TeamFoundation.Client.dll and Microsoft.VisualStudio.TeamFoundation.VersionControl.dll, while working with TFS API directly, use Microsoft.TeamFoundation.dll, Microsoft.TeamFoundation.Client.dll and Microsoft.TeamFoundation.VersionControl.dll from [PROGRAM FILES]\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\. Just like this:
VersionControlServer _vcs…_vcs = (VersionControlServer)_server.GetService(typeof(VersionControlServer));…var _sets = _vcs.QueryPendingSets( new[] { new ItemSpec(serverPath, RecursionType.Full) }, null, null);…foreach (PendingSet set in sets) {…
//Get everything you need here
We done. It’s very easy to work with Team System from inside Visual Studio. Also it’s very easy to build useful tools, not built by Microsoft for some reason
Have a nice day, be good people and wait for me to beatify sources before releasing as another Open Source application.
January 27th, 2009 · Comments (9)
Nifty time savers for WPF development
I just published an article on Code Project, that explains how to use my latest FM USB library for building real world software radio receiver with WPF. There I referenced to some nifty WPF time savers, I’m using for everyday development. So, today I want to share those code pieces with you.
Binding time savers
Want to use following syntax for set binding in code?
Presets.SetBinding(ListBox.ItemsSourceProperty, _device, "Presets");
This piece of code sets binding to Preset DependencyObject, which is Listbox and connects ListBox.ItemsSource dependency property with “Presets” property of CLR object _device. How it done? Simple, as usual
[DebuggerStepThrough]
public static BindingExpressionBase SetBinding(this DependencyObject target, DependencyProperty dp, object source, string path) {
Binding b = new Binding(path);
b.Source = source;
return BindingOperations.SetBinding(target, dp, b);
}
But what to do when we need a converter? Simple:
[DebuggerStepThrough]
public static BindingExpressionBase SetBinding(this DependencyObject target, DependencyProperty dp, object source, string path, IValueConverter converter) {
Binding b = new Binding(path);
b.Source = source;
b.Converter = converter;
return BindingOperations.SetBinding(target, dp, b);
}
However to use this method, we need to create special object, which implements IValueConverter. Whey not to do it generically? Like this:
SignalTransform.SetBinding(ScaleTransform.ScaleYProperty, _device.RDS,"SignalStrength", new ValueConverter<byte, double>(b => { return 1-(b / 36d); }));
But we need this special handy ValueConverter class. What’s the problem? Here come the king:
public class ValueConverter<TIN, TOUT> : IValueConverter {
public ValueConverter(Func<TIN, TOUT> forwardConversion) {
ForwardConversion = forwardConversion;
}public ValueConverter(Func<TIN, TOUT> forwardConversion, Func<TOUT, TIN> reverseConversion) {
ForwardConversion = forwardConversion;
ReverseConversion = reverseConversion;
}public Func<TIN, TOUT> ForwardConversion { get; set; }
public Func<TOUT, TIN> ReverseConversion { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
try {
var in1 = Object.ReferenceEquals(value, DependencyProperty.UnsetValue) ? default(TIN) : (TIN)value;
return ForwardConversion(in1);
} catch {
return Binding.DoNothing;
}
}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
try {
var out1 = Object.ReferenceEquals(value, DependencyProperty.UnsetValue) ? default(TOUT) : (TOUT)value;
return ReverseConversion(out1);
} catch {
return Binding.DoNothing;
}
}}
Isn’t it really simple? But what to do with ugly App.Current.Dispatcher.BeginInvoke((SendOrPostCallback)delegate(object o)…? Use dispatcher time savers.
Dispatcher time savers
Don’t you ever want to do this in order to make context switching between UI thread and other application thread in WPF?
this.Dispatch(() => {… DO SOMETHING IN UI THREAD …};
Now you can (with default and preset DispatcherPriority:
public static DispatcherOperation Dispatch(this DispatcherObject sender, Action callback) { return sender.Dispatch(DispatcherPriority.Normal, callback); }
public static DispatcherOperation Dispatch(this DispatcherObject sender, DispatcherPriority priority, Action callback) {
if (sender.Dispatcher == null) return null;
if (sender.Dispatcher.CheckAccess()) {
callback();
return null;
} else {
return sender.Dispatcher.BeginInvoke(priority, callback);
}
}
Nice, isn’t it? But what to do if we do not want to set binding, but we do want to be notified about property change of dependency objects?
Bindingless handlers time saver
Let’s assume, that we have “Tune” UIelement, which has Angle property, but not exposes PropertyChanged event (like it done with Rotary custom control by Expression Blend team… Designers, you know…
However I want to be able to add handler for Angle dependency property changed event and do something when it changed. Like this:
Tune.AddValueChanged(RotaryControl.RotaryControl.AngleProperty, (s, ex) => {
_device.Tune(Tune.Angle > _prevTune);
_prevTune = Tune.Angle;
});
Here comes our time saver for this purpose:
public static void AddValueChanged(this DependencyObject sender, DependencyProperty property, EventHandler handler) {
DependencyPropertyDescriptor.FromProperty(property, sender.GetType()).AddValueChanged(sender, handler);
}
But if we add handler we should be able to remove it too.
public static void RemoveValueChanged(this DependencyObject sender, DependencyProperty property, EventHandler handler) {
DependencyPropertyDescriptor.FromProperty(property, sender.GetType()).RemoveValueChanged(sender, handler);
}
Now we done with some of my nifty helpers. And last, but not the least:
All times question: how to scale ranges
Here is how
public static double ToRange(this double value, double minSource, double maxSource, double minTarget, double maxTarget) {
var sr = maxSource – minSource;
var tr = maxTarget – minTarget;
var ratio = sr / tr;
return minTarget+(value / ratio);
}
Now we can connect them and get something like this:
Volume.AddValueChanged(RotaryControl.RotaryControl.AngleProperty, (s, ex) => {
DirectSoundMethods.Volume = (int)Volume.Angle.ToRange(Volume.CounterClockwiseMostAngle, Volume.ClockwiseMostAngle, -4000, 0);
});
Isn’t it brilliant?
Have a good day and be sure to read and rate my last article on Code Project
Be good people.
January 8th, 2009 · Comments (2)
Source code for Silverlight 2 controls
Too much exciting news today. Shortly after announced about Windows 7 beta download, I found, that Joe Stegman, Seema Ramchandani, Andre Michaud, Jon Sheller and other guys from Silverlight team released the source code of managed Silverlight controls, included in System.Windows.dll, System.Windows.Controls.dll, and System.Windows.Controls.Data.dll. Get it, you have a lot of thing to learn from this package.
Download Silverlight 2.0 controls source code >>
January 7th, 2009 · Comments (2)
Audio CD operation including CD-Text reading in pure C#
Recently we spoke about reading radio data in C#, however as in any vehicle we have also CD players. So what can be better, than to have an ability to play CDs while being notified about track name, gathered from CD-Text?
So, let’s start. First of all, I want to express my pain with MSDN documentation about CD-ROM structure. Documentation team, please, please, please update it. First of all it is no accurate, then there are a ton of things missing. However, “À la guerre comme à la guerre”, thus I invested three days in deep DDK research.
Before we can do anything with CD-ROM, we have to find it. I took the same approach as I used for HID devices. Let’s create a device
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public class CDDADevice : SafeHandleZeroOrMinusOneIsInvalid, IDisposable, INotifyPropertyChanged {
Internal constructor for security reasons
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
internal CDDADevice(char drive) : base(true) {
findDevice(drive);
}
And a find method itself
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
private void findDevice(char drive) {
if (Drive == drive) return;
if (Native.GetDriveType(string.Concat(drive, ":\")) == Native.DRIVE.CDROM) {
this.handle = Native.CreateFile(string.Concat("\\.\", drive, ‘:’), Native.GENERIC_READ, Native.FILE_SHARE_READ, IntPtr.Zero, Native.OPEN_EXISTING, Native.FILE_ATTRIBUTE_READONLY | Native.FILE_FLAG_SEQUENTIAL_SCAN, IntPtr.Zero);
if (this.handle.ToInt32() != -1 && this.handle.ToInt32() != 0) this.Drive = drive;
}
}
Where GetDriveType and CreateFile are win32 methods with following signatures
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern DRIVE GetDriveType(string drive);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern bool CloseHandle(IntPtr hHandle);
Also, we need some constants
internal enum DRIVE : byte {
UNKNOWN = 0,
NO_ROOT_DIR,
REMOVABLE,
FIXED,
REMOTE,
CDROM,
RAMDISK
}internal const uint GENERIC_READ = 0×80000000;
internal const uint FILE_SHARE_READ = 0×00000001;
internal const uint OPEN_EXISTING = 3;
internal const uint FILE_ATTRIBUTE_READONLY = 0×00000001;
internal const uint FILE_FLAG_SEQUENTIAL_SCAN = 0×08000000;
Now, when we have our cdrom handle in hands, we can read it’s Table Of Content. Now, thing become harder because of the fact, that we have to use very complicated platform method:
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeviceIoControl(
[In] IntPtr hDevice,
IOCTL dwIoControl,
[In] IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
When thing are generic it’s good, however this one is, probably, most generic method in Win32 API. You can do anything with this method and you never know what to expect in lpOutBuffer
However, as I told earlier, I invested three days in investigations and researches (tnx to DDK documentation team) and now things become to be clearer. We need to get CDROM_TOC. It done by invoking IOCTL_CDROM_READ_TOC call
uint bytesRead = 0;
TOC = new Native.CDROM_TOC();
TOC.Length = (ushort)Marshal.SizeOf(TOC);
var hTOC = Marshal.AllocHGlobal(TOC.Length);
Marshal.StructureToPtr(TOC, hTOC, true);
if (Native.DeviceIoControl(this.handle, Native.IOCTL.CDROM_READ_TOC, IntPtr.Zero, 0, hTOC, TOC.Length, out bytesRead, IntPtr.Zero)) Marshal.PtrToStructure(hTOC, TOC);
Marshal.FreeHGlobal(hTOC);
But, not too fast. CDROM_TOC contains array of TRACK_DATA with unknown size.
typedef struct _CDROM_TOC { UCHAR Length[2]; UCHAR FirstTrack; UCHAR LastTrack; TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];} CDROM_TOC, *PCDROM_TOC;typedef struct _TRACK_DATA { UCHAR Reserved; UCHAR Control : 4; UCHAR Adr : 4; UCHAR TrackNumber; UCHAR Reserved1; UCHAR Address[4];} TRACK_DATA, *PTRACK_DATA;
P/Invoke it! But how to marshal unknown array? We should create wrapper object. Also there is very fun BitVector, used in this structure! What’s the problem? Pin it with some Math!
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class CDROM_TOC {public ushort Length;
public byte FirstTrack;
public byte LastTrack;
public TRACK_DATA_ARRAY TrackData;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct TRACK_DATA {public byte Reserved;
public byte bitVector;
public byte Control {
get { return ((byte)((this.bitVector & 15u))); }
set { this.bitVector = ((byte)((value | this.bitVector))); }
}
public byte Adr {
get { return ((byte)(((this.bitVector & 240u) / 16))); }
set { this.bitVector = ((byte)(((value * 16) | this.bitVector))); }
}
public byte TrackNumber;
public byte Reserved1;
public uint Address;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal sealed class TRACK_DATA_ARRAY {internal TRACK_DATA_ARRAY() { data = new byte[MAXIMUM_NUMBER_TRACKS * Marshal.SizeOf(typeof(TRACK_DATA))]; }
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_NUMBER_TRACKS * 8)]
private byte[] data;public TRACK_DATA this[int idx] {
get {
if ((idx < 0) | (idx >= MAXIMUM_NUMBER_TRACKS)) throw new IndexOutOfRangeException();
TRACK_DATA res;
var hData = GCHandle.Alloc(data, GCHandleType.Pinned);
try {
var buffer = hData.AddrOfPinnedObject();
buffer = (IntPtr)(buffer.ToInt32() + (idx * Marshal.SizeOf(typeof(TRACK_DATA))));
res = (TRACK_DATA)Marshal.PtrToStructure(buffer, typeof(TRACK_DATA));
} finally {
hData.Free();
}
return res;
}
}
}
Fuf, done. The code is rather self explaining, we just “tell” marshaler, that we have byte array, while calculating pointers to pinned object to get actual value and marshal it back. So, now we have TOC. So, we know how many tracks we have and addresses to data chunks inside the CD.
But it now enough to understand where our tracks. CD-ROM structure is very tricky. There we have blocks or sectors (which is the smallest chunks of data), so we have to convert bytes into sector addresses. Each block is 2352 bytes in RAW mode, while address value inside TRACK_DATA points us to layout address with is sync, sector id, error detection etc… So, in order to convert TRACK object into actual track number on disk, we have to stick to following method
public static int SectorAddress(this TRACK_DATA data) {
var addr = BitConverter.GetBytes(data.Address);return (addr[1] * 60 * 75 + addr[2] * 75 + addr[3]) – 150;
}
Now, when we know numbers of tracks, we also know start and end sector, disk type and other useful information we are ready to twist it a bit and read CD-Text (if there are and your CD reader supports it).
So, coming back to our favorite method DeviceIoControl, but this time with IOCTL_CDROM_READ_TOC_EX control.
bytesRead = 0;
TOCex = new Native.CDROM_READ_TOC_EX {Format = Native.CDROM_READ_TOC_EX_FORMAT.CDTEXT
};
var sTOCex = Marshal.SizeOf(TOCex);
var hTOCex = Marshal.AllocHGlobal(sTOCex);
Marshal.StructureToPtr(TOCex, hTOCex, true);
var Data = new Native.CDROM_TOC_CD_TEXT_DATA();
Data.Length = (ushort)Marshal.SizeOf(Data);var hData = Marshal.AllocHGlobal(Data.Length);
Marshal.StructureToPtr(Data, hData, true);
if (Native.DeviceIoControl(this.handle, Native.IOCTL.CDROM_READ_TOC_EX, hTOCex, (ushort)sTOCex, hData, Data.Length, out bytesRead, IntPtr.Zero)) Marshal.PtrToStructure(hData, Data);
Marshal.FreeHGlobal(hData);
Marshal.FreeHGlobal(hTOCex);
Looks too simple? Let’s see inside CDROM_READ_TOC_EX structure. It is very similar to _CDROM_TOC.
typedef struct _CDROM_READ_TOC_EX { UCHAR Format : 4; UCHAR Reserved1 : 3; UCHAR Msf : 1; UCHAR SessionTrack; UCHAR Reserved2; UCHAR Reserved3;} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX;
Simple. Isn’t it?
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CDROM_READ_TOC_EX {public uint bitVector;
public CDROM_READ_TOC_EX_FORMAT Format {
get { return ((CDROM_READ_TOC_EX_FORMAT)((this.bitVector & 15u))); }
set { this.bitVector = (uint)((byte)value | this.bitVector); }
}
public uint Reserved1 {
get { return ((uint)(((this.bitVector & 112u) / 16))); }set { this.bitVector = ((uint)(((value * 16) | this.bitVector))); }
}
public uint Msf {
get { return ((uint)(((this.bitVector & 128u) / 128))); }set { this.bitVector = ((uint)(((value * 128) | this.bitVector))); }
}
public byte SessionTrack;
public byte Reserved2;
public byte Reserved3;
}
But what will come inside lpOutBuffer? Fellow structure, named CDROM_TOC_CD_TEXT_DATA with unknown size array of CDROM_TOC_CD_TEXT_DATA_BLOCK
typedef struct _CDROM_TOC_CD_TEXT_DATA { UCHAR Length[2]; UCHAR Reserved1; UCHAR Reserved2; CDROM_TOC_CD_TEXT_DATA_BLOCK Descriptors[0];} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA;typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK { UCHAR PackType; UCHAR TrackNumber:7; UCHAR ExtensionFlag:1; UCHAR SequenceNumber; UCHAR CharacterPosition:4; UCHAR BlockNumber:3; UCHAR Unicode:1; union { UCHAR Text[12]; WCHAR WText[6]; }; UCHAR CRC[2];} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK;
Too bad to be true. Isn’t it? Let’s try to marshal it my hands (with the trick used for TRACK_DATA
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class CDROM_TOC_CD_TEXT_DATA {public ushort Length;
public byte Reserved1;
public byte Reserved2;
public CDROM_TOC_CD_TEXT_DATA_BLOCK_ARRAY Descriptors;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal sealed class CDROM_TOC_CD_TEXT_DATA_BLOCK_ARRAY {internal CDROM_TOC_CD_TEXT_DATA_BLOCK_ARRAY() { data = new byte[MINIMUM_CDROM_READ_TOC_EX_SIZE * MAXIMUM_NUMBER_TRACKS * Marshal.SizeOf(typeof(CDROM_TOC_CD_TEXT_DATA_BLOCK))]; }
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MINIMUM_CDROM_READ_TOC_EX_SIZE * MAXIMUM_NUMBER_TRACKS * 18)]
private byte[] data;public CDROM_TOC_CD_TEXT_DATA_BLOCK this[int idx] {
get {
if ((idx < 0) | (idx >= MINIMUM_CDROM_READ_TOC_EX_SIZE * MAXIMUM_NUMBER_TRACKS)) throw new IndexOutOfRangeException();
CDROM_TOC_CD_TEXT_DATA_BLOCK res;
var hData = GCHandle.Alloc(data, GCHandleType.Pinned);
try {
var buffer = hData.AddrOfPinnedObject();
buffer = (IntPtr)(buffer.ToInt32() + (idx * Marshal.SizeOf(typeof(CDROM_TOC_CD_TEXT_DATA_BLOCK))));
res = (CDROM_TOC_CD_TEXT_DATA_BLOCK)Marshal.PtrToStructure(buffer, typeof(CDROM_TOC_CD_TEXT_DATA_BLOCK));
} finally {
hData.Free();
}
return res;
}
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CDROM_TOC_CD_TEXT_DATA_BLOCK {public CDROM_CD_TEXT_PACK PackType;
public byte bitVector1;
public byte TrackNumber {
get { return ((byte)((this.bitVector1 & 127u))); }
set { this.bitVector1 = ((byte)((value | this.bitVector1))); }
}
public byte ExtensionFlag {
get { return ((byte)(((this.bitVector1 & 128u) / 128))); }set { this.bitVector1 = ((byte)(((value * 128) | this.bitVector1))); }
}
public byte SequenceNumber;
public byte bitVector2;public byte CharacterPosition {
get { return ((byte)((this.bitVector2 & 15u))); }set { this.bitVector2 = ((byte)((value | this.bitVector2))); }
}
public byte BlockNumber {
get { return ((byte)(((this.bitVector2 & 112u) / 16))); }set { this.bitVector2 = ((byte)(((value * 16) | this.bitVector2))); }
}
public byte Unicode {
get { return ((byte)(((this.bitVector2 & 128u) / 128))); }set { this.bitVector2 = ((byte)(((value * 128) | this.bitVector2))); }
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12, ArraySubType = UnmanagedType.I1)]
public byte[] TextBuffer;
public string Text {
get { return (Unicode == 1) ? ASCIIEncoding.ASCII.GetString(TextBuffer) : UTF32Encoding.UTF8.GetString(TextBuffer); }}
public ushort CRC;
}
Can’t you see a small problem here? Yes, we do not know the actual/maximum size of CDROM_TOC_CD_TEXT_DATA_BLOCK array. Until, I’ll find a nice way to marshal smart pointers, we’ll stick to MAX_TRACKS (100) * MIN_DATA_BLOCK (2).
We almost finished and the worst things are behind us. Now you should enumerate thru CDROM_TOC_CD_TEXT_DATA_BLOCK and look for Text, TrackNumber and SequenceNumber (which is continuation of text reported). For example, slot for ALBUM_NAME “Satisfaction” will looks as following
| BlockNumber | 0×00 |
| CharacterPosition | 0×00 |
| CRC | 0×3EAB |
| SequenceNumber | 0×00 |
| Text |