CPSC 481 - Tutorial 6 More WPF (based on previous tutorials by Alice Thudt, Fateme Rajabiyazdi, David Ledo, Brennan Jones, Sowmya Somanath, and Kevin Ta)
Introduction
Contact Info li26@ucalgary.ca Please always include [CPSC 481] in the subject header Expect replies in: 24 hours on weekdays 48 hours on weekends http://pages.cpsc.ucalgary.ca/~li26/481/
Reminder Horizontal Prototype Due March 6th (Monday) in class Write-up, including redesign rational (i.e. changes from the Lo-Fi prototype), screenshots, and the grading sheet (from the handout) Horizontal prototype presentation freeze Either email your slides (PDF) to me (li26@ucalgary.ca) OR submit on a USB, along with your write-up Presentations on March 7th / 9th
Horizontal Prototype
More WPF!
User Controls Controls are interactive elements in WPF Elements such as Buttons, TextBoxes, etc. are Microsoft Controls If you want to reuse specific elements in your interface, you can create User Controls User Controls can be composites of Microsoft Elements
Create User Control
Page Switcher
Create 3 buttons Pages: Method 1
Create a user control Pages (cont.)
Pages (cont.)
Fill with content Pages (cont.)
Pages (cont.) Add a StackPanel And give it a name
Pages: Initialize User Controls Create 2 additional user controls Add the following code to your MainWindow.xaml.cs before the constructor: // Initialize user controls UserControl1 _page1 = new UserControl1(); UserControl2 _page2 = new UserControl2(); UserControl3 _page3 = new UserControl3();
Pages: Result
Pages: Event Handlers private void Page1_Button_Click(object sender, RoutedEventArgs e) { stackpanel1.children.clear(); } stackpanel1.children.add(_page1); private void Page2_Button_Click(object sender, RoutedEventArgs e) { stackpanel1.children.clear(); } stackpanel1.children.add(_page2); private void Page3_Button_Click(object sender, RoutedEventArgs e) { stackpanel1.children.clear(); } stackpanel1.children.add(_page3);
Pages: Method 2 Create 3 User Controls, and name them: MainMenu, Page1, Page2 Add a Switcher.cs class to the project using System.Windows.Controls; public static MainWindow pageswitcher; public static void Switch(UserControl newpage) { pageswitcher.navigate(newpage); }
Pages (cont.) Add the following code to MainWindow.xaml.cs public MainWindow() { InitializeComponent(); Switcher.pageSwitcher = this; Switcher.Switch(new MainMenu()); } public void Navigate(UserControl nextpage) { this.content = nextpage; }
Pages (cont.) Design MainMenu, Page1, and Page2 to look like this:
Pages (cont.) For MainMenu, Page1, and Page2, add the following events: private void Button1_Click(object sender, RoutedEventArgs e) { Switcher.Switch(new MainMenu()); } private void Button2_Click(object sender, RoutedEventArgs e) { Switcher.Switch(new Page1()); } private void Button3_Click(object sender, RoutedEventArgs e) { Switcher.Switch(new Page2()); }
Pages (cont.) If you want to save the page state, then keep the User Control instance Page1 _page1 = new Page1(); private void Button_Click(object sender, RoutedEventArgs e) { Switcher.Switch(_page1); }
Style and Template
Style To customize the look-and-feel of a button Add a Resources tag
Style (cont.) Define the style
Style (cont.) OR give it a key to reuse the same style
Template You can create Control Templates These define how a control is drawn
Template (cont.) You can create Control Templates to define how a control is drawn <UserControl.Resources> <Style x:key="mybuttonstyle" TargetType="{x:Type Button} > <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Border Name="fondoboton" BorderBrush="DarkGray" BorderThickness="5" CornerRadius="10,0,10,0" Background="LightGray"> <ContentPresenter Name="contenido" Content="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}"></ContentPresenter> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources>
Template (cont.) You can create Control Templates to define how a control is drawn <UserControl.Resources> <Style x:key="mybuttonstyle" TargetType="{x:Type Button} > <Setter Property= Background" Value="Orange"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Border Name="fondoboton" BorderBrush="DarkGray" BorderThickness="5" CornerRadius="10,0,10,0" Background= {TemplateBinding Background} > <ContentPresenter Name="contenido" Content="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}"></ContentPresenter> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources>
Template: Override Property For a specific button, you can set the background colour to something other than the default, while keeping everything else the same as the template Without changing the template, change the button s XAML code to something like this: <Button Style= {StaticResource MyButtonStyle} Background= Red Content= Button HorizontalAlignment= Left Margin= 119,234,0,0 VerticalAlignment= Top Width= 75 >
List Box
Drag & drop List Box
List Box (cont.) Click to modify items
List Box (cont.) Select ListBoxItem Click to add
List Box (cont.) Change content
List Box: Result
List Box (cont.) Obtain the selected index listbox1.selectedindex; Add event handler private void listbox1_selectionchanged(object sender, SelectionChangedEventArgs e) { testbox1.text = (String)((ListBoxItem)listBox1.SelectedItem).Content; }
Simple Animation
Insert an ellipse Simple Animation
Simple Animation (cont.) XAML code <Ellipse Name= ellipse1" Fill= #FFE828 HorizontalAlignment= Left Height= 118 Margin= 10,151,0,0 Stroke= Black Width= 127 > Add instance declaration using System.Windows.Media.Animation; private Storyboard mystoryboard;
Simple Animation (cont.) In the User Control constructor // animate fade in and fade out DoubleAnimation animation = new DoubleAnimation(); animation.from = 1.0; animation.to = 0.0; animation.duration = new Duration(TimeSpan.FromSeconds(5)); animation.autoreverse = true; animation.repeatbehavior = RepeatBehavior.Forever; mystoryboard = new Storyboard(); mystoryboard.children.add(animation); Storyboard.SetTargetName(animation, ellipse1.name); Storyboard.SetTargetProperty(animation, new PropertyPath(Ellipse.OpacityProperty)); // Use the Loaded event to start the Storyboard. ellipse1.loaded += new RoutedEventHandler(myEllipseLoaded);
Simple Animation (cont.) Add event handler private void myellipseloaded(object sender, RoutedEventArgs e) { mystoryboard.begin(this); } How about animating the width of the ellipse?
Click & Drag
Click & Drag Create an ellipse and give a name Also give the grid a name
Click & Drag (cont.) MouseDown MouseMove MouseUp
Click & Drag (cont.) bool captured = false; private void Ellipse1_MouseDown(object sender, MouseButtonEventArgs e) { captured = true; } private void Ellipse1_MouseUp(object sender, MouseButtonEventArgs e) { captured = false; } private void Ellipse1_MouseMove(object sender, MouseEventArgs e) { if (captured) } { Thickness margin = ellipse1.margin; margin.left = e.getposition(_maingrid).x - (ellipse1.width / 2); margin.top = e.getposition(_maingrid).y - (ellipse1.height / 2); ellipse1.margin = margin; }
Trigger
Trigger Allow you to change the value of a given property one a certain condition is reached Can be done entirely in XAML 3 types: 1. Property trigger 2. Data trigger 3. Event trigger
Property Trigger Defined by the <Trigger> element Watches the change of a specific property on the owner control Whenever that property has a specific value, it changes other properties
Property Trigger Example <TextBlock Text="Hello, styled world!" FontSize="28" HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock.Style> <Style TargetType="TextBlock"> <Setter Property="Foreground" Value="Blue"></Setter> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Foreground" Value="Red" /> <Setter Property="TextDecorations" Value="Underline" /> </Trigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock> Result: underlines and colours the text red on mouse over
Data Trigger Defined by the <DataTrigger> element Watches a specific property that can be anywhere (not specifically on the owner control) Whenever that property has a specific value, it changes other properties
Data Trigger Example <CheckBox Name="cbSample" Content= Hello, world? /> <TextBlock Margin= 0,20,0,0 FontSize="48" HorizontalAlignment="Center"> <TextBlock.Style> <Style TargetType="TextBlock"> <Setter Property="Text" Value= No"></Setter> <Setter Property="Foreground" Value="Red"></Setter> <Style.Triggers> <DataTrigger Binding= {Binding ElementName=cbSample, Path=IsChecked} Value="True"> <Setter Property="Foreground" Value="Green" /> <Setter Property="Text" Value= Yes!" /> </DataTrigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock> Result: Changes the text to Yes! and colour to green when the checkbox is checked
Event Trigger Defined by the <EventTrigger> element Triggers in response to an event being called Triggers exactly once that event is called
Event Trigger Example <TextBlock Name="lblStyled" Text="Hello, styled world!" FontSize="18" HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock.Style> <Style TargetType="TextBlock"> <Style.Triggers> <EventTrigger RoutedEvent= MouseEnter > <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration= 0:0:0.300 Storyboard.Targetproperty= FontSize" To="28"> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent= MouseLeave > <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration= 0:0:0.800 Storyboard.Targetproperty= FontSize" To="18"> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock>
Event Trigger Example (cont.) Result: animation enlarges the text on mouse over, and thinks it back to its original size on mouse leave
Image as Button
Image as Button Create a button that displays as an image <Grid> <Button Background="Transparent" HorizontalAlignment="Left" Margin="117,84,0,0" VerticalAlignment="Top" Width="361" Height="231"> <Image Name="img1" Stretch="Fill" Source="Testimg.png" Margin= 10" /> </Button> </Grid>
Timer
Timer We are going to make use of a DispatchTimer Make sure you are using the Threading namespace Add a <TextBlock> on your code, and we will change the value every time the timer ticks
Timer (cont.) XAML <Grid Name="grid" > <TextBlock Name="TimerText" FontSize="48" VerticalAlignment= Center" HorizontalAlignment= Center" /> </Grid> C# using System.Windows.Threading; public void DispatcherTimerSample() { InitializeComponent(); DispatcherTimer timer = new DispatcherTimer(); timer.interval = TimeSpan.FromSeconds(1); timer.tick += timer_tick; timer.start(); } void timer_tick(object sender, EventArgs e) { timertext.content = DateTime.Now.ToLongTimeString(); }
Exercise Try a few of the things we talked today
Next Week Horizontal Prototype Presentations 12 mins + 3 mins feedback All group members must attend
Thank You