Yesterday I had the strangest XAML behaviour ever ... I have to share this!
The issue
In a Windows Phone app I have this object tree in my ApplicationPage, where each View contains a ScrollViewer with simple Grid content - nothing special.
<Grid x:Name="LayoutRoot">
<controls:Pivot Title="{Binding PageTitle}">
<controls:PivotItem Header="Page 1">
<Grid>
<Views:ItemOneView DataContext="{Binding Data}"/>
</Grid>
</controls:PivotItem>
<controls:PivotItem Header="Page 2">
<Grid>
<Views:ItemTwoView DataContext="{Binding Data}"/>
</Grid>
</controls:PivotItem>
<controls:PivotItem Header="Page 3">
<Grid>
<Views:ItemThreeView DataContext="{Binding Data}"/>
</Grid>
</controls:PivotItem>
</controls:Pivot>
</Grid>
The issue was, that the runtime didn't allow me to scroll down to hidden content of ItemTwoView. The scrollbar didn't come up and altough I saw the content while scrolling, it moved back to the original position when I stopped.
The fix
After hours of debugging, I just rewrote the 5 lines from <controls:PivotItem Header="Page 2"> to </controls:PivotItem> exactly 1:1. And it worked!
I really didn't believe it ... so I pushed undo and had the behavior again, although the code didn't change. Hidden characters? Encoding issue? Bug? Don't know.
In a Windows Phone 7 project I recently needed a function that does the work of System.Drawing.ColorTranslator.FromHtml(string color). Therefore I wrote this little extension method.
It deals with RGB and ARGB input values, with or without the leading hash.
public static Color FromHtml(this string s)
{
// Check fore a valid code (RGB = 6 chars, ARGB = 8 chars)
var regex = new Regex(@"^[A-Fa-f0-9]*$");
if (s == null || ((s = s.Trim().TrimStart('#')).Length != 6 && s.Length != 8) || !regex.IsMatch(s))
return Colors.White;
int index = 0;
// If the color length is 8, the first 2 chars contain the alpha part
byte a = 255;
if (s.Length == 8)
{
a = Convert.ToByte(s.Substring(0, 2), 16);
index += 2;
}
// Get R value
byte r = Convert.ToByte(s.Substring(index, 2), 16);
index += 2;
// Get G value
byte g = Convert.ToByte(s.Substring(index, 2), 16);
index += 2;
// Get B value
byte b = Convert.ToByte(s.Substring(index, 2), 16);
return Color.FromArgb(a, r, g, b);
}
Usage:
var color1 = "#CC3333".FromHtml();
var color2 = "CC3333".FromHtml();
var color3 = "#FFCC3333".FromHtml();
Finding a way back from LINQ to SQL cuncurrency hell.
Yesterday I was trapped in concurrency hell and had no idea why.
Background
The Windows Phone App I am currently working on, synchronizes data between a local database and a REST service. When the app receives an update for a row, I select the row to be updated from the local database via LinqToSql, update its values with the data from the service and save it.
The issue
As you can see in the snippet below, I select a record, update it ... and a few lines later the update crashes with a lovely System.Data.Linq.ChangeConflictException saying "Row not found or changed". How is that possible? I'm sure that nobody modifies or deletes the data in the meantime.
private void updatePerson(Person person)
{
var localPerson = DataStore.Data.Persons.Where(p => p.Id == person.Id);
if(localPerson == null)
{
//person is new, so create it
DataStore.Data.Persons.InsertOnSubmit(person);
}
else
{
//update existing person
localPerson.Name = person.Name;
localPerson.CustomerId = person.CustomerId;
localPerson.DepartmentId = person.DepartmentId;
localPerson.IsActive = person.IsActive;
}
DataStore.Data.SubmitChanges(); //crash boom bang --> Row not found or changed.
}
Aha! LINQ to SQL uses Optimistic Concurrency
Hahaaa, that's it! When LINQ to SQL selects a record, it does not lock any data. When it is updating a record, it compares all columns with their original values.
So what does this mean? The update query that I expected from LINQ to SQL was:
UPDATE Persons
SET Name = 'Mr. Buggy',
CustomerId = null,
DepartmentId = 6,
IsActive = true
WHERE
Id = 9999
But the real world is different; due to optimistic concurrency it compared all columns:
UPDATE Persons
SET Name = 'Mr. Buggy',
CustomerId = null,
DepartmentId = 6,
IsActive = true
WHERE
Id = 9999 AND
Name = 'Mr. Buggy' AND
CustomerId = 1234 AND
DepartmentId = 1 AND
IsActive = true
This still does neither explain nor solve my issue, since my original values did not change in the meantime. But with the knowledge of Optimistic Concurrency and a few more minutes of debugging, I found (my) fault: The database field for CustomerId is not nullable ... but the REST Service returned null.
I fixed this and everyone (that's me) is happy!
Recently I've done some optimizations for mobile websites where I focused on the default viewport size of common mobile browsers.
Here's the list of the default viewport width I used:
Windows Phone 7 IE: 1024px
Android: 800px
iPhone Safari: 980px
Opera Mobile: 850px