Guardian’s Home

.NET, Software Developing, Mammuths and various Life Things…

Archive for the ‘xaml’ tag

XAML Power Toys and Mole

without comments

Reading Tim Heuer’s Blog I discovered these two very nice tools written by Karl Shifflett. They are a very nice XAML code generator to build basic business form in WPF and Silverlight, and a tool that provides a series of advanced Visualizers that interact with Visual Studio 2008 (excerpt from mole documentation: Mole was designed [...]



kick it on DotNetKicks.com

Written by Guardian

October 9th, 2008 at 3:47 am

Posted in Silverlight, Tips, WPF

Tagged with ,

Silverlight: Dropdown Menu Control

with 10 comments

In a previous post I showed how we can build a simple menu control for Silverlight 2 Beta 2 (Silverlight: how to build a simple menu control); then with the release of Silverlight RC0 some things were changed and the menu stopped working, due to how events are handled for disabled controls (Silverlight 2 RC0 [...]



kick it on DotNetKicks.com

Written by Guardian

October 7th, 2008 at 8:24 am

Silverlight: how to build a simple Menu Control

with one comment

public void AddSubmenu(SubMenu sm) { if (p == null) { p = new System.Windows.Controls.Primitives.Popup(); pnl = new StackPanel(); p.Child = pnl; MenuLayout.Children.Add(p); } pnl.Children.Add(sm); sm.ParentMenu = this; EnablePopupProvider(); }

 

Menu and SubMenu items have a ParentMenu property to trace who’s his parent cause when you click on a SubMenu you have to close the popup which is holded by it’s parent control; the first attempt to identify a parent menu of a submenu was made by using a while cycle looking at the ‘Parent’ propery of each control that is the visualization tree until we found a ‘Menu’ or ‘SubMenu’ control, so for a Level 1 SubMenu the sequence could have been something like this:

MenuButton –> Grid –> StackPanel –> Popup –> Menu Control

but it came out that the parent property of a StackPanel inside a Popup control returned null..so we were forced to add a ParentMenu property and populate it on the Add() and Remove() functions.

The last thing to note was a ‘Bug’ in the state management of the control, when you use a menu you usually open it up by clicking on the menu voice which will open the popup, then you select a subitem hovering on it with the mouse (the control changes its state to ‘mouseover’) then you click on it (‘pressed’ state); at this point, on the internal button click event 2 things happens: the subitem ask it’s parent to close the menu popup and a MenuClick event is raised for the application to handle it.

But the popup closes itself when the mouse is STILL over the submenu item and the internal control will retain its ‘mouseover’ status (the menu is highlighted) and when you open the popup again you get the last item you clicked on still highlighted.

The solution is to ask the VisualStateManager to change the state of each control to ‘Normal’ each time the popup is shown, so we add the call on the Loaded event (which is called every time we open the popup) of the SubItem control, here’s the code:

void SubMenu_Loaded(object sender, RoutedEventArgs e) { //force the visualization to switch to the normal state to avoid the //hovering bug: the control is in the hover state when we ask to close //the popup that contains it, if we do not change the state manually //it will retain the 'mouse hover' status if (IsEnabled) VisualStateManager.GoToState(MenuButton, "Normal", true); }

 

In the end, let’s have a look at how you can use it:

//Dynamically buildup a menu Menu m1 = new Menu("Test1"); m1.AddSubmenu(new SubMenu("Sub1")); m1.AddSubmenu(new SubMenu("Long Sub1 string")); SubMenu sb1 = new SubMenu("Disabled Sub1"); sb1.IsEnabled = false; m1.AddSubmenu(sb1); sb1 = new SubMenu("Click Me! Sub1"); sb1.MenuClick += new MenuClickEventHandler(sb1_MenuClick); m1.AddSubmenu(sb1); Menu.AddMenu(m1); Menu m2 = new Menu("Disabled Test2"); m2.IsEnabled = false; m2.AddSubmenu(new SubMenu("Sub2")); m2.AddSubmenu(new SubMenu("Sub2")); m2.AddSubmenu(new SubMenu("Sub2")); Menu.AddMenu(m2); Menu m3 = new Menu("Test3"); m3.AddSubmenu(new SubMenu("Sub3")); m3.AddSubmenu(new SubMenu("Sub3")); SubMenu sb3 =new SubMenu("Sub3"); m3.AddSubmenu(sb3); Menu.AddMenu(m3);

This is only the first version of this control, and there’s room for LOTS of improvements (like adding a child menu to each submenu; and a better templating system), but nonetheless it’s a good starting point for your own menu control.

Example Solution:

SilverlightMenu.zip

Technorati Tags: ,,,,

-->

In my current project I needed to use a dynamic Menu Control (a completely declarative approach hardcoding the structure in XAML wasn’t a good fit for my application cause I need to dynamically add, remove, enable and disable menu items). Since Silverlight doesn’t support a menu control yet I had 3 options:
1- look for a [...]



kick it on DotNetKicks.com

Written by Guardian

September 25th, 2008 at 6:33 am

Posted in Silverlight

Tagged with , , , ,

Silverlight: Custom Buttons with Templates

without comments

<RadialGradientBrush x:Name="RedRadialBrush" GradientOrigin="0.2,0.2" > <GradientStop Color="#FFFFFFFF"/> <GradientStop Color="Red" Offset="1"/> </RadialGradientBrush> <Style x:Key="RoundTextButton" TargetType="Button"> <Setter Property="Background" Value="{StaticResource GrayRadialBrush}" /> <Setter Property="Width" Value="30" /> <Setter Property="Height" Value="30" /> <Setter Property="FontSize" Value="10" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"> <vsm:VisualStateManager.VisualStateGroups> <vsm:VisualStateGroup x:Name="FocusStates"> <vsm:VisualState x:Name="Unfocused"/> ... </Style>

and you can instantiate some on a page like this:

<Grid x:Name="LayoutRoot" Background="White"> <StackPanel> <StackPanel Orientation="Horizontal"> <Button Content="Edit1" Style="{StaticResource RoundTextButton}" /> <Button Content="Edit2" Style="{StaticResource RoundTextButton}" Background="{StaticResource YellowRadialBrush}" /> <Button Content="Edit3" Style="{StaticResource RoundTextButton}" Background="{StaticResource GreenRadialBrush}" /> <Button Content="Edit4" Style="{StaticResource RoundTextButton}" Background="{StaticResource RedRadialBrush}" /> </StackPanel> ... </StackPanel> </Grid>

 

The code above produce this:

CustomButtons1

4 small round buttons with animations when your mause move over them or when you press them.

What we see here is that the xaml code of the page looks a little bloated and not very well readable, plus changing a single resource as the background color of the buttons in code is a little messy cause you have to create a new brush consistent with the previous ones.

What we can do is define our own Button control (which inherits from Button), define the properties we want to access directly (as dependancy properties to support binding and templating) and then move the master template in the Generic.xaml file. The button class is straightforward and doesn’t need many comments:

public class CustomButton : Button, INotifyPropertyChanged { public CustomButton() : base() { this.DefaultStyleKey = typeof(CustomButton); } public override void OnApplyTemplate() { base.OnApplyTemplate(); GradientStop gs = GetTemplateChild("EllipseBackGroundColor") as GradientStop; if (gs != null) gs.Color = BackgroundColor; } #region BackgroundColor /// <summary> /// Gets or sets the BackgroundColor possible Value of the Color object. /// </summary> public Color BackgroundColor { get { return (Color)GetValue(BackgroundColorProperty); } set { SetValue(BackgroundColorProperty, value); } } /// <summary> /// Identifies the BackgroundColor dependency property. /// </summary> public static readonly DependencyProperty BackgroundColorProperty = DependencyProperty.Register( "BackgroundColor", typeof(Color), typeof(CustomButton), new PropertyMetadata(OnBackgroundColorPropertyChanged)); /// <summary> /// BackgroundColorProperty property changed handler. /// </summary> /// <param name="d">CustomButton that changed its BackgroundColor.</param> /// <param name="e">DependencyPropertyChangedEventArgs.</param> private static void OnBackgroundColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { CustomButton _CustomButton = d as CustomButton; if (_CustomButton != null) { OnPropertyChanged(_CustomButton, "BackgroundColor"); } } #endregion BackgroundColor #region INotifyPropertyChanged Members }

The DefaultStyleKey propery setted in the constructor tells what is the default style to load from the Generic.xaml file.

The interesting thing happens in the OnApplyTemplate() functions; here since we cannot use TemplateBinding to change the color of the GradientStop used in the RadialBrush that defines the background color of the button, we have to access to the element in code and change its value ‘at runtime’.

I modified my xaml like this:

<Grid x:Name="LayoutRoot" Background="White"> <StackPanel> <StackPanel Orientation="Horizontal"> <Button Content="Edit1" Style="{StaticResource RoundTextButton}" /> <Button Content="Edit2" Style="{StaticResource RoundTextButton}" Background="{StaticResource YellowRadialBrush}" /> <Button Content="Edit3" Style="{StaticResource RoundTextButton}" Background="{StaticResource GreenRadialBrush}" /> <Button Content="Edit4" Style="{StaticResource RoundTextButton}" Background="{StaticResource RedRadialBrush}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <ctrl:CustomButton Content="Edit1" /> <ctrl:CustomButton Content="Edit1" BackgroundColor="Yellow" /> <ctrl:CustomButton Content="Edit1" BackgroundColor="Green" /> <ctrl:CustomButton Content="Edit1" BackgroundColor="Red" /> </StackPanel> </StackPanel> </Grid>

But this isnt enough yet since the first time I run the code I saw that the buttons weren’t working well:

CustomButtons2

The 4 buttons were rendered circular but their color was not right and the animation didnt worked too…it tooks me a while (and the help of SilverlightDefaultStyleBrowser) to realize that by default every control is created in a DISABLED state and that you have to enable it (in the xaml style or in code).

<Style TargetType="ctrl:CustomButton"> <!-- key lines to enable the control --> <Setter Property="IsEnabled" Value="true" /> <Setter Property="IsTabStop" Value="true" /> ...

After placing the right lines in the default style in Generic.xaml it all finally worked and you can now have your buttons working with a more compact and readable xaml.

Example Solution:

CustomButtons.zip

Technorati Tag: ,,
-->

Sometimes you want to define a consistent look for all you application and maybe you completely replace the template of a control (lets say…a button :D), then you want to use the same template with small variations (colors or images for example).
Lets say we have realized the usual round button with a gradient background and [...]



kick it on DotNetKicks.com

Written by Guardian

September 1st, 2008 at 6:12 am

Posted in Silverlight

Tagged with , , ,

Silverlight: simulate a ‘Windows’ desktop application - part 1

with 6 comments

/// <summary> /// Gets called once the template is applied /// </summary> public override void OnApplyTemplate() { base.OnApplyTemplate(); window = GetTemplateChild("PART_Window") as Grid; captionBar = GetTemplateChild("PART_CaptionBar") as FrameworkElement; captionText = GetTemplateChild("PART_CaptionText") as TextBlock; captionText.Text = _Caption; Button closeButton = GetTemplateChild("PART_CloseButton") as Button; if (closeButton != null) closeButton.Click += new RoutedEventHandler(closeButton_Click); DefineDragEvents(); DefineResizeEvents(); Canvas.SetZIndex(this, currentZIndex); }

We also have to provide the window with an event that will be raised whrn the user click on the close button.

public event EventHandler Closed; public void Close() { this.Visibility = Visibility.Collapsed; //raise the closed event if (Closed != null) Closed(this, EventArgs.Empty); } void closeButton_Click(object sender, RoutedEventArgs e) { Close(); }

the handler will hide the window and notify the manager to take all the actions it has to do to remove the window from the surface and destroy it.

An intereresting thing to note is how it was implemented the Caption property, used to set the title of the window:

public string Caption { get { return (captionText != null) ? captionText.Text : _Caption; } set { if (captionText != null) captionText.Text = value; else _Caption = value; } } private string _Caption = "";

It may happen that you want to get or set this property before the template is actually loaded, so you have to

bufferize the value and apply it later in the OnApplyTemplate() function.

The WindowManager class is extremely simple, it will get a refence to the Canvas in which any window will be placed and will offer function to create new windows specifing the control that will be hosted inside and the position where to display it. It will internally subscribe to the Closed() event raised by the windows and will automatically remove them from the surface whenever they are closed.

/// <summary> /// Class that handles the creation and destruction of dynamic windows /// </summary> public class WindowsManager { private Canvas _canvas = null; /// <summary> /// creates the manager and stores the canvas to which attach the windows /// </summary> /// <param name="surface"></param> public WindowsManager(Canvas surface) { _canvas = surface; } public Window ShowWindow(FrameworkElement content, string caption, Point location) { Window w = new Window(); w.Caption = caption; w.Content = content; w.Closed += new EventHandler(w_Closed); Canvas.SetLeft(w, location.X); Canvas.SetTop(w, location.Y); _canvas.Children.Add(w); return w; } ... void w_Closed(object sender, EventArgs e) { //remove the object from the childern colelction and dispose it dispose the object Window w = (Window)sender; _canvas.Children.Remove(w); //todo: dispose the object } }

You have a series of options on how to use this control, you can define it directly in xaml:

<Canvas x:Name="LayoutRoot" Background="White"> <ctrl:Window Width="200" Canvas.Top="100" Caption="Test 0"> <TextBlock>TEST</TextBlock> </ctrl:Window> ...

Or you can create them by code using the WindowManager class.

public partial class Page : UserControl { public Page() { InitializeComponent(); this.Loaded += new RoutedEventHandler(Page_Loaded); } void Page_Loaded(object sender, RoutedEventArgs e) { wm = new WindowsManager(LayoutRoot); this.btn.Click += new RoutedEventHandler(btn_Click); } int i = 0; void btn_Click(object sender, RoutedEventArgs e) { i++; wm.ShowWindow(new WindowContent(), "Windows " + i.ToString(), new Point(100, 100)); } private WindowsManager wm = null; }

 

That’s all for this part, see you for the next ones.

The complete sample solution:

SimulatingWindows.zip

Technorati Tag: ,

-->

As my first real experiment in building a Silverlight control, I wanted to realize something that could permit me to offer to the users a windows-like experience application hosted in the browser, so I started wondering how difficult was to implement a control that could host other silverlight control and even pages, this control should [...]



kick it on DotNetKicks.com

Written by Guardian

August 20th, 2008 at 5:01 am

Posted in Silverlight

Tagged with , , ,