CPSC 481 – Tutorial 7
More WPF
Brennan Jones bdgjones@ucalgary.ca (based on tutorials by Alice Thudt, Fateme Rajabiyazdi, and David Ledo)
CPSC 481 Tutorial 7 More WPF Brennan Jones bdgjones@ucalgary.ca - - PowerPoint PPT Presentation
CPSC 481 Tutorial 7 More WPF Brennan Jones bdgjones@ucalgary.ca (based on tutorials by Alice Thudt, Fateme Rajabiyazdi, and David Ledo) Plan for Today More WPF material, examples, and coding exercises Mostly stuff that will be
Brennan Jones bdgjones@ucalgary.ca (based on tutorials by Alice Thudt, Fateme Rajabiyazdi, and David Ledo)
vertical prototypes
Horizontal prototype due Monday Nov. 2 in lecture:
changes from the first prototype), screen snapshots, and a grading sheet (from assignment handout)
(bdgjones@ucalgary.ca) OR submit them on a USB along with your write-up.
Microsoft Controls
interface, you can create User Controls
Elements
Create your own User Control
Create your own User Control, and try to add an instance of it to your MainWindow.xaml.
Create three buttons XAML
Create a user control
Name it
Fill it with content
Create two additional user controls and do the same.
Add a StackPanel to the Main Window Give it a name
Add the following code to your MainWindow.xaml.cs before the public MainWindow(){ … } constructor:
// Initialize user controls. UserControl1 page1 = new UserControl1(); UserControl2 page2 = new UserControl2(); UserControl3 page3 = new UserControl3();
Result:
Make it so that clicking the buttons at the top changes the current user control.
Add the following click-event handlers:
private void page1Button_Click(object sender, RoutedEventArgs e) { stackPanel1.Children.Clear(); stackPanel1.Children.Add(page1); } private void page2Button_Click(object sender, RoutedEventArgs e) { stackPanel1.Children.Clear(); stackPanel1.Children.Add(page2); } private void page3Button_Click(object sender, RoutedEventArgs e) { stackPanel1.Children.Clear(); stackPanel1.Children.Add(page3); }
Create a User Control for an Email that looks like this:
<Grid Background="White"> <Ellipse Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="10,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/> <Label Name="SenderText" Content="Sender: Brennan Jones" HorizontalAlignment="Left" Margin="125,19,0,0" VerticalAlignment="Top" FontWeight="Bold"/> <Label Name="BodyText" Content="Body of the email..." HorizontalAlignment="Left" Margin="125,50,0,0" VerticalAlignment="Top"/> <Canvas Name="DeleteGroup" HorizontalAlignment="Left" Height="25" Margin="401,10,0,0" VerticalAlignment="Top" Width="25" MouseDown="DeleteGroup_MouseDown"> <Ellipse Fill="Red" Height="25" Canvas.Left="0" Stroke="Black" Canvas.Top="0" Width="25"/> <Label Content="X" Canvas.Left="0" Canvas.Top="0" Foreground="White"/> </Canvas> </Grid>
each instance of an email.
be removed from the view.
public partial class Email : UserControl { private string sender; public string Sender { get { return sender; } set { sender = value; this.SenderText.Content = this.sender; } } private string body; public string Body { get { return body; } set { body = value; this.BodyText.Content = this.body; } } public Email() { InitializeComponent(); } private void DeleteGroup_MouseDown(object sender, MouseButtonEventArgs e) { (this.Parent as Panel).Children.Remove(this); } }
<ScrollViewer Height=“auto"> <StackPanel Height=“auto" Width=“auto"></StackPanel> </ScrollViewer>
emails (using the Email User Control that you just created).
public MainWindow() { InitializeComponent(); for(int i = 0; i < 20; i++) { Email email = new Email(); email.Sender = "Sender " + i.ToString(); this.Emails.Children.Add(email); }
}
Which of these do you want me to go over?
MainMenu, Page1, and Page2.
will handle switching between different User Controls.
using System.Windows.Controls; public static MainWindow pageSwitcher; public static void Switch(UserControl newPage) { pageSwitcher.Navigate(newPage); }
public MainWindow() { InitializeComponent(); Switcher.pageSwitcher = this; Switcher.Switch(new MainMenu()); } public void Navigate(UserControl nextPage) { this.Content = nextPage; }
following events:
private void Button_Click(object sender, RoutedEventArgs e) { Switcher.Switch(new MainMenu()); } private void Button_Click_1(object sender, RoutedEventArgs e) { Switcher.Switch(new Page1()); } private void Button_Click_2(object sender, RoutedEventArgs e) { Switcher.Switch(new Page2()); }
transitioning (e.g., to save the contents of textboxes, the states of checkboxes etc.), keep the same User Control object. For example:
Page1 page1 = new Page1(); ... private void Button_Click_1(object sender, RoutedEventArgs e) { Switcher.Switch(page1); }
Always use this ‘Page1’ object
Source (and excellent resource): http://www.codeproject.com/Articles/84630/WPF- Customize-your-Application-with-Styles-and-Con
Start by creating a button
Add this ‘Resources’ block
Insert this code: This defines the style of buttons in your XAML. The button’s appearance changes
You can also give it a key… …and set specific buttons to the particular style.
You can create define Control Templates
Example:
<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>
Result:
You can also define a default background colour:
<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>
Add this line Add this
Result:
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.
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"/>
Background is ‘Red’
Result:
Define a template for a button (like the one shown in the previous slides) that has a default border colour
has the border colour blue.
<UserControl.Resources> <Style x:Key="MyButtonStyle" TargetType="{x:Type Button}"> <Setter Property="BorderBrush" Value="Black" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Border Name="fondoboton" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="5" CornerRadius="10,0,10,0"> <ContentPresenter Name="contenido" Content="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}"></ContentPresenter> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources>
Result:
<Button Style="{StaticResource MyButtonStyle}" BorderBrush="Blue" Content="Button" HorizontalAlignment="Left" Margin="119,234,0,0" VerticalAlignment="Top" Width="75"/>
Result:
Drag a ListBox into the XAML
Click to modify items
Click to add Select ‘ListBoxItem’
Change content
Result:
Can get the currently-selected index:
listbox1.SelectedIndex
whenever a listbox’s selection is changed.
Add ‘SelectionChanged’ event handler.
private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e) { textbox1.Text = (String)((ListBoxItem)listBox1.SelectedItem).Content; }
Insert an ellipse into your XAML
XAML code:
<Ellipse Name="ellipse1" Fill="#FFE82828" HorizontalAlignment="Left" Height="118" Margin="10,151,0,0" Stroke="Black" VerticalAlignment="Top" Width="127"/>
Add this code to the top of your C# file:
using System.Windows.Media.Animation;
Add this inside your user control class before the constructor:
private Storyboard myStoryboard;
Add this code to your 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);
Add this function:
private void myEllipseLoaded(object sender, RoutedEventArgs e) { myStoryboard.Begin(this); }
ellipse is animated.
// animate fade in and fade out DoubleAnimation animation = new DoubleAnimation(); animation.From = 120.0; animation.To = 240.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.WidthProperty)); // Use the Loaded event to start the Storyboard. ellipse1.Loaded += new RoutedEventHandler(myEllipseLoaded);
Create an ellipse Give it a name
Give the grid a name too
Add MouseDown Add MouseMove Add MouseUp
bool captured = false; ... private void Ellipse_MouseDown_1(object sender, MouseButtonEventArgs e) { captured = true; } private void Ellipse_MouseUp_1(object sender, MouseButtonEventArgs e) { captured = false; } private void Ellipse_MouseMove_1(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; } }
Source (and excellent resource): http://www.wpf- tutorial.com/styles/trigger-datatrigger-event-trigger/
Property trigger
and 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>
Property trigger example
Data trigger
(not specifically on the owner control), and whenever that property has a specific value, it changes other properties.
Data trigger example
<CheckBox Name="cbSample" Content="Hello, world?" /> <TextBlock HorizontalAlignment="Center" Margin="0,20,0,0" FontSize="48"> <TextBlock.Style> <Style TargetType="TextBlock"> <Setter Property="Text" Value="No" /> <Setter Property="Foreground" Value="Red" /> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=cbSample, Path=IsChecked}" Value="True"> <Setter Property="Text" Value="Yes!" /> <Setter Property="Foreground" Value="Green" /> </DataTrigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock>
Data trigger example
when the checkbox is checked.
Event trigger
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> ...
Event trigger example (cont’d)
... <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
it back to its original size on mouse-leave.
Exercise: Create a button that displays as an image.
Solution:
<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>
namespace.
value every time the timer ticks.
<Grid Name="Grid"> <TextBlock Name=”timerText" FontSize="48” HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid>
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(); }