Skip to content

Commit 4999e44

Browse files
committed
Create SearchBox component
This component replaces the search boxes in CodeExplorer and Add/Remove References dialog. It provides a vast simplification over the preexisting use of overriding a TextBox with a Style defined in the resources section. Also this commit moves Behaviours into their own solution folder, though no namespace adjustments are performed.
1 parent dd68164 commit 4999e44

8 files changed

+210
-1
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System.Windows;
2+
using System.Windows.Controls.Primitives;
3+
4+
namespace Rubberduck.UI.Controls.Behavior
5+
{
6+
using ButtonBehavior = System.Windows.Interactivity.Behavior<ButtonBase>;
7+
8+
public class ResetValueBehavior : ButtonBehavior
9+
{
10+
private ButtonBase _associatedButton;
11+
12+
protected override void OnAttached()
13+
{
14+
_associatedButton = AssociatedObject;
15+
16+
_associatedButton.Click += AssociatedButtonClick;
17+
}
18+
19+
protected override void OnDetaching()
20+
{
21+
_associatedButton.Click -= AssociatedButtonClick;
22+
}
23+
24+
private void AssociatedButtonClick(object sender, RoutedEventArgs e)
25+
{
26+
Affects = Default;
27+
}
28+
29+
public object Affects
30+
{
31+
get => GetValue(AffectsProperty);
32+
set
33+
{
34+
var oldValue = Affects;
35+
SetValue(AffectsProperty, value);
36+
OnPropertyChanged(new DependencyPropertyChangedEventArgs(AffectsProperty, oldValue, value));
37+
}
38+
}
39+
40+
public object Default
41+
{
42+
get => GetValue(DefaultProperty);
43+
set
44+
{
45+
var oldValue = Default;
46+
SetValue(DefaultProperty, value);
47+
OnPropertyChanged(new DependencyPropertyChangedEventArgs(DefaultProperty, oldValue, value));
48+
}
49+
}
50+
51+
// Using a DependencyProperty as the backing store for Affects.
52+
// This enables animation, styling, binding, etc...
53+
public static readonly DependencyProperty AffectsProperty =
54+
DependencyProperty.Register("Affects", typeof(object), typeof(ResetValueBehavior), new UIPropertyMetadata());
55+
public static readonly DependencyProperty DefaultProperty =
56+
DependencyProperty.Register("Default", typeof(object), typeof(ResetValueBehavior), new UIPropertyMetadata(defaultValue: null));
57+
}
58+
}

Rubberduck.Core/UI/Controls/NumberPicker.xaml.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.ComponentModel;
33
using System.Windows;
4+
using System.Windows.Controls;
45
using Rubberduck.Settings;
56

67
// credit to http://stackoverflow.com/a/2752538
@@ -9,7 +10,7 @@ namespace Rubberduck.UI.Controls
910
/// <summary>
1011
/// Interaction logic for NumberPicker.xaml
1112
/// </summary>
12-
public partial class NumberPicker : IDataErrorInfo
13+
public partial class NumberPicker : UserControl, IDataErrorInfo
1314
{
1415
public static readonly DependencyProperty NumValueProperty =
1516
DependencyProperty.Register(nameof(NumValue), typeof(int), typeof(NumberPicker), new UIPropertyMetadata(default(int), PropertyChangedCallback));
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<UserControl x:Class="Rubberduck.UI.Controls.SearchBox"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
7+
xmlns:local="clr-namespace:Rubberduck.UI.Controls;assembly="
8+
xmlns:ib="clr-namespace:Rubberduck.UI.Controls.Behavior;assembly="
9+
xmlns:converters="clr-namespace:Rubberduck.UI.Converters;assembly="
10+
mc:Ignorable="d"
11+
MinWidth="50" MinHeight="20"
12+
Height="20"
13+
Name="Root"
14+
d:DesignHeight="20" d:DesignWidth="400"
15+
d:DataContext="{d:DesignInstance local:SearchBox, IsDesignTimeCreatable=True}">
16+
<Grid>
17+
<Grid.ColumnDefinitions>
18+
<ColumnDefinition Width="*"/>
19+
<ColumnDefinition Width="20" />
20+
</Grid.ColumnDefinitions>
21+
<TextBox Text="{Binding Path=Text, ElementName=Root, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
22+
x:Name="ValueContainer"
23+
Background="Transparent"
24+
Panel.ZIndex="2"
25+
VerticalContentAlignment="Center"
26+
Width="Auto"
27+
Grid.Row="0" Grid.Column="0"/>
28+
<!-- this is the actual hint container, it's BELOW the displaying control -->
29+
<TextBox Text="{Binding Path=Hint, ElementName=Root, Mode=OneWay}"
30+
Background="{Binding Path=Background, ElementName=Root}"
31+
Width="{Binding Path=ActualWidth, ElementName=ValueContainer}"
32+
Height="{Binding Path=ActualHeight, ElementName=ValueContainer}"
33+
Panel.ZIndex="1"
34+
VerticalContentAlignment="Center"
35+
Grid.Row="0" Grid.Column="0">
36+
<TextBox.Style>
37+
<Style TargetType="{x:Type TextBox}">
38+
<!-- Setter needs to be within this type to be overwritable with a trigger -->
39+
<Setter Property="Foreground" Value="Transparent" />
40+
<Style.Triggers>
41+
<DataTrigger Binding="{Binding Path=Text, Source={x:Reference ValueContainer}}" Value="">
42+
<Setter Property="Foreground" Value="{x:Static SystemColors.GrayTextBrush}"/>
43+
</DataTrigger>
44+
</Style.Triggers>
45+
</Style>
46+
</TextBox.Style>
47+
</TextBox>
48+
<Button Name="SearchButton" Grid.Column="1" Command="{Binding ClearSearchCommand}"
49+
BorderBrush="{x:Static SystemColors.ControlLightBrush}"
50+
Background="Transparent"
51+
Width="20" Height="20" Padding="0" Margin="0,1"
52+
xmlns:sys="clr-namespace:System;assembly=mscorlib">
53+
<Button.Resources>
54+
<converters:SearchImageSourceConverter x:Key="SearchToIcon" />
55+
</Button.Resources>
56+
<Image VerticalAlignment="Center" HorizontalAlignment="Center"
57+
Width="16" Height="16"
58+
Source="{Binding Text, ElementName=ValueContainer,
59+
Converter={StaticResource SearchToIcon},
60+
UpdateSourceTrigger=PropertyChanged}" />
61+
<i:Interaction.Behaviors>
62+
<local:FocusElementAfterClickBehavior FocusElement="{x:Reference ValueContainer}"/>
63+
<ib:ResetValueBehavior Affects="{Binding Path=Text, ElementName=ValueContainer, Mode=OneWayToSource}"
64+
Default="{x:Static sys:String.Empty}"/>
65+
</i:Interaction.Behaviors>
66+
</Button>
67+
</Grid>
68+
</UserControl>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using NLog;
2+
using Rubberduck.UI.Command;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using System.Windows;
9+
using System.Windows.Controls;
10+
using System.Windows.Data;
11+
using System.Windows.Documents;
12+
using System.Windows.Input;
13+
using System.Windows.Media;
14+
using System.Windows.Media.Imaging;
15+
using System.Windows.Navigation;
16+
using System.Windows.Shapes;
17+
18+
namespace Rubberduck.UI.Controls
19+
{
20+
/// <summary>
21+
/// Interaction logic for SearchBox.xaml
22+
/// </summary>
23+
public partial class SearchBox : UserControl
24+
{
25+
public static readonly DependencyProperty TextProperty =
26+
DependencyProperty.Register(nameof(Text), typeof(string), typeof(SearchBox), new UIPropertyMetadata(default(string), PropertyChangedCallback));
27+
public static readonly DependencyProperty HintProperty =
28+
DependencyProperty.Register(nameof(Hint), typeof(string), typeof(SearchBox), new UIPropertyMetadata(default(string), PropertyChangedCallback));
29+
30+
private static void PropertyChangedCallback(DependencyObject source, DependencyPropertyChangedEventArgs e)
31+
{
32+
if (source is SearchBox control)
33+
{
34+
var newValue = (string)e.NewValue;
35+
switch (e.Property.Name)
36+
{
37+
case "Text":
38+
control.Text = newValue;
39+
break;
40+
case "Hint":
41+
control.Hint = newValue;
42+
break;
43+
}
44+
}
45+
}
46+
47+
public string Text
48+
{
49+
get => (string)GetValue(TextProperty);
50+
set
51+
{
52+
var old = GetValue(TextProperty);
53+
SetValue(TextProperty, value);
54+
OnPropertyChanged(new DependencyPropertyChangedEventArgs(TextProperty, old, value));
55+
}
56+
}
57+
public string Hint
58+
{
59+
get => (string)GetValue(HintProperty);
60+
set
61+
{
62+
var old = GetValue(HintProperty);
63+
SetValue(HintProperty, value);
64+
OnPropertyChanged(new DependencyPropertyChangedEventArgs(HintProperty, old, value));
65+
}
66+
}
67+
68+
public ICommand ClearSearchCommand { get => new DelegateCommand(LogManager.GetCurrentClassLogger(), (arg) => Text = ""); }
69+
70+
public SearchBox()
71+
{
72+
// design instance!
73+
Text = "";
74+
Hint = "Search";
75+
Width = 300;
76+
Height = 25;
77+
Background = SystemColors.WindowBrush;
78+
// not so much design instance
79+
InitializeComponent();
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)