Showing posts with label Silverlight. Show all posts
Showing posts with label Silverlight. Show all posts

Saturday, February 5, 2011

Working with threads in silverlight

Lets say that we have a silverlight application that gets updates from an outer service every X seconds. the application calls the service every X seconds and waits for the answer(async-way of course).

The most trivial way is to use a timer that every X seconds the Tick event will raise and call our service.

In order to do so we have got the System.Threading.Timer to use. the code will look like that:

       public MainPage()
       {
           InitializeComponent();

           var timer = new Timer(TimerTick, null, new TimeSpan(0, 0, 0, 1), new TimeSpan(0, 0, 0, 5));
       }

       private void TimerTick(object state)
       {
           var client = GetClient();
           client.GetUpdatesComplete += GetUpdate_OnComplete;

           client.GetUpdates();
       }

       private void GetUpdate_OnComplete(object sender, GetUpdatesCompleteEventArgs e)
       {
           if (e.Error == null)
           {
               MyTextBox.Text = "Hello world! the time is " + DateTime.Now;
           }
           else
           {
               MyTextBox.Text = "Error!";
           }

       }

But when we will run the code we will get an error:

"Cross-thread operation not valid: Control 'MyTextBox' accessed from a thread other than the thread it was created on."

The meaning of this error is that we are trying the access the UI from other thread rather than the UI thread. and in silverlight, this is not possible.

So what we do?? we use the method Dispatcher.BeginInvoke() that will change the property via the UI thread. the code will look like this:

        private void GetUpdate_OnComplete(object sender, GetUpdatesCompleteEventArgs e)
        {
            if (e.Error == null)
            {
                Dispatcher.BeginInvoke(() => MyTextBox.Text = "Hello world! the time is " + DateTime.Now);
            }
            else
            {
                ispatcher.BeginInvoke(() => MyTextBox.Text = "Error!");
            }

        }

This is all nice and pretty but there might be a problem. this thread will run no matter what is the state of the UI. even if the UI is stuck, because it runs from another thread….

If we want to use timer that will run on the UI thread we can use DispatcherTimer , and we won't have to call the Dispatcher.BeginInvoke().

Did you got confused?? lets summarize:

1) If you need to use threads that should run each X seconds, no matter what the UI state is, and don't want it to effect the UI – use Timer and Dispatcher.BeginInvoke().

2) If you want that your timer will not run while the UI is stuck or have al long processing to do – use DispatcherTimer.

Friday, January 21, 2011

Silverlight control template–Part II

As I promised in my last post I will show you how to change the visual appearance of controls that are not content control.

For this explanation I will create round text box.

I will start from the end and show you the complete result:

image

And the style code:

<Style x:Key="TextBoxStyle" TargetType="TextBox">
          <Setter Property="Template">
              <Setter.Value>
                  <ControlTemplate TargetType="TextBox">
                      <Grid x:Name="RootElement">
                          <Border x:Name="Border" BorderThickness="{TemplateBinding BorderThickness}" 
                                  CornerRadius="15" BorderBrush="Black" >
                              <ScrollViewer Height="Auto" 
                                                    x:Name="ContentElement" Width="100"
                                                    BorderThickness="0" 
                                                    IsTabStop="False" 
                                                    Padding="{TemplateBinding Padding}" 
                                                    Margin="5"/>
                          </Border>
                      </Grid>
                  </ControlTemplate>
              </Setter.Value>
          </Setter>
</Style>

At first, it's look exactly the same as the example of the round button. but the big difference is in the bolded text. because text box does not have a content we cannot use content presenter to holds it's content. but every textbox has the place where you can write things, and you need some way to present it in your template!

In my case, The ScrollViewer comes to help. and why? because in the textbox defenition it defines "place holder" for the text area, in order for us to be able replace it with another control. so I defined a ScrollViewer and gave it the name of the part "ContentElement".

What? Where? How?

From msdn:

[TemplatePartAttribute(Name = "ContentElement", Type = typeof(FrameworkElement))]
[TemplateVisualStateAttribute(Name = "InvalidUnfocused", GroupName = "ValidationStates")]
[TemplateVisualStateAttribute(Name = "InvalidFocused", GroupName = "ValidationStates")]
[TemplateVisualStateAttribute(Name = "ReadOnly", GroupName = "CommonStates")]
[TemplateVisualStateAttribute(Name = "Normal", GroupName = "CommonStates")]
[TemplateVisualStateAttribute(Name = "Disabled", GroupName = "CommonStates")]
[TemplateVisualStateAttribute(Name = "Unfocused", GroupName = "FocusStates")]
[TemplateVisualStateAttribute(Name = "Valid", GroupName = "ValidationStates")]
[TemplateVisualStateAttribute(Name = "MouseOver", GroupName = "CommonStates")]
[TemplateVisualStateAttribute(Name = "Focused", GroupName = "FocusStates")]
public class TextBox : Control

The control defines TemplatePart that can be any FrameworkElement and by defining this part it will behave as text holder for the text box. (p.s the state the you see are the visual state that you can define to the control)

Here is the same code with button as ContentElement part of the textbox:

(The text is not the content of the button! you can write whatever you like in runtime)

image

All silverlight controls defines parts that helps you change the control's appearance without loosing it's behivor! all you need to do is go to the control definition is msdn – and start desigining your controls!

Silverlight rocks!!

Saturday, December 18, 2010

Silverlight Control template for content controls

One of the strongest things about silverlight is that it gives you the complete control over your application visual appearance.

Unlike win-forms controls or asp.net controls, the look of the control and it's behavior are two different things.

For example, a button is Clickable but it doesn't have to look like a button, it can be a bunch of circles or whatever you like.

So how you change the control appearance?

It depends on what you want to do… let's say we want to create a round Button.

We can try to create a Border element around it, like this:

 <Border BorderThickness="5" CornerRadius="15" BorderBrush="Black">
            <Button Content="Click me!" />
 </Border>

Now we have a round border around our button, but it's still a regular button:

image

So we have to get into the actual control and change it's complete appearance , and how? by changing the control's template.

The control template defines the visual-tree of the control.

In order to create our round button I created a style that defines the visual tree of the button as an ellipse.

 <Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
                        <Ellipse  Opacity="0.8">
                            <Ellipse.Fill>
                                <SolidColorBrush x:Name="Brush" Color="LightGreen"/>
                            </Ellipse.Fill>
                        </Ellipse>
                        <ContentPresenter Margin="{TemplateBinding Padding}" VerticalAlignment="Center"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
</Style>

So what did I do here?

I've changes the button to be a grid that has an ellipse and something to holds it's content (Content presenter) on top of the ellipse.

When someone that use's this template define a content for the button(it can be some text,another control etc..), the content will be presented on the ellipse.

The button with text content:

image

The button with 2 ellipses as a content:

image

Note: this is still a button! when you click on it, it fires the "Click" event!

Another important thing to mention is that when you create your own template for the control, you actually run-over the default template, and by doing so, loses some things like the management of visual states of the control, which means you need to create them yourself (like I did in this post).

The code with the visual states(simple mouse-over) will look like this:

<Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="Brush"    
                                                        Storyboard.TargetProperty="Color" Duration="0:0:0"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="Brush" 
                                                                    Storyboard.TargetProperty="Color"
                                                                    To="Pink"  Duration="0:0:0"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Ellipse  Opacity="0.8">
                            <Ellipse.Fill>
                                <SolidColorBrush x:Name="Brush" Color="LightGreen"/>
                            </Ellipse.Fill>
                        </Ellipse>
                        <ContentPresenter Margin="{TemplateBinding Padding}" VerticalAlignment="Center"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
</Style>

Last thing, this post is for content controls, and why is that? because we use Content Presenter as a placeholder for the content.

But what if it's a TextBox that does not have content? well,this is for the next post… סמיילי

Saturday, November 13, 2010

"Selected button" with visual state in silverlight

Lately, I start using silverlight to create some pages in my asp application.

I needed to create a toolbar that had some buttons for different operations for users to use, and to make their experience better I wanted to mark the selected tool in some way.

My first thought was to create "click" events to all my tools buttons and write something like this:

private void MyToolAButton_Click(object sender, RoutedEventArgs e)
{
       UnClickedTool(ToolB);
       UnClickedTool(ToolC);
       ClickedTool(ToolA)
}
……
private void UnClickedTool(Button tool)
{
       //Set unclicked visual appearance
}

private void ClickedTool(Button tool)
{
       //Set clicked visual appearance
}

This solution will work but it felt a bit outdated for silverlight.

Then I remembered hearing stuff about silverlight VisualStateManager that helps you define the visualization for each of the states in your control(such as mouseOver,Focused etc..), and all in simple xaml code!

For example, here is some code to change the color of the button(from red to orange) when mouseOver:

<Button x:Name="ButtonA">
            <Button.Template>
                <ControlTemplate TargetType="Button">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="ButtonSolidBrush"
                                                        Storyboard.TargetProperty="Color"
                                                        To="Orange" Duration="0" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Normal"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="ButtonBorder" >
                            <Border.Background>
                                <SolidColorBrush x:Name="ButtonSolidBrush" Color="Red"/>
                            </Border.Background>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Button.Template>
</Button>

But I wanted to change the color when the button is selected! so at first, I configured the "Pressed" state of the button. but the problem is that when your mouse leaves the button, the state is changed back to "normal" (and return to the old color) because "Pressed" state is when you actually press the button.

The solution for this is simple – use ToggleButton.

What is ToggleButton?

ToggleButton is the base class of checkbox and radiobutton, which means that it's a button with checked and unchecked states.

The state of the control is determined by the IsChecked property.

By replacing my Button control with ToggleButton I was able to achieve my goal!

I've created a control template with "checked" and "unchecked" visual configuration:

 <ControlTemplate TargetType="ToggleButton" x:Name="ToggleTemplate">
            <Grid>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Checked">
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetName="ButtonSolidBrush"
                                                        Storyboard.TargetProperty="Color"
                                                        To="Orange" Duration="0" />
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Unchecked">
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetName="ButtonSolidBrush"
                                                        Storyboard.TargetProperty="Color"
                                                        To="Blue" Duration="0" />
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <Border x:Name="ButtonBorder" BorderBrush="Coral">
                    <Border.Background>
                        <SolidColorBrush x:Name="ButtonSolidBrush" Color="Red"/>
                    </Border.Background>
                </Border>
           </Grid>
</ControlTemplate>

Created 2 togglebuttons with this template:

<ToggleButton x:Name="MyButton" Grid.Row="1" Content="Click me.." Checked="MyButton_Checked"  Template="{StaticResource ToggleTemplate}" IsThreeState="False"/>
<ToggleButton x:Name="MyButton2" Grid.Row="2" Content="Click me2.." Checked="MyButton2_Checked"  Template="{StaticResource ToggleTemplate}" IsThreeState="False"/>

*The "IsThreeState" property determine if we had "indeterminate" state or just "checked" and "unchecked" states.

And implemented the events(when checking one button,the other is unchecked):

private void MyButton_Checked(object sender, RoutedEventArgs e)
{
     MyButton2.IsChecked = false;
}

private void MyButton2_Checked(object sender, RoutedEventArgs e)
{
     MyButton.IsChecked = false;
}

You can see that I still had to implement sort of "ClickedTool" and "UnClickedTool" in my events. so what's the difference??

Well, the big difference is that I don't use any visual definition in my code behind! I've just changed the states of the controls and that's it! all the visual definitions is in the xaml,so I can change them without changing any code! so if tomorrow I get new control template I just need to change the "Template" properties of my buttons and that's it!

Saturday, October 16, 2010

Problems with Wcf RIA services installation(or uninstallation)

Yesterday i installed the full version of vs2010 on my laptop(i had vs2010 express so far) and remove the vs2008.

All well, till i tried to create a silverlight application with Ria service.

First,when creating the Silverlight Application project i didn't have the "enable WCF Ria services" checkbox. that turned a red light, but i kept going… then i tried to add a Domain service to the web application but i couldn't! it wasn't in the list of items to add..

So i tried to uninstall and install the silverlight tools,toolkit and sdk about a 1000 times – didn't help! there was a time that i did get the "enable WCF Ria services" checkbox but it was disabled.

Then,i found a post somewhere that talked about old vs2008 installation of Ria services that should be uninstalled,so i looked in the control panel and searched for the installation of WCF Ria services, but trying to uninstall it led to nothing. it was still there no matter what i tried to do…

At the end, after heavy search on google i found the solution! removing some keys from the registry and the problem solved! (i had to install all silverlight stuff again and that's it).

The solution is described in here:

http://forums.silverlight.net/forums/t/149912.aspx

Good luck…