Jonas Bush

Blog.blog.blog.blog
posts - 17 , comments - 190 , trackbacks - 17

Saturday, August 25, 2012

Windows 8–Custom WinRT components and WinJS

Wow, I’m still alive!

I installed the RTM of Windows 8 when it became available, and in the last few days have started taking a look at writing a windows 8 app using HTML/JS, which in and of itself is a weird thing. I don’t think that windows developers of 10 years ago would’ve thought something like this would have ever come about.

As I was working on this, I ran across a problem, found the solution, and thought I’d blog about it to try and kick start me back into blogging. I already answered my own question on Stack Overflow, but will explain here.

I needed to create a custom WinRT component to do some stuff that I either wouldn’t be able to or didn’t know how to do with the javascript libraries available to me. I had a javascript class defined like this:

WinJS.Namespace.define("MyApp", {
  MyClass: WinJS.Class.define(function() {
    //constructor function
  },
  { /*instance members*/ },
  { /*static members*/ })
});

This gives me an object I can access in javascript: var foo = new MyApp.MyClass();

I created my WinRT component like this:

namespace MyApp
{
  public sealed class SomeClass
  {
    public int SomeMethod()
    {
      return 42;
    }
  }
}

 

With the thought that from my javascript, I’d be able to do this:

var foo = new MyApp.MyClass();
var bar = new MyApp.SomeClass(); //from WinRT component
foo.SomeProperty = bar.SomeMethod();

 

When I tried this, I got the following error when trying to construct MyApp.MyClass (the object defined in Javascript)

0x800a01bd - Javascript runtime error: Object doesn't support this action.

I puzzled for a bit, then noticed while debugging that my “MyApp” namespace didn’t have anything in it other than the WinRT component. I changed my WinRT component to this:

namespace MyAppUtils
{
  public sealed class SomeClass
  {
    //etc
  }
}
And after this, everything was fine. So, lesson learned: If you’re using Javascript and create a custom WinRT component, make sure that the WinRT component is in a namespace all its own. Not sure why this happens, and if I find out why or if MS says something about this somewhere, I’ll come back and update this.

Posted On Saturday, August 25, 2012 4:24 PM | Comments (0) | Filed Under [ .Net Win8 ]

Thursday, July 15, 2010

Creating generic classes at runtime

Hey there!

So recently I was struggling with something for the new job, and was able to figure it out, and thought I'd share it with you, dear readers.

I have a generic class I use for parsing data. Inside that class, I ran across the need to create another instance of the generic class to parse more data, but I didn't know the type at compile time.

So I have this class:

public class MyClass<T> where T: class
{
    public void DoSomething() { }
}
 
 

In the course of DoSomething, I need to create a new MyClass, so I do that as follows:

Type classType = typeof(MyClass<>);
Type myType = classType.MakeGenericType(new Type[1] { someOtherType });
var obj = Activator.CreateInstance(myType, null);
 

So now I have an object "obj" that is a generic of type "someOtherType". Now to call the method!

MethodInfo mi = classType.GetMethod("DoSomething");
mi.Invoke(obj, null); // ERROR!

 

Uhoh! We got an error.

"System.InvalidOperationException: Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true."

I'm not 100% sure what that means, but I took a guess that because my reflected MethodInfo was off of the base generic type, not the new type I created. So I replaced the above with:

MethodInfo mi = myType.GetMethod("DoSomething");
mi.Invoke(obj, null); //SUCCESS!

 

And we're all good! Hope this helps you out at some point.

Posted On Thursday, July 15, 2010 3:45 PM | Comments (1) | Filed Under [ .Net ]

Monday, July 13, 2009

Images being requested twice from the server

*taptaptap* Is this thing on?

 I ran into an interesting bug recently, where you would get 2 identical requests to the page you were visiting. I wasn't sure where this was coming from, so I poked around a bit. It turns out that having an <img /> tag on a page with an empty src attribute (like so: <img src="" />) causes that image tag to point to the containing page, causing the entire page to get requested again (causing any server-side code you may have to get executed again), but the response just gets thrown away, since the img tag is only expecting an image back from the server, not an HTML document.

The way around this is to remove the src attribute altogether, and you can still set the image source through javascript.

 

 

Posted On Monday, July 13, 2009 9:55 AM | Comments (0) |

Monday, March 5, 2007

Curly braces and string.Format()

Recently I was trying to use StringBuilder.AppendFormat to build some javascript, and was hit with an exception when trying to do this:

sb.AppendFormat("function {0}(args) { return false; }", someVariable);

The problem is that you can't have { or } inside an input string for string.Format(). The solution is actually fairly straightforward:

sb.AppendFormat("function {0}(args) {{ return false; }}", someVariable);

Instead of using "\" as an escape character, you would use { or } (depending on what you want to escape).

Posted On Monday, March 5, 2007 2:08 PM | Comments (17) |

Monday, January 29, 2007

Triggering a validator through javscript

In this post, I talked about enabling or disabling a validator client-side. Someone had commented asking how to change the status of a control from valid to invalid. The following javascript works at least for required field validators, I haven't tested it with anything else (but I imagine it should work just fine). Again, this is 2.0, I haven't tested this in 1.1:

var myValidator = document.getElementById('<%=reqField.ClientID%>');
ValidatorValidate(myValidator);

For a required field validator at least, the causes the same actions as clicking on a button on the page.

Hope this helps!

Posted On Monday, January 29, 2007 3:45 PM | Comments (1) |

Wednesday, August 16, 2006

Using Atlas to act as a check on javascript calls

One of the things I've been working on is how to use Atlas web services to verify actions on the server. So the client requests to perform a particular action on the server, and if they don't have access to perform that action or the action fails (because a database is down, or something along those lines), I don't want the method on the client to continue executing.

The problem with that is that Atlas web service calls are asynchronous by nature (explained here and here). So I can't say something like this:

if(myService.myServiceCall() == true)
{
  //do stuff
}

What I've come up with is this javascript object:

function webServiceRunner(webServiceFunction, returnFunction, returnParams)
{
 
var _returnFunction = returnFunction;
 
var _returnParams = returnParams;
 
var _webServiceFunction = webServiceFunction;

  this
.runService = function
()
 
{
   
_webServiceFunction(onServiceComplete);
 
}

  function onServiceComplete(result)
 
{
   
var r = '_returnFunction(';
   
for(var i = 0; i < _returnParams.length; i++)
   
{
     
r +=
'_returnParams[' + i.toString() + ']';
     
if(i < returnParams.length - 1)
       
r +=
',';
   
}
   
r +=
', result);';
   
//alert(r);
   
eval(r);
  
}
}

This takes advantage of some of the nice (and dangerous) features of Javascript, the eval() statement, the arguments object, and function pointers. Eval() will let you create a string, like var s = 'alert(“hi“);'; - and then call eval(s); - the end result of which will be “Hi“ showing up in an alert box. The arguments object is created automatically for you in javascript inside of any function, and contains an array of all the arguments passed into that function.

So now I can instantiate and call this class like so:

<span class="CommandLink" onclick="testOne(this);">Testspan>

function testOne(sender, result)
{
 
if(result == undefined)
 
{
   
var sr = new webServiceRunner(TestWebService.HasAccess, testOne, arguments);
   
sr.runService();
   
return;
 
}

 
if(result)
 
{
 
}
 
else
 
{
   
alert(
'sorry, you are unable to perform that action');
 
}
}

Assuming I have a webservice defined, as well as the proper Atlas script manager setup:

<atlas:scriptmanager id="scriptManager" runat="server">
 
<services>
   
<atlas:servicereference path="TestWebService.asmx" />
 
services>
atlas:scriptmanager>

[WebMethod]
public bool
HasAccess()
{
 
return false;
}

What ends up happening inside the webServiceRunner is that the following string will be created:

_returnFunction(_returnParams[0], result);

Then that string is eval-ed, and my original testOne function is called, with the original sender object (from the original click), and the result parameter from the web service.

If this is confusing, post a comment or send me an email and I'll try and elaborate further. If you think this is silly or useless, leave a comment and explain why. :)

 

Posted On Wednesday, August 16, 2006 2:48 PM | Comments (0) |

Friday, August 11, 2006

Disabling an ASP.Net Validator through Javascript

If you ever find yourself needing to selectively disable an asp.net validator through javascript, you can do the following (in 2.0, not sure if this exists in 1.x):

function doSomething()
{
  var myVal = document.getElementById('myValidatorClientID');
  ValidatorEnable(myVal, false); 

}

Quick and easy! Sadly, not as easy to find through Google, so hopefully this post will help that. :)

Posted On Friday, August 11, 2006 8:57 AM | Comments (97) |

Thursday, July 27, 2006

Enabling/disabling asp.net checkboxes through javascript

The problem:

You want to have a web form with multiple checkboxes, and have some of them be enabled or disabled depending on whether a certain checkbox is checked (or radio button selected, or what have you).

At first glance, this seems fairly simple; you can just do:

<%=myCheckBox.ClientID%>.disabled = false;

in javascript.

The problem comes when you, on the server side, disable the checkbox by default. (NB: this pertains to ASP.Net 2.0, it may work differently in 1.x). The problem is that an <asp:checkbox /> control gets rendered out like this:

<span><input type='checkbox'></span>

The real problem comes when you have a checkbox like this: <asp:checkbox enabled=”false” />. This gets rendered out like this:

<span disabled='disabled'><input type='checkbox' disabled='disabled'></span>

Can you see the problem? In our javascript, when we enable the input, we're not enabling the surrounding span. As it happens, in FireFox, this doesn't seem to be an issue (the checkbox will be enabled as you would expect). In IE6, however, the checkbox will be disabled because the surrounding span is disabled.

To get around this, you can do the following instead of saying myCheckBox.Enabled = false in your code-behind:

myCheckBox.InputAttributes.Add(”disabled”, “disabled”);

(There's also a “LabelAttributes” property of the checkbox, if your control has text that you want to give attributes to explicitly).

Hope this helps!

Posted On Thursday, July 27, 2006 10:10 PM | Comments (85) |

Tuesday, May 9, 2006

Less than useful helpfiles, part 1

In the helps for HtmlInputControl.Name (for .NET 2.0):

Gets or sets the unique identifier name for the HtmlInputControl control.

Later on, in that same help file:

In this implementation, the get accessor returns the value of the Control.UniqueID property. However, the set accessor does not assign a value to this property.

So then why say that it sets the property, if it doesn't actually set the property?

Posted On Tuesday, May 9, 2006 1:37 PM | Comments (1) |

Monday, May 8, 2006

Repeaters, Checkboxes and UpdatePanels, Oh My!

I was working on some sample stuff that I'll be posting later and ran into a problem. I had 2 different update panels; inside one was just a div, inside the other one was a repeater. Inside the repeater I had a bunch of checkboxes, and when I checked/unchecked them, I needed the first update panel to be updated. This posed a couple of problems:

  • A checkbox doesn't have a CommandName property, and can't be used to trigger a Repeater's ItemCommand event

This I got around by declaring the event handler for the checkbox in the markup: OnCheckedChanged=”myCB_OnCheckedChanged”, and in the event handler I can cast the sender argument to a checkbox. The other problem:

  • An UpdatePanel's list of triggers can't include a control that's inside a template

Which means I can't say <atlas:ControlEventTrigger ControlID=”myCB” EventName=”myCB_OnCheckedChanged” />, since myCB doesn't actually exist at runtime. Instead, in myCB_OnCheckedChanged, I can just say: updatePanel1.Update(); and everything works fine.

Hope this helps...

Posted On Monday, May 8, 2006 2:08 PM | Comments (3) |

Wednesday, May 3, 2006

Retrieivng data from XML inside SQL

Recently I had to retrieve some data from SQL that was tucked away inside XML. We have a “Settings” class inside our application that is a bunch of public properties, which we then serialize to XML to store inside the DB. This lets us easily add/remove fields to store without having to modify the database.

This can be a problem if you need to access those one of those field values from within SQL, but SQL 2005 provides some methods to do this (note that your data column must be the xml data type, I haven't found a way to get this to work by casting an ntext field to xml):

Providing your class looks like this:

[XmlSerializable]
public class GlobalSettings
{
  [XmlElement]
  public int SomeValue;
}

Then when serialized, your XML will look similar to this:

<GlobalSettings>
  <SomeValue>5</SomeValue>
</GlobalSettings>

In SQL Management studio, you can write this (assuming GlobalSettings is the table and GlobalSettingsXML is the column where this data is stored):

SELECT GlobalSettingsXML.query('(/GlobalSettings/SomeValue)') FROM GlobalSettings

This will return:

<SomeValue>5</SomeValue>

Which may not be as useful as we want. :) To get the actual value (5) from this, we need to use the value() function:

SELECT GlobalSettingsXML.value('(/GlobalSettings/SomeValue)[1]', 'int') FROM GlobalSettings

This will give us '5', cast to an int. Per the MSDN helps on value(), the [1] is required after your xpath expression because the expression is supposed to return a singleton. I'm not quite sure what that means or how the [1] denotes it, but it works (if you know, by all means tell me!).

Hopefully this will be of use to you.

 


 

Posted On Wednesday, May 3, 2006 1:07 PM | Comments (0) |

Monday, April 3, 2006

Atlas and JSON

I just finished up some code that uses some other functionality of atlas.  To sum up: Whoa! This may be available in AJAX.net or some of the other frameworks, but I was amazed at how easy this was:
 
I have a web service that returns a class, like so:
 
public class MyClass
{
  public string MyString;
  public int MyInt;
}
 
[WebMethod(true)]
public MyClass MyWebMethod()
{
  //init MyClass here
  MyClass myClass = new MyClass();
  return myClass;
}

 
the beauty of it is, I have access to those fields in my javascript:
 
function callWS()
{
  MyWebService.MyWebMethod(onComplete);
}
 
function onComplete(result)
{
  alert(result.MyString);
}

 
Very very very very cool :)
 

Posted On Monday, April 3, 2006 2:10 PM | Comments (0) |

Wednesday, February 15, 2006

Success!

After struggling with Atlas for awhile, we finally released our latest feature on http://www.squeet.com. The new “Preview“ functionality uses the Atlas UpdatePanel to display the 5 latest entries for any blog you enter. It will by default show only a summary of the item, but you can click on the “expand“ link to show the full HTML content for the entry.

The UpdatePanel is surrounding a standard ASP.Net repeater control, which contains some LinkButtons. The UpdatePanel responds to the RowCommand event raised by the repeater, and all the code to handle the event is normal code-behind code. The Atlas portion of this portion was very easy to implement (once I got away from using the WebService calls directly, those don't seem to be fully mature yet).

preview

Posted On Wednesday, February 15, 2006 11:18 AM | Comments (0) |

Monday, February 13, 2006

Atlas, Viewstate, IE and FF.

In my inaugural post, I described a problem I had with a WebMethod erroring out instantly on the client, accompanied by a puzzling message in the Event Log, regarding viewstate.

On a whim, on that site, I decided to “publish” the website from within VS 2005 to a separate directory.  I set up another virtual directory within IIS to point to that directory, loaded up the site and IE, and all my WebMethod calls were working!

From IE6, that is.

From FireFox, none of the calls work on the published website....

...the first time. If I click on the link that calls the WebMethod again (after getting the instant error), it works fine. Very weird.

Posted On Monday, February 13, 2006 7:47 AM | Comments (0) |

Putting the hair back in.

In this post, I mentioned tearing my hear out because I couldn't get a gridview to work right with the update panel. Today I decided to just start on a fresh web form and everything seems to be working fine.

I did learn that an updatepanel without any triggers will consume any server-side event that fires inside of it (ie, to get paging and sorting working you don't need to explicitly specify triggers to handle those events). I also learned that (and this isn't related to Atlas) a gridview's page and sort events also fire off RowCommand events...which I guess make sense since the header is a “row” and the pager thing is also a “row”.

Still trying to figure out the updatePanel inside of a userControl thing figured out, I'll keep you posted.

Posted On Monday, February 13, 2006 7:07 AM | Comments (0) |

Powered by: