WELCOME
Friday, December 4, 2009
SetPropertyValues never called in custom ProfileProvider
Profile's underlying object model is complex and less than intuitive. The challenge for me was trying to figure out what things had to be implemented in order to get basic functionality working.
The major roadblock I ran into was that at the point that I was code complete and everything seemed like it "should" have been working I couldn't get anything to save. No errors, but nothing was saving.
All Profile saves go through SetPropertyValues and when I set a break point on my overridden version of this method it was just never getting hit.
After hours of trashing about I finally found the answer in this thread: http://forums.asp.net/t/635411.aspx
The gist of the problem is that before every save Profile calls GetProfileValues, and if the result returned by GetProfileValues isn't properly populated SetPropertyValues just doesn't get called. Highly unintuitive.
Here is the quote from the thread that finally solved the problems for me:
"Basically, somewhere in GetPropertyValues, there should be code new'ing up SettingsPropertyValue instances that looks like:
SettingsPropertyValue sv = new SettingsPropertyValues(SettingsPropertyInstanceGoesHere);
You get the SettingsProperty instance from the SettingsPropertyCollection that is passed in as a parameter to the GetPropertyValues method."
When I'm done these providers will be published on Codeplex as part of my ScrappyDB C# library for SimpleDB.
Sunday, November 29, 2009
Happy Holidays!
Family 2.0 portrait at "the Farm" in Grand Marais over Thanksgiving. Photo by Gramma Betsy.
Wednesday, November 11, 2009
Question from a friend: I need a more "professional" email address, but I don't want to give up my Gmail address
Example current address: binge.drinker@gmail.com
New email address: john.a.doe@gmail.com
No problem!
- First step create the new Gmail account.
- Then you need to pick which mailbox you want to use as the primary one that you are going to login to (you probably want to keep using the existing one, because it has all your old mail).
- Go into the new email box and click on the "Settings" link at the top right.
- Select the "Forwarding and POP/IMAP" tab.
- Select "Forward a copy of incoming mail to" and enter the email address of the old account.
- I would recommend setting "archive Gmail's copy".
You are now done with step one. All email sent to the new address should start showing up in you old inbox. Now you want to be able choose which address to use when you send/reply to email in your old inbox.
- Go into the old email box and click on the "Settings" link at the top right.
- Select the "Accounts and Import" tab.
- Go to the "Send mail as:" section and click the "Send mail from another address" button enter the other (new) email address.
- Check the "Reply from the same address the message was sent to" option.
- Gmail is now going to send you an email to confirm that you own the other address, you will need to click a link in the email to confirm.
Now when you are composing an email you will notice there is "change" link after the "From:" address. You can use this to pick which address you would like your email to be from.
Monday, November 9, 2009
ScrappyDB: C# Object Mapper for Amazon SimpleDB
http://scrappydb.codeplex.com/
Project Description
ScrappyDB is a simple object mapper for storing .NET classes and collections in Amazon SimpleDB. It is currently under active development to support the needs of a specific website. As such it only provides functionality to support the needs of one "customer", this means that there are many "obvious" use cases and data types that are not yet supported... because we didn't need them. But we think other people may find it useful, so we are sharing it here...
Why create an new tool instead of using one of the existing .NET tools for SimpleDB?
In particular:
- Simple Savant http://simplesavant.codeplex.com/ (Simple Savant is a great tool and definitly a more mature code base. We would recommend that you investigate it first before considering ScrappyDB.)
Features that we felt were important for our implementation:
- Support for multi-value attributes (using arrays or arraylists).
- Support for nested objects and relationships (in particular cases where a custom class has a property that is a collection of some other custom class).
- Integrated support for web caching for performance.
- Location data (in particular the ability to do proximity searches "show me all records within 5 miles of X").
Things that we did NOT feel were important for our implementation:
- Support for all .NET data types (we only support a subset of "common" data types, but there is no reason you can't enhance it to support the one you need).
- Update caching to work around "eventual consistency" (if you don't have a full understanding of what eventual consistency means take the time to learn about it before you decide whether SimpleDB is a viable platform for your data).
About the source code
- To do what it does ScrappyDB makes extensive use of some painful reflection.
- The code does not follow any identifiable design patterns and it doesn't follow any of the latest inversion of control fashions: "I'm just a caveman, and I'm not familiar with your modern ways..."
Known Issues:
- Current code is definitely ALPHA, has not had any significant production use.
- Relationship logic is lightly testing, is probably buggy and is likely to see some significant refactoring.
- We are planning to add a second relationship type that uses multivalued attributes for "1 to few" relationships ("1 to many" relationships use an intermediate relationship "table" which is slower).
Dependencies
- ScrappyDb is dependent on the excellent Amazon C# Library for SimpleDB http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1133&categoryID=148
Documentation
- Currently the primary developer documentation for ScrappyDB is the unit tests included with the source code.
But here are a few basic examples to help you get started:
Basic Save
var db = new DB();
var o = new MyClass {Id = Guid.NewGuid, TestProperty = "HelloWorld"};
db.Save(o);
Basic Load by Id
var result = db.Load(testId);
Save a Collection
var a = new ScrappyDbCollection();
a.Add(new TestItem() { Id = Guid.NewGuid(), TestString = "test1" });
a.Add(new TestItem() { Id = Guid.NewGuid(), TestString = "test2" });
a.Add(new TestItem() { Id = Guid.NewGuid(), TestString = "test3" });
a.Save();
Query a Collection
var b = new ScrappyDbCollection();
b.QueryCollection(" TestString = 'test2' ");
Tuesday, September 1, 2009
WSOD Google Style (White Screen of Darn)
FYI: There is an application status page at Google for major apps: http://www.google.com/appsstatus
UPDATE: Great post on the Gmail Blog detailing what caused today's outage: http://gmailblog.blogspot.com/2009/09/more-on-todays-gmail-issue.html
Error | |
Server Error
The server encountered a temporary error and could not complete your request.
Please try again in 30 seconds.
Thursday, June 18, 2009
Happy Early Father's Day To Me!
The kids all got matching shirts (including one for me) for a Father's Day picture...
Thursday, June 11, 2009
MVVM Questions: Can a View Model close a window and other puzzlers
Many sample WPF applications written using MVVM (Model - View - View Model) only use a single Window, but the LOB (Line Of Business) applications I’ve been working on use LOTS of windows for different business tasks, and this has brought up a number of interesting questions about the “right” or “best” or “most practical” way to manage multiple Windows in a WPF application using MVVM?
Questions:
- Does a Window create it’s View Model?
- Or does the View Model create it’s Window?
- Or does “something else” create the View Model and the Window and then bind them together?
- How do you close a Window?
- Can a View Model close itself and it’s Window?
Our Answers:
- We created a “Window Service” which is basically a Singleton with a Dictionary of all the open Windows and View Models in the application, and a few related methods to deal with opening and closing Windows .
- To open a Window you supply the Window Service with Window and a View Model. The Window Service deals with binding the two together, showing the Window, and then keeping track of the open Windows.
- If a user (or something else) tries to close a Window we catch the Window_Closing event using AttachedCommandBehavior (see XAML below) and call a command on the View Model Base Class to give the View Model control over the closing event.
<acb:CommandBehaviorCollection.Behaviors>
<acb:BehaviorBinding Event="Initialized" Command="{Binding Path=Window_InitializedCommand}" />
<acb:BehaviorBinding Event="Activated" Command="{Binding Path=Window_ActivatedCommand}" />
<acb:BehaviorBinding Event="Closing" Command="{Binding Path=Window_ClosingCommand}" />
</acb:CommandBehaviorCollection.Behaviors>
- View Models have the ability to close themselves (and their related Window) by calling the Window Service.
Wednesday, June 10, 2009
A simple method of binding the selected values of a list in WPF with MVVM
Using the MVVM pattern in WPF applications simplifies some aspects of developing and testing WPF applications, but it add quite a bit of complexity to others…
One interesting challenge I faced recently with MVVM was how to achieve two way binding of the selected values of a ListBox to a collection in a view model. I would like to share an approach to solving this challenge using Styles and Databinding.
It’s easy to bind the values of a collection in a view model to a list, but the challenge is that you want the view model to be aware of user selections in the list without having to use traditional events an code behind.
You also want to be able to change the selected items in the view model and have those changes reflected in the UI. In my sample code (below) this is demonstrated by the “Select All” checkbox, which modifies the select items in the view model.
The key to this approach is that entities in the collection you are binding to have to have a boolean “IsSelected” property (you can name it whatever you like). And then you create a Style to bind the IsSelected property of the ListBoxItem to the IsSelected property of the bound entity. See the XAML sample code below:
<ListBox ItemsSource="{Binding PersonCollection}"
SelectionMode="Multiple" >
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
<DataTemplate DataType="{x:Type MultiSelectMvvm:Person}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Name}"/>
<Label Content="{Binding IsSelected}"/>
</StackPanel>
</DataTemplate>
</ListBox.Resources>
</ListBox>
<CheckBox IsChecked="{Binding SelectAll}" Margin="3">
Select All
</CheckBox>
Here is the ViewModel code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
namespace MultiSelectMvvm
{
public class Window1ViewModel
{
ObservableCollection<Person> personCollection;
public ObservableCollection<Person> PersonCollection
{
get
{
if (personCollection == null)
{
personCollection = new ObservableCollection<Person>();
}
return personCollection;
}
set { personCollection = value; }
}
private bool selectAll;
public bool SelectAll
{
get
{
return selectAll;
}
set
{
selectAll = !selectAll;
foreach (var person in personCollection)
{
person.IsSelected = selectAll;
}
}
}
}
public class Person : INotifyPropertyChanged
{
public string Name
{
get;
set;
}
private bool? isSelected;
public bool? IsSelected
{
get
{
return isSelected;
}
set
{
isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}
FYI: Marlon over at C# Disciples wrote a recent blog post about this: Sync Multi Select Listbox with ViewModel. His approach uses Attached Properties.
Tuesday, June 9, 2009
Microsoft paying to advertise Bing on Google?!?!
It has got to cause some serious pain at Microsoft to pay this bill. Did they use Steve Balmer's credit card to setup the Adwords account?
Who is the person at Google that signed off on this? It takes some balls to happily place ads for your competition on your own site.
Thursday, April 9, 2009
Silverlight 3 plus OS X plus Firefox = bad juju?
Key point: the website says I have the latest version of Silverlight installed, but I'm getting a message box that says my version of Silverlight has "expired"... not very helpful...
UPDATE: The problem site I am trying to access is: http://blogs.msdn.com/silverlightws/archive/2009/04/08/using-wcf-services-from-silverlight-in-azure.aspx
UPDATE #2: Manually installing the Silverlight 3 Beta did solve the problem (the error message was still incredibly unhelpful...)
Tuesday, March 31, 2009
Double-clicking on a ListBox in MVVM
<ListBox Name="MyListBox">
TargetType="{x:Type ListBoxItem}">
Property="IsSelected"
Value="{Binding
Path=IsSelected, Mode=TwoWay}"/>
Property="acb:CommandBehavior.Event"
Value="MouseDoubleClick" />
Property="acb:CommandBehavior.Command"
Path=DataContext.MyDoubleClickCommand}" />
Property="acb:CommandBehavior.CommandParameter"
Value="{Binding}"
/>
</ListBox.Resources>
Key points to note:
- Setting the CommandParameter to "{Binding}" passes the item that is bound to this ListBoxItem as a parameter to the command we are calling (answering the question: "What item was double clicked?".
- Using a Style is a quick way to insert the stuff we want into each ListBoxItem.
- This example is also binding IsSelected so that we can determine the SelectedItem(s) from within the view model (this isn't required to make double click work... I just thought it was interesting to leave it in the code snippet since it took me a while to figure it out...)
Wednesday, February 25, 2009
Why is my WPF Popup black and how do I get it positioned properly?
Problem: I was trying to create a cool OS X style semi-transparent round cornered popup but no combination of setting Background=Transparent or Opacity<1 would give me anything but a big square cornered black box in the wrong part or the screen.
Solution: You need to set the AllowsTransparency property on the Popup to True, and set the PlacementTarget and Placement properties to control the position the Popup opens in.
<Popup x:Name="RecipeSourcePopup"
PlacementTarget="{Binding ElementName=MainStackPanel}"
Placement="Center" AllowsTransparency="True"
HorizontalAlignment="Center" VerticalAlignment="Center" >
Thursday, February 12, 2009
Email Management Tip: Automatically flagging sent email that requires a followup
How often do send an email that requires a response from somebody else, or that you want to followup on later? How often does the other person fail to reply? How often do you fail to remember to follow up?
So here's the tip: On any email that requires a followup, cc: it to YOURSELF and then create an Inbox rule in Outlook or filter in Gmail (I love Gmail) that saves the sent message to folder/label named "Followup Required".
Wala! An automagic task list!
And you can add tasks for yourself the same way... just email yourself a note... it doesn't have to be a reply.
And if you thought that was interesting you might like this old post on the rest of my email management strategy.
Wednesday, February 11, 2009
Great article on using: WCF in Silverlight 2
http://www.netfxharmonics.com/2008/11/Understanding-WCF-Services-in-Silverlight-2
Friday, February 6, 2009
Applying (and blocking) global styles in WPF/Silverlight
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--Default styles that will apply to any object of the specified type (if it doesn't have style set locally)-->
<Style TargetType="Button">
<Setter Property="FontSize" Value="11"/>
<Setter Property="FontWeight" Value="UltraBold"/>
<Setter Property="Button.Margin" Value="10,0,10,0" />
<Setter Property="Button.Padding" Value="3" />
<Setter Property="Button.Height" Value="25" />
<Setter Property="Button.MinWidth" Value="75" />
</Style>
<Style TargetType="Label" >
<Setter Property="Margin" Value="10,0,10,0" />
<Setter Property="FontSize" Value="11"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="MinWidth" Value="75"/>
</Style>
This is all great EXCEPT when you DON'T want your groovy new global styles to apply to a window or specific element on your page. In my specific case the global style for "Button" was totally hosing the display of the WPFToolkit DataGrid which is itself composed of lots of WPF Buttons.
The answer is to put an EMPTY Style into the Resources section of the page or control that you want to block the global style from applying to. Here is the DataGrid specific example:
<toolkit:DataGrid.Resources>
<!--The following line overrides (blocks) the global default styles
for "Button" from effecting the datagrid -->
<Style TargetType="Button" />
</toolkit:DataGrid.Resources>
You can do the same thing for the whole Window like this:
<Window.Resources>
<Style TargetType="Button" />
</Window.Resources>
Wednesday, February 4, 2009
Simple Asynch Demo in Silverlight
Thanks to MichealGG for the code. See his response to my question on StackOverflow here: http://stackoverflow.com/questions/508177/implementing-a-nested-asynch-call-stack-scenario-in-net
using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
namespace SilverlightTestApp
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
private void AsynchDemo()
{
ResultsTextBlock.Text = "";
ResponseWriteLine("BEGIN: AsynchDemo()");
AsyncHelp(
() => SlowDateTime("The time is now: "),
ex => ResultsTextBlock.Text += ex.ToString(),
bla => ResultsTextBlock.Text += bla.ToString()
);
ResponseWriteLine("CALLED: SlowDateTime()");
Action<string> r = ResponseWrite;
for(int x = 0;x<100;x++)
{
AsyncHelp(
() => RandomSleep(x),
ex => ResultsTextBlock.Text += ex.ToString(),
r); //use a delegate instead of a lambda expression
}
ResponseWriteLine("END: RandomSleep() x 100");
}
public string RandomSleep(int input)
{
Random r = new Random();
int t = r.Next(10000);
Thread.Sleep(t);
return input.ToString() + "."; ;
}
public void ResponseWrite<T>(T result)
{
ResultsTextBlock.Text += result.ToString();
}
public void ResponseWriteLine<T>(T result)
{
ResultsTextBlock.Text += result.ToString() + Environment.NewLine;
}
public string SlowDateTime(string text)
{
Thread.Sleep(5000);
return text + DateTimeOffset.Now.ToString();
}
public void AsyncHelp<T>(Func<T> f, Action<Exception> econt, Action<T> cont)
{
var t = new Thread((_) =>
{
try
{
var res = f();
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => cont(res));
}
catch (Exception ex)
{
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => econt(ex));
}
});
t.Start();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
AsynchDemo();
}
}
}
Tuesday, January 27, 2009
Windows 7 Beta plus Visual Studio Express Editions: Happiness!
To actually test it a little bit I decided I should use it for some real development, and so I installed the C# and Web versions of Visual Studio 2008 Express Edition and checked out a couple of existing projects from svn.
I'm impressed with both Windows 7 and the Visual Studio 2008 Express Editions (I had never actually tried to use them before)! Other than missing Resharper, I'm not sure that I really use that much functionality in Visual Studio 2008 Team Suite at all...
Best of all it seems really fast on a VM with only 1gb of ram!
Tuesday, January 20, 2009
Deleting 4,000 Gmail groups... (or: Repairing Soocial replication damage)
In reality it's a young beta application that launched a little too soon, and you should use it with extreme caution. I'm sure it's going to be great when they work the bugs out, but today it still has some "issues".
In my case it created over 4,000 groups in my Gmail account over the space of a couple days before I noticed. NOT a happy thing!
Gmail doesn't have any sort of bulk delete option, and deleting all 4,000 of them one at a time could have taken years... So I downloaded the Google API and wrote a little .NET application to do it for me. Nerd overkill, but it was a good excuse to learn something about the Google API.
If you have this problem too you can download my application here:
http://scrappydog.com/GoogleGroupCleanup/publish.htm
Note: This is a very simple brute force application. It will delete ALL your email groups (no way to keep the 10 you REALLY care about).
You can read more about the issue here on their support site:
http://getsatisfaction.com/soocial/topics/synchronization_creates_duplicate_groups
UPDATE: Soocial is currently offline. I get prompted for a password when I try to access their site... I would guess the are busy fixing bugs... :-)
UPDATE2: This tool still gets a surprising number of downloads, and today "Ben" asked if I would share the source code. No problem. Here is the link: http://blog.scrappydog.com/2010/02/souce-code-for-deleting-googlegmail.html
Friday, January 16, 2009
"Failed to copy file" Error when publishing VS2008 application via FTP
Simple right? Wrong! I'm trying to publish via FTP and getting the following error:
Failed to copy file 'C:\Projects\scrappydog_projects\Google\libgoogle-data-mono-1.3.1.0\src\GoogleGroupCleanup\bin\Debug\app.publish\Application Files\GoogleGroupCleanup_1_0_0_0\Google.GData.Client.dll.deploy' to 'ftp://scrappydog.com/GoogleGroupCleanup/Application Files/GoogleGroupCleanup_1_0_0_0/Google.GData.Client.dll.deploy'. Unable to add 'Application Files/GoogleGroupCleanup_1_0_0_0/Google.GData.Client.dll.deploy' to the Web site. Could not find a Web server at 'scrappydog.com' on port 21. Please check to make sure that the Web server name is valid and your proxy settings are set correctly. If you are sure that everything is correct, the Web server may be temporarily out of service.
I can watch the files being created on the server with a ftp client, and so I know it's connecting, but somewhere at the end of the process something else fails, and rolls back the whole process and deletes the files... aargh...
I've found lots of references to the same problem, but no solutions... anyone? anyone?
UPDATE: This issue seems like it may be firewall related. Publishing the same project from a different computer on a different network works fine...