Korkboard is a little tool I have been developing that enables a uniform method of storing multiple items on the clipboard. When Korkboard runs, it hooks into the clipboard chain and attempts to intercept messages as you use the Copy and Cut commands. It then stores the items on its own list so that they may be retrieved at a later time. It is important to note that Korkboard does not mess with the functionality of the clipboard. If you copy an item, the clipboard works as expected without any interruption or user required interception. Check it out, and let me know what you think!
Korkboard is written in WPF/.NET4 and uses ClickOnce to manage the installation and update processes.
Update: Added the Zip file for those having trouble using the ClickOnce method.
A design pattern made famous in the .NET community by Microsoft’s ASP.NET, the provider model explains is a pattern that supplies the end-developer with a plug-and-play architecture. The provider model is most often used when you have a consumer object that is dependent on specific functionality that can be supplied by one or more underlying systems. The major benefit of which is an increase in manageability and reusability.
Before I begin this post, big thanks to Eibx and David over at the Community Forums for helping me find these methods. I have modified the CheckTexture method a bit, but its purpose remains unchanged.
As of the last FGF article, the Application class was implementing the IGame interface but was missing the ability to create a render target object on the PC and Xbox 360. For PC games this can be a troubling problem since different hardware can obviously require different formats and dimensions of render target. Rather than bake this functionality into the Application class itself, it is moved to a static helper class so that all developers can make good use of its functionality at any point in time.
To start off, a simple default creation method is included to give the basic functionality an easy access point.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace FocusedGames.Xna.Graphics { public static class GraphicsHelper { public static RenderTarget2D CreateRenderTarget(GraphicsDevice device) { return CreateRenderTarget( device, device.PresentationParameters.BackBufferWidth, device.PresentationParameters.BackBufferHeight, 1, device.PresentationParameters.BackBufferFormat ); } |
This tutorial covers a basic way of implementing two dimensional fog of war for a game in XNA and assumes you (the reader) has basic knowledge of C# and the XNA Framework. To get things started, create an empty Windows game project. Two textures will be needed: one for the Light and one for the Background. After adding these to the Content Project, go ahead and add the following members to the game class.
1 2 3 4 5 6 7 | Texture2D lightTexture; Texture2D backgroundTexture; RenderTarget2D lightTarget; RenderTarget2D mainTarget; Effect basicFogOfWarEffect; |
While the use of the texture fields is obvious, the use of the render targets may not. The concept behind this fog of war implementation is to draw the light texture to the lightTarget render target and then use the produced texture as the alpha channel for the texture produced from the mainTarget render target.
Rather than writing an actual letter, which would do no good, I have chosen to write this post with the idea that as an MVP I should lead and teach by example. One of the most important design principles that factor into designing a framework is that of dependency hierarchies. In less fancy terms it simply means what classes implement what interfaces and where these things are maintained in the framework. Recently I placed a suggestion on Connect to Move INotifyCollectionChanged to System.dll so that more projects that do not require WindowsBase.dll (WPF) could use the functionality. Fortunately for .NET developers everywhere the suggestion was taken (although I won’t claim sole responsibility) and the move is happening.
This post is about the reasons for such a move, and such reasons are incredibly basic to realize. Consider a platform other than Windows whether it be Linux, Windows Mobile, the Xbox 360 or even the Zune HD. Now think about how you would write a framework that supports some of (or all) these platforms and consider the problem of developing a class that implements something like INotifyCollectionChanged. The problem, of course, is that not all the platforms have access to WindowsBase.dll. Thus the developers come to a crossroads: either recreate the functionality for the platforms or don’t implement the functionality.
While that may not seem too unreasonable a dilemma, the problem is that Microsoft implemented functionality in a branched assembly that really has no dependency on any classes or interfaces within that assembly. Here the principle is simple: when possible, move functionality up the assembly hierarchy so as to reduce cross dependencies. In layman’s terms, by moving the INotifyCollectionChanged interface to System.dll, many more projects can take advantage of it without requiring any sort of platform dependent code. And here it is important to remember that one of the original goals of .NET was to enable true cross platform development.
To say that this case is the only one of its kind would be ignorant. The scary thing is that I don’t think anyone actually has a list of where these mistakes exist and what can be done about them. Even scarier than that is the fact that Microsoft is making these mistakes. Consider the following which further demonstrates this point.
While helping someone today with a few questions on the System.Reflection namespace, a point was made about how odd it is to compare generic types. When you have a generic class such as Nullable<T> you cannot do something as simple as if(foo is Nullable) because the generic parameter can make a difference. While this isn’t too much of a problem, Microsoft later also developed the System.Data assembly and included an interface called INullable within this assembly under the System.Data.SqlTypes namespace. This, like INotifyCollectionChanged, constricts the use of this interface to only assemblies that reference System.Data.dll. Furthermore, the interface contains a single boolean property and has not a single dependency on anything within the System.data assembly.
The problem and its solution should be obvious: move INullable to the System namespace in System.dll and make Nullable<T> implement it. This allows developers to easily check whether or not a type represents a nullable type while not creating a single problem in the entire framework’s design. Furthermore it would allow developers to treat System.Nullable and System.Data.SqlTypes.* as the same types which can come in handy.
Update: I added a suggestion on Connect for moving INullable to System.dll.
One of the requirements of the framework I am building (FGF) is cross platform support. For my XNA games this means support for not only Windows but also the Zune and the Xbox 360. For my Windows based projects I often find that X64 can be used (and in the case of IIS in 2008 R2, encouraged) so I also support X64 versions.
The problem is that when using an XNA project template to build a library for the simple fact that XNA projects can automatically synchronized (across platforms), Visual Studio blocks the creation of an X64 build target. Rather you are stuck with X86, Zune or Xbox 360.
The good news is that you can get around this! Open up the Windows project file (csproj) in a suitable text editor and copy the sections for both “Debug|x86″ and “Release|x86″ and paste them right after.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>..\Bin\x86\Debug\</OutputPath> <DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <NoStdLib>true</NoStdLib> <UseVSHostingProcess>false</UseVSHostingProcess> <PlatformTarget>x86</PlatformTarget> <XnaCompressContent>false</XnaCompressContent> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>..\Bin\x86\Release\</OutputPath> <DefineConstants>TRACE;WINDOWS</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <NoStdLib>true</NoStdLib> <UseVSHostingProcess>false</UseVSHostingProcess> <PlatformTarget>x86</PlatformTarget> <XnaCompressContent>true</XnaCompressContent> </PropertyGroup> |
Next you simply replace the instances of x86 with x64 and change anything else you need.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>..\Bin\x64\Debug\</OutputPath> <DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <NoStdLib>true</NoStdLib> <UseVSHostingProcess>false</UseVSHostingProcess> <PlatformTarget>x64</PlatformTarget> <XnaCompressContent>false</XnaCompressContent> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' "> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>..\Bin\x64\Release\</OutputPath> <DefineConstants>TRACE;WINDOWS</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <NoStdLib>true</NoStdLib> <UseVSHostingProcess>false</UseVSHostingProcess> <PlatformTarget>x64</PlatformTarget> <XnaCompressContent>true</XnaCompressContent> </PropertyGroup> |
One warning – this should only be used for projects that don’t require references to the XNA framework. At this time Microsoft has no support for x64 XNA references.
One of the major gripes I have with the Windows operating system is its inability to build decent event logs when an exception occurs. This is particularly annoying on the server builds because as a developer, I need to know what is causing a crash or a hang. Recently I have been developing a site using Sitecore and after a publish the site started crashing and bringing down the entire server. The following is an overview of how I solved the issue.
The first thing I did was check the Event Viewer on the server itself – notice the horrible information within the error. The one important code to write down is the exception code (0xE053534F).
After reading a tutorial on how to catch a crash I was able to catch the crash in a dump file. While the debug diag tool was useful for catching, I needed WinDbg to get to the root of the problem.
Note: I set the symbols location to SRV*c:\users\jsedlak\documents\websymbols*http://msdl.microsoft.com/download/symbols
As you can see, the debug view is fairly useless. Run the following commands:
Now you can see what is causing the stack overflow. Turns out it was an XSLT file that was doing a recursive climb up the Sitecore tree without a base case. The cause of the problem however was that I had just implemented Workflow on all items which corrupted their state and seemed to have removed their published version from the web database. By fixing the XSLT to have a base case and submitting all content through their workflow I was able to get the site back.
With the upcoming release of FGF/Thrust comes the return of a more traditional GUI. One of the most problematic requirements of a large GUI system is the notion of focus. The question remains how do you efficiently determine who has focus and how do you pass focus between controls? On Windows this is incredibly easy because we have the mouse pointer. Focus is changed whenever your mouse acts on a control. What about on the Zune or the Xbox 360 though? On both of these systems their is no mouse (although Thrust supports a virtual mouse).
The answer is to look at what Thrust currently supports. What built in system supports all three systems seamlessly? (~ means some support, X means full support)
| Event | Zune | Windows | Xbox 360 |
| Mouse | X | ||
| Keyboard | X | X | |
| GamePad | ~ | X | X |
| UniversalButton | X | X | X |
The problem is we can’t rely on each individual hardware controller being present and useable. For example we can’t rely on a keyboard being a focusing mechanism on the Xbox 360 because it isn’t a guarantee it exists. Likewise, we cannot rely on the GamePad on the Zune because of the lack of buttons.
To get to the point, the UniversalButton system was meant as a virtualization of the various hardware supported for each platform. It turns GamePad, Mouse, and Keyboard events into simple events like Up, Left, Down, Right, Select and Cancel. Because of this we can rely on it and implement a few more events.
You can consider local tabbing to be much like you would on a Windows form: hitting the tab key (or shift-tab) will move you from one control to another based on some order and only in the context of the global focus point (you never tab to a control in another window). The global tabbing can be considered like an Alt-Tab (or shift-alt-tab) where you can switch between windows.
So how do we implement this? We need a managing class (sorry Bjoern) to produce a bottleneck for the input events. As events are channeled through this class, it massages the data and figures out what to do. For instance if a global tab next event is received it has to switch focus to the next window in the system on the same level as the current window. If it receives a local tab event it will pass a message to the current focal point to tab to the next control.
What does this do for us? For one, it unifies the approach to focusing across all the UI subsystems. This means that a Window/Form implementation will focus in much the same way a simple screen will. Unfortunately it also means a complexity requirement for implementation developers. The age of the simple StateManager class is coming to an end. Elements on the screen now need to have a basic state for animation as well as a state for focus (or lack thereof). While it may still be possible to simply unload an element through the StateManager, the reality is that UI elements will have to do a little more management under the hood. Whether this is exposed to the user / developer is still to be decided.
Knowing how frameworks are designed and developed definately has its benefits. Awhile ago I spent some time looking into how DependencyObject and DependencyProperty work in WPF. Essentially, many of the properties are not simple properties but rather facades for method invocations.
Fast forward to today when I was working on Versionator, an application I am writing to help me manage my many projects’ versions. The problem is that project information files (AssemblyInfo.cs) are not straight forward in terms of parsing. They are merely text files, awkward and malformed code files in fact. To be able to support many properties so easily, I came up with a scheme to parse, manage and save the projects’ properties in the file.
What I do is parse the properties, extracting the data and storing it in a dictionary as “old values.” At the same time I create a copy of the values in a “current values” dictionary. As new values come in, I channel them through properties, then Get and Set methods which access the “current values” dictionary. When it comes time to save I have to do some management of the data based on whether or not the property was empty, non-existant or is being changed to empty. It is simple to say that it would have taken me a lot longer if I had not taken a look at WPF. So was it a spark of genius? Or just plain old learnedness?
The Code (Beware of its massive length):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | using System; using System.Collections.Generic; using System.IO; namespace FocusedGames.Versionator.Data { public class ProjectInfo { public enum Properties : ushort { Title = 0, Description = 1, Company = 2, Product = 3, Copyright = 4, Trademark = 5, AssemblyVersion = 6, FileVersion = 7, Guid = 8 } private readonly string[] lookups = new [] { "AssemblyTitle", "AssemblyDescription", "AssemblyCompany", "AssemblyProduct", "AssemblyCopyright", "AssemblyTrademark", "AssemblyVersion", "AssemblyFileVersion", "Guid" }; private readonly Dictionary<ushort, string> propertyValues = new Dictionary<ushort, string>(); private readonly Dictionary<ushort, string> oldValues = new Dictionary<ushort, string>(); public static ProjectInfo FromFile(string filename) { return new ProjectInfo(filename); } public ProjectInfo() { Array enumValues = Enum.GetValues(typeof (Properties)); foreach(ushort prop in enumValues) { propertyValues.Add(prop, string.Empty); oldValues.Add(prop, string.Empty); } } public ProjectInfo(string filename) : this() { Load(filename); } #region Getting and Setting Project Properties protected void SetProperty(Properties prop, string value) { propertyValues[(ushort) prop] = value; } protected string GetProperty(Properties prop) { string newValue = propertyValues[(ushort) prop]; if(string.IsNullOrEmpty(newValue)) return oldValues[(ushort) prop]; return newValue; } #endregion #region Loading and Saving public void Load(string filename) { Filename = filename; string[] lines = File.ReadAllLines(Filename); Array enumValues = Enum.GetValues(typeof (Properties)); foreach(ushort prop in enumValues) { Load(lines, prop); } } private void Load(string[] lines, ushort lookup) { for(int i = 0; i < lines.Length; i++) { string currentLine = lines[i]; string searchTerm = lookups[lookup]; // Get the first index of the search term int firstIndex = currentLine.IndexOf(searchTerm); // The property wasn't found, continue // through the file. if(firstIndex == -1) continue; // Now we need to extract the data out of the string! string data = currentLine.Substring(firstIndex + searchTerm.Length).TrimFront("\"").TrimBack("\""); oldValues[lookup] = data; propertyValues[lookup] = data; } } public void Save() { string[] lines = File.ReadAllLines(Filename); Array enumValues = Enum.GetValues(typeof(Properties)); foreach (ushort prop in enumValues) Save(lines, prop); StreamWriter sw = new StreamWriter(Filename, false); for(int i = 0; i < lines.Length; i++) sw.WriteLine(lines[i]); sw.Close(); } private void Save(string[] lines, ushort prop) { for (int i = 0; i < lines.Length; i++) { string currentLine = lines[i]; string searchTerm = lookups[prop]; // Get the first index of the search term int firstIndex = currentLine.IndexOf(searchTerm); // The property wasn't found, continue // through the file. if (firstIndex == -1) continue; string oldValueLocal = oldValues[prop]; string newValueLocal = propertyValues[prop]; // If the old value didn't exist, we can adjust the // replacement mechanism to remove the "" and add // them back in. if (string.IsNullOrEmpty(oldValueLocal)) { oldValueLocal = "\"\""; newValueLocal = string.Format("\"{0}\"", newValueLocal); } // We also need to catch people emptying strings out. // To do this we adjust the saving mechanism the same way. if(string.IsNullOrEmpty(newValueLocal)) { oldValueLocal = string.Format("\"{0}\"", oldValueLocal); newValueLocal = "\"\""; } // Replace the old value with the new value if (!string.IsNullOrEmpty(newValueLocal)) lines[i] = lines[i].Replace(oldValueLocal, newValueLocal); } } #endregion public string Filename { get; private set; } public string AssemblyVersion { get { return GetProperty(Properties.AssemblyVersion); } set { SetProperty(Properties.AssemblyVersion, value); } } public string FileVersion { get { return GetProperty(Properties.FileVersion); } set { SetProperty(Properties.FileVersion, value); } } public string Title { get { return GetProperty(Properties.Title); } set { SetProperty(Properties.Title, value); } } public string Description { get { return GetProperty(Properties.Description); } set { SetProperty(Properties.Description, value); } } public string Company { get { return GetProperty(Properties.Company); } set { SetProperty(Properties.Company, value); } } public string Product { get { return GetProperty(Properties.Product); } set { SetProperty(Properties.Product, value); } } public string Copyright { get { return GetProperty(Properties.Copyright); } set { SetProperty(Properties.Copyright, value); } } public string Trademark { get { return GetProperty(Properties.Trademark); } set { SetProperty(Properties.Trademark, value); } } public string Guid { get { return GetProperty(Properties.Guid); } set { SetProperty(Properties.Guid, value); } } } } |
P.S. The code is not done, is not even close to being efficient or functionally complete. But it works!
Tackling the problem in the previous post I have decided to rely on providing more options than necessary. I have to remember that because Vodka is not client software, I have to write it as if the client software will be as simple as possible. The goal of Vodka is to give developers a way of setting up a software based CMS with great ease.
To do this, I have built in services that can be implemented and exposed via WCF as well as built in implementations of these services. If you had the binaries for Vodka, you could reference FocusedGames.Vodka.Services, create a class in a Service project and inherit from ContentService or MembershipService. After deploying the project, you can treat it like any other WCF service reference.
The original question dealt with translation services however, is it a client or server responsibility? You would generally make it client side because you may wish to get a different template for the content or change how translation is done. This is on par with most CMS software installs out there but there is a problem. Templates in the Vodka backend are treated as standard items of content. It then would require two calls to the service: one for the template and one for the content. You would also have to know how the template is extracted from the content item. This is a bad idea as it increases server load unecessarily.
The answer is simple: abstract it and keep it server side. The idea here is that the developers can plugin their own template provider into the service when setting it up. This will allow them to point to another service, a local directory or hardcoded templates. If no plugin is used, the service will continue on its standard course, grabbing the template from the standard content data store.
You may be asking why you would ever want to use a custom provider to point to a second service. Let’s say you have a ton of websites that you all want to look the same. For instance Microsoft may have microsoft.com, msdn.microsoft.com, creators.xna.com, xbox.com, et cetera and may want them to all use the same templates for items. They could use a provider to point to a single template service removing the need to change 5+ templates on 5+ servers.