Skip to content

Commit b158eca

Browse files
committed
Added TextBox behavior
1 parent 589bbcf commit b158eca

File tree

16 files changed

+384
-42
lines changed

16 files changed

+384
-42
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
using Microsoft.Xaml.Interactivity;
2+
using System;
3+
using Windows.UI.Xaml;
4+
using Windows.UI.Xaml.Controls;
5+
using Windows.UI.Xaml.Markup;
6+
7+
namespace Template10.Behaviors
8+
{
9+
/// <summary>
10+
/// Trigger which runs off a timer
11+
/// </summary>
12+
[ContentProperty(Name = "Actions")]
13+
public sealed class TimerTriggerBehavior : DependencyObject, IBehavior
14+
{
15+
private int _tickCount;
16+
private DispatcherTimer _timer;
17+
18+
/// <summary>
19+
/// Backing storage for Actions collection
20+
/// </summary>
21+
public static readonly DependencyProperty ActionsProperty =
22+
DependencyProperty.Register("Actions", typeof(ActionCollection), typeof(TimerTriggerBehavior), new PropertyMetadata(null));
23+
24+
/// <summary>
25+
/// Actions collection
26+
/// </summary>
27+
public ActionCollection Actions
28+
{
29+
get
30+
{
31+
ActionCollection actions = (ActionCollection)base.GetValue(ActionsProperty);
32+
if (actions == null)
33+
{
34+
actions = new ActionCollection();
35+
base.SetValue(ActionsProperty, actions);
36+
}
37+
return actions;
38+
}
39+
}
40+
41+
/// <summary>
42+
/// Backing storage for the counter
43+
/// </summary>
44+
public static readonly DependencyProperty MillisecondsPerTickProperty =
45+
DependencyProperty.Register("MillisecondsPerTick", typeof(double), typeof(TimerTriggerBehavior), new PropertyMetadata(1000.0));
46+
47+
/// <summary>
48+
/// Milliseconds
49+
/// </summary>
50+
public double MillisecondsPerTick
51+
{
52+
get
53+
{
54+
return (double)base.GetValue(MillisecondsPerTickProperty);
55+
}
56+
set
57+
{
58+
base.SetValue(MillisecondsPerTickProperty, value);
59+
}
60+
}
61+
62+
/// <summary>
63+
/// Backing storage for the total ticks counter
64+
/// </summary>
65+
public static readonly DependencyProperty TotalTicksProperty =
66+
DependencyProperty.Register("TotalTicks", typeof(int), typeof(TimerTriggerBehavior), new PropertyMetadata(-1));
67+
68+
/// <summary>
69+
/// Total ticks elapsed
70+
/// </summary>
71+
public int TotalTicks
72+
{
73+
get
74+
{
75+
return (int)base.GetValue(TotalTicksProperty);
76+
}
77+
set
78+
{
79+
base.SetValue(TotalTicksProperty, value);
80+
}
81+
}
82+
83+
/// <summary>
84+
/// Called when the timer elapses
85+
/// </summary>
86+
/// <param name="sender"></param>
87+
/// <param name="e"></param>
88+
private void OnTimerTick(object sender, object e)
89+
{
90+
if (this.TotalTicks > 0 && ++this._tickCount >= this.TotalTicks)
91+
{
92+
this.StopTimer();
93+
}
94+
95+
// Raise the actions
96+
Interaction.ExecuteActions(AssociatedObject, this.Actions, null);
97+
}
98+
99+
/// <summary>
100+
/// Called to start the timer
101+
/// </summary>
102+
internal void StartTimer()
103+
{
104+
this._timer = new DispatcherTimer { Interval = (TimeSpan.FromMilliseconds(this.MillisecondsPerTick)) };
105+
this._timer.Tick += this.OnTimerTick;
106+
this._timer.Start();
107+
}
108+
109+
/// <summary>
110+
/// Called to stop the timer
111+
/// </summary>
112+
internal void StopTimer()
113+
{
114+
if (this._timer != null)
115+
{
116+
this._timer.Stop();
117+
this._timer = null;
118+
}
119+
}
120+
121+
/// <summary>
122+
/// Attaches to the specified object.
123+
/// </summary>
124+
/// <param name="associatedObject">The <see cref="T:Windows.UI.Xaml.DependencyObject"/> to which the <seealso cref="T:Microsoft.Xaml.Interactivity.IBehavior"/> will be attached.</param>
125+
public void Attach(DependencyObject associatedObject)
126+
{
127+
if ((associatedObject != AssociatedObject) && !Windows.ApplicationModel.DesignMode.DesignModeEnabled)
128+
{
129+
if (AssociatedObject != null)
130+
throw new InvalidOperationException("Cannot attach behavior multiple times.");
131+
132+
AssociatedObject = associatedObject;
133+
StartTimer();
134+
}
135+
}
136+
137+
/// <summary>
138+
/// Detaches this instance from its associated object.
139+
/// </summary>
140+
public void Detach()
141+
{
142+
this.StopTimer();
143+
AssociatedObject = null;
144+
}
145+
146+
/// <summary>
147+
/// Gets the <see cref="T:Windows.UI.Xaml.DependencyObject"/> to which the <seealso cref="T:Microsoft.Xaml.Interactivity.IBehavior"/> is attached.
148+
/// </summary>
149+
public DependencyObject AssociatedObject { get; private set; }
150+
}
151+
152+
153+
[ContentProperty(Name = "Actions")]
154+
[TypeConstraint(typeof(TextBox))]
155+
public class TextBoxEnterBehavior : DependencyObject, IBehavior
156+
{
157+
private TextBox AssociatedTextBox { get { return AssociatedObject as TextBox; } }
158+
public DependencyObject AssociatedObject { get; private set; }
159+
160+
public void Attach(DependencyObject associatedObject)
161+
{
162+
AssociatedObject = associatedObject;
163+
AssociatedTextBox.KeyDown += AssociatedTextBox_KeyDown;
164+
}
165+
166+
public void Detach()
167+
{
168+
AssociatedTextBox.KeyDown -= AssociatedTextBox_KeyDown;
169+
}
170+
171+
private void AssociatedTextBox_KeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
172+
{
173+
if (e.Key == Windows.System.VirtualKey.Enter)
174+
{
175+
Interaction.ExecuteActions(AssociatedObject, this.Actions, null);
176+
}
177+
}
178+
179+
public ActionCollection Actions
180+
{
181+
get
182+
{
183+
var actions = (ActionCollection)base.GetValue(ActionsProperty);
184+
if (actions == null)
185+
{
186+
base.SetValue(ActionsProperty, actions = new ActionCollection());
187+
}
188+
return actions;
189+
}
190+
}
191+
public static readonly DependencyProperty ActionsProperty =
192+
DependencyProperty.Register("Actions", typeof(ActionCollection),
193+
typeof(TextBoxEnterBehavior), new PropertyMetadata(null));
194+
}
195+
}

Templates (Project)/Blank/Blank.csproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,14 @@
9494
<Compile Include="App.xaml.cs">
9595
<DependentUpon>App.xaml</DependentUpon>
9696
</Compile>
97+
<Compile Include="Behaviors\TextBoxEnterBehavior.cs" />
9798
<Compile Include="Controls\BackButton.xaml.cs">
9899
<DependentUpon>BackButton.xaml</DependentUpon>
99100
</Compile>
100101
<Compile Include="Common\BootStrapper.cs" />
102+
<Compile Include="Controls\ForwardButton.xaml.cs">
103+
<DependentUpon>ForwardButton.xaml</DependentUpon>
104+
</Compile>
101105
<Compile Include="Controls\PageHeader.xaml.cs">
102106
<DependentUpon>PageHeader.xaml</DependentUpon>
103107
</Compile>
@@ -146,6 +150,10 @@
146150
<SubType>Designer</SubType>
147151
<Generator>MSBuild:Compile</Generator>
148152
</Page>
153+
<Page Include="Controls\ForwardButton.xaml">
154+
<SubType>Designer</SubType>
155+
<Generator>MSBuild:Compile</Generator>
156+
</Page>
149157
<Page Include="Controls\PageHeader.xaml">
150158
<SubType>Designer</SubType>
151159
<Generator>MSBuild:Compile</Generator>
@@ -167,6 +175,11 @@
167175
<ItemGroup>
168176
<Folder Include="Models\" />
169177
</ItemGroup>
178+
<ItemGroup>
179+
<SDKReference Include="BehaviorsXamlSDKManaged, Version=12.0">
180+
<Name>Behaviors SDK %28XAML%29</Name>
181+
</SDKReference>
182+
</ItemGroup>
170183
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
171184
<VisualStudioVersion>14.0</VisualStudioVersion>
172185
</PropertyGroup>

Templates (Project)/Blank/Common/BootStrapper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Windows.UI.Xaml.Controls;
66
using Windows.ApplicationModel.Activation;
77
using Windows.UI.Core;
8+
using Windows.UI.Xaml.Navigation;
89

910
namespace Template10.Common
1011
{

Templates (Project)/Blank/Controls/BackButton.xaml.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,53 +16,59 @@ public sealed partial class BackButton : UserControl
1616
public BackButton()
1717
{
1818
this.InitializeComponent();
19-
Loaded += BackButton_Loaded;
19+
Loaded += (s, e) =>
20+
{
21+
DependencyObject item = this;
22+
while (!((item = VisualTreeHelper.GetParent(item)) is Page)) { }
23+
Page page = item as Page;
24+
this.Frame = page.Frame;
25+
this.Visibility = CalculateOnCanvasBackVisibility();
26+
};
2027
MyBackButton.Click += (s, e) => Frame.GoBack();
28+
Window.Current.SizeChanged += (s, arg) => this.Visibility = CalculateOnCanvasBackVisibility();
2129
RegisterPropertyChangedCallback(VisibilityProperty, (s, e) => VisibilityChanged?.Invoke(this, EventArgs.Empty));
2230
}
2331

2432
public Frame Frame { get; private set; }
2533

26-
private void BackButton_Loaded(object sender, RoutedEventArgs e)
27-
{
28-
DependencyObject item = this;
29-
while (!((item = VisualTreeHelper.GetParent(item)) is Page)) { }
30-
Page page = item as Page;
31-
this.Frame = page.Frame;
32-
this.Visibility = CalculateOnCanvasBackVisibility();
33-
Window.Current.SizeChanged += (s, arg) => this.Visibility = CalculateOnCanvasBackVisibility();
34-
}
35-
3634
private Visibility CalculateOnCanvasBackVisibility()
3735
{
36+
// by design it is not visible when not applicable
3837
var cangoback = Frame.CanGoBack;
3938
if (!cangoback)
4039
return Visibility.Collapsed;
4140

41+
// mobile always has a visible back button
4242
var mobilefam = ResourceContext.GetForCurrentView().QualifierValues["DeviceFamily"].Equals("Mobile");
4343
if (mobilefam)
4444
return Visibility.Collapsed;
4545

46+
// simply don't know what to do with else
4647
var desktopfam = ResourceContext.GetForCurrentView().QualifierValues["DeviceFamily"].Equals("Desktop");
4748
if (!desktopfam)
4849
return Visibility.Collapsed;
4950

51+
// touch always has a bisible back button
5052
var touchmode = UIViewSettings.GetForCurrentView().UserInteractionMode == UserInteractionMode.Touch;
5153
if (touchmode)
5254
return Visibility.Collapsed;
5355

56+
// full screen back button is only visible when mouse reveals title (prefered behavior is on-canvas visible)
5457
var fullscreen = ApplicationView.GetForCurrentView().IsFullScreen;
5558
if (fullscreen)
5659
return Visibility.Visible;
5760

61+
// hide the button if the shell button is visible
5862
var optinback = SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility.Equals(AppViewBackButtonVisibility.Visible);
5963
if (optinback)
6064
{
65+
// shell button will not be visible if there is no title bar
6166
var hastitle = !CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar;
6267
if (hastitle)
6368
return Visibility.Collapsed;
6469
}
6570

71+
// at this point, we show the on-canvas button
6672
return Visibility.Visible;
6773
}
6874
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<UserControl
2+
x:Class="Template10.Controls.ForwardButton"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:local="using:Template10.Controls"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
mc:Ignorable="d"
9+
d:DesignHeight="300"
10+
d:DesignWidth="400">
11+
<Button x:Name="MyForwardButton" Style="{StaticResource NavigationBackButtonNormalStyle}" RenderTransformOrigin="0.5,0.5" >
12+
<Button.RenderTransform>
13+
<CompositeTransform ScaleX="-1"/>
14+
</Button.RenderTransform>
15+
</Button>
16+
</UserControl>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using Windows.UI.Xaml;
3+
using Windows.UI.Xaml.Controls;
4+
using Windows.UI.Xaml.Media;
5+
6+
namespace Template10.Controls
7+
{
8+
public sealed partial class ForwardButton : UserControl
9+
{
10+
public event EventHandler VisibilityChanged;
11+
12+
public ForwardButton()
13+
{
14+
this.InitializeComponent();
15+
Loaded += (s, e) =>
16+
{
17+
DependencyObject item = this;
18+
while (!((item = VisualTreeHelper.GetParent(item)) is Page)) { }
19+
Page page = item as Page;
20+
this.Frame = page.Frame;
21+
this.Visibility = CalculateOnCanvasBackVisibility();
22+
};
23+
MyForwardButton.Click += (s, e) => Frame.GoForward();
24+
Window.Current.SizeChanged += (s, arg) => this.Visibility = CalculateOnCanvasBackVisibility();
25+
RegisterPropertyChangedCallback(VisibilityProperty, (s, e) => VisibilityChanged?.Invoke(this, EventArgs.Empty));
26+
}
27+
28+
public Frame Frame { get; private set; }
29+
30+
private Visibility CalculateOnCanvasBackVisibility()
31+
{
32+
// by design it is not visible when not applicable
33+
var cangoforward = Frame.CanGoForward;
34+
if (!cangoforward)
35+
return Visibility.Collapsed;
36+
37+
// at this point, we show the on-canvas button
38+
return Visibility.Visible;
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)