It took a short while to figure that using the “mbox” snippet won’t work (actually because the message box is not in “Forms”). The resulting line of code is:
System.Windows.MessageBox.Show("XXX");
It can be used with caption and buttons parameters, but that’s for a later usage (maybe).
Next step run the project. It appears that the “run-time” environment for debugging is not installed automatically with the SDK, god help M$... Another download, a quick installation and it was over.
Page loads. Page is shown, button is shown, label is gone. Huh???
I repeated the process with different styling, to no result.
Once I added the setting of its content to the “Loaded” of either Layout or the label itself it worked:
private void label1_Loaded(object sender, RoutedEventArgs e)
{
label1.Content = "ZZZ";
}
There was no need to do any styling, just insert the content.
Next, let’s have some fun. Adding a label to the form on the click, assign a function that moves it around on mouse enter.
private void button1_Click(object sender, RoutedEventArgs e)
{
Label x = new Label();
x.Content = "XXXX";
x.FontSize = 30;
x.VerticalAlignment = System.Windows.VerticalAlignment.Top;
x.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
x.Foreground = new SolidColorBrush(Color.FromArgb(255, 235, 24, 24));
x.Margin = new Thickness(30, 40, 0, 0);
x.MouseEnter += new MouseEventHandler(x_MouseEnter);
LayoutRoot.Children.Add(x);
}
And the events function
void x_MouseEnter(object sender, MouseEventArgs e)
{
if (sender is Label)
{
Label x = ((Label)sender);
double left = x.Margin.Left;
double top = x.Margin.Top;
if (left < 245)
{
left += 10;
} else {
left = 0;
}
top += 10;
x.Margin = new Thickness(left, top, x.Margin.Right, x.Margin.Bottom);
x.Foreground = new SolidColorBrush(Color.FromArgb(255, System.Convert.ToByte(left), 24, 24));
}
}
Nice and easy. Next step put a grid, and fill it with data from an SQL server table.
Hmmmm… That’s not possible directly in Silverlight.
Datagrid component exists in the toolbox. The problem is with the binding. So I used a WCF as data delegate:
private void button1_Click(object sender, RoutedEventArgs e)
{
label1.Content = "Loading...";
svc.GetAccountsCompleted += new
EventHandler
svc.GetAccountsAsync();
}
Note: the call is Asynchronous. There’s no synchronous method for Silverlight WCF.
And the “Completed” method:
void svc_GetAccountsCompleted(object sender, ServiceReference1.GetAccountsCompletedEventArgs e)
{
label1.Content = "Done";
dataGrid1.ItemsSource = e.Result;
}
The WCF (declared on the supporting site) has:
[OperationContract]
public System.Collections.Generic.List
{
DataClasses1DataContext db = new DataClasses1DataContext();
System.Collections.Generic.List
var tbl = from x in db.TBL_ACCOUNTs where !x.isDeleted select x;
foreach (TBL_ACCOUNT item in tbl.Take(100))
{
res.Add(new AccountClass(item.accountID, item.accountName));
}
return res;
}
public class AccountClass
{
public int AccountID { get; set; }
public string AccountName { get; set; }
public AccountClass(int ID, string Name)
{
AccountID = ID;
AccountName = Name;
}
}
I used LINQ in order to live the DB without junk procedures. For real life DON’T USE IT! It’s by far slower and as might be understood from the code – resource waster.
Last test was multi-threading. Update 3 labels from 3 different threads, non of them is the main thread.
My first version was something like this:
private void button2_Click(object sender, RoutedEventArgs e)
{
System.Threading.Thread th = new System.Threading.Thread(DoThread);
th.Start(new object[] { label1 });
th = new System.Threading.Thread(DoThread);
th.Start(new object[] { label2 });
th = new System.Threading.Thread(DoThread);
th.Start(new object[] { label3 });
}
public void DoThread(object bag)
{
int count = 0;
object[] real_bag = (object[])bag;
Label lbl = (Label)real_bag[0];
while (true)
{
count++;
lbl.Content = count.ToString();
System.Threading.Thread.Sleep(1000);
}
}
It didn’t work (actually I was surprised it compiled…) with a very good reason it’s not thread-safe to manipulate the UI from inside a thread. The problem was that it just terminated the thread without any notice. Thread is alive, poof, no thread exists.
After digging a bit, and adding some beatification the result is:
private static Random r = new Random();
private bool _done = true;
private void button2_Click(object sender, RoutedEventArgs e)
{
if (!_done)
{
_done = true;
}
else
{
StartThreads();
}
}
private void StartThreads()
{
_done = false;
System.Threading.Thread th = new System.Threading.Thread(DoThread);
th.Start(new object[] { label1 });
th = new System.Threading.Thread(DoThread);
th.Start(new object[] { label2 });
th = new System.Threading.Thread(DoThread);
th.Start(new object[] { label3 });
}
public void DoThread(object bag)
{
int count = 0;
object[] real_bag = (object[])bag;
Label lbl = (Label)real_bag[0];
while (!_done)
{
count++;
LayoutRoot.Dispatcher.BeginInvoke(delegate()
{
lbl.Content = count.ToString();
});
System.Threading.Thread.Sleep(r.Next(1000));
}
}
Actually the most important thing in here is the LayoutRoot.Dispatcher.BeginInvoke. That’s the magic command that tells the CLI: use the main thread.
No comments:
Post a Comment