Skip to content

Commit b1aa6f7

Browse files
committed
Additional popup placement modes. fixes #152
1 parent 8507ee0 commit b1aa6f7

File tree

12 files changed

+96
-403
lines changed

12 files changed

+96
-403
lines changed

MaterialDesignThemes.Wpf/MaterialDesignThemes.Wpf.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
4242
</PropertyGroup>
4343
<ItemGroup>
44-
<Compile Include="..\paket-files\ControlzEx\ControlzEx\src\Controlz\PopupEx.cs">
44+
<Compile Include="..\paket-files\ControlzEx\ControlzEx\src\ControlzEx\PopupEx.cs">
4545
<Paket>True</Paket>
4646
<Link>ControlzEx/PopupEx.cs</Link>
4747
</Compile>

MaterialDesignThemes.Wpf/PopupBox.cs

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
using System.Windows.Markup;
1313
using System.Windows.Media;
1414
using System.Windows.Media.Animation;
15-
using Controlz;
15+
using ControlzEx;
1616

1717
namespace MaterialDesignThemes.Wpf
1818
{
@@ -44,7 +44,31 @@ public enum PopupBoxPlacementMode
4444
/// <summary>
4545
/// Display the popup above the toggle, and align the center of the popup with the center of the toggle.
4646
/// </summary>
47-
TopAndAlignCentres
47+
TopAndAlignCentres,
48+
/// <summary>
49+
/// Display the popup to the left of the toggle, and align the top edges.
50+
/// </summary>
51+
LeftAndAlignTopEdges,
52+
/// <summary>
53+
/// Display the popup to the left of the toggle, and align the bottom edges.
54+
/// </summary>
55+
LeftAndAlignBottomEdges,
56+
/// <summary>
57+
/// Display the popup to the left of the toggle, and align the middles.
58+
/// </summary>
59+
LeftAndAlignMiddles,
60+
/// <summary>
61+
/// Display the popup to the right of the toggle, and align the top edges.
62+
/// </summary>
63+
RightAndAlignTopEdges,
64+
/// <summary>
65+
/// Display the popup to the right of the toggle, and align the bottom edges.
66+
/// </summary>
67+
RightAndAlignBottomEdges,
68+
/// <summary>
69+
/// Display the popup to the right of the toggle, and align the middles.
70+
/// </summary>
71+
RightAndAlignMiddles,
4872
}
4973

5074
/// <summary>
@@ -244,16 +268,21 @@ public bool StaysOpen
244268
set { SetValue(StaysOpenProperty, value); }
245269
}
246270

247-
public static readonly DependencyProperty PropertyTypeProperty = DependencyProperty.Register(
248-
"PlacementMode", typeof (PopupBoxPlacementMode), typeof (PopupBox), new PropertyMetadata(default(PopupBoxPlacementMode)));
271+
public static readonly DependencyProperty PlacementModeProperty = DependencyProperty.Register(
272+
"PlacementMode", typeof (PopupBoxPlacementMode), typeof (PopupBox), new PropertyMetadata(default(PopupBoxPlacementMode), PlacementModePropertyChangedCallback));
273+
274+
private static void PlacementModePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
275+
{
276+
((PopupBox)dependencyObject)._popup?.RefreshPosition();
277+
}
249278

250279
/// <summary>
251280
/// Gets or sets how the popup is aligned in relation to the toggle.
252281
/// </summary>
253282
public PopupBoxPlacementMode PlacementMode
254283
{
255-
get { return (PopupBoxPlacementMode) GetValue(PropertyTypeProperty); }
256-
set { SetValue(PropertyTypeProperty, value); }
284+
get { return (PopupBoxPlacementMode) GetValue(PlacementModeProperty); }
285+
set { SetValue(PlacementModeProperty, value); }
257286
}
258287

259288
public static readonly DependencyProperty PopupModeProperty = DependencyProperty.Register(
@@ -381,6 +410,30 @@ private CustomPopupPlacement[] GetPopupPlacement(Size popupSize, Size targetSize
381410
x = targetSize.Width/2 - popupSize.Width/2 - Math.Abs(offset.X*2);
382411
y = 0 - popupSize.Height - Math.Abs(offset.Y * 2);
383412
break;
413+
case PopupBoxPlacementMode.LeftAndAlignTopEdges:
414+
x = 0 - popupSize.Width - Math.Abs(offset.X * 2);
415+
y = 0 - Math.Abs(offset.Y * 3);
416+
break;
417+
case PopupBoxPlacementMode.LeftAndAlignBottomEdges:
418+
x = 0 - popupSize.Width - Math.Abs(offset.X * 2);
419+
y = 0 - (popupSize.Height - targetSize.Height);
420+
break;
421+
case PopupBoxPlacementMode.LeftAndAlignMiddles:
422+
x = 0 - popupSize.Width - Math.Abs(offset.X * 2);
423+
y = targetSize.Height / 2 - popupSize.Height / 2 - Math.Abs(offset.Y * 2);
424+
break;
425+
case PopupBoxPlacementMode.RightAndAlignTopEdges:
426+
x = targetSize.Width;
427+
y = 0 - Math.Abs(offset.X * 3);
428+
break;
429+
case PopupBoxPlacementMode.RightAndAlignBottomEdges:
430+
x = targetSize.Width;
431+
y = 0 - (popupSize.Height - targetSize.Height);
432+
break;
433+
case PopupBoxPlacementMode.RightAndAlignMiddles:
434+
x = targetSize.Width;
435+
y = targetSize.Height / 2 - popupSize.Height / 2 - Math.Abs(offset.Y * 2);
436+
break;
384437
default:
385438
throw new ArgumentOutOfRangeException();
386439
}
@@ -399,7 +452,9 @@ private void AnimateChildren()
399452
double translateYFrom;
400453
if (PlacementMode == PopupBoxPlacementMode.TopAndAlignCentres
401454
|| PlacementMode == PopupBoxPlacementMode.TopAndAlignLeftEdges
402-
|| PlacementMode == PopupBoxPlacementMode.TopAndAlignRightEdges)
455+
|| PlacementMode == PopupBoxPlacementMode.TopAndAlignRightEdges
456+
|| PlacementMode == PopupBoxPlacementMode.LeftAndAlignBottomEdges
457+
|| PlacementMode == PopupBoxPlacementMode.RightAndAlignBottomEdges)
403458
{
404459
controls = controls.Reverse();
405460
translateYFrom = 40;

MaterialDesignThemes.Wpf/Themes/Generic.xaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:local="clr-namespace:MaterialDesignThemes.Wpf"
55
xmlns:converters="clr-namespace:MaterialDesignThemes.Wpf.Converters"
6-
xmlns:controlz="clr-namespace:Controlz">
6+
xmlns:controlzEx="clr-namespace:ControlzEx">
77

88
<ResourceDictionary.MergedDictionaries>
99
<!-- we only bring in the dictionaries for controls which were "invented"
@@ -533,20 +533,20 @@
533533
</VisualState>
534534
</VisualStateGroup>
535535
</VisualStateManager.VisualStateGroups>
536-
<controlz:PopupEx IsOpen="False"
536+
<controlzEx:PopupEx IsOpen="False"
537537
PlacementTarget="{Binding ElementName=DialogHostRoot, Mode=OneWay}"
538538
StaysOpen="True"
539539
AllowsTransparency="True"
540540
PopupAnimation="None"
541541
x:Name="PART_Popup"
542542
Placement="Center">
543-
<Popup.Resources>
543+
<controlzEx:PopupEx.Resources>
544544
<ResourceDictionary>
545545
<ResourceDictionary.MergedDictionaries>
546546
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
547547
</ResourceDictionary.MergedDictionaries>
548548
</ResourceDictionary>
549-
</Popup.Resources>
549+
</controlzEx:PopupEx.Resources>
550550
<local:Card x:Name="PART_PopupContentElement"
551551
Margin="22"
552552
local:ShadowAssist.ShadowDepth="Depth5"
@@ -573,7 +573,7 @@
573573
</TransformGroup>
574574
</local:Card.RenderTransform>
575575
</local:Card>
576-
</controlz:PopupEx>
576+
</controlzEx:PopupEx>
577577
<AdornerDecorator>
578578
<ContentPresenter
579579
x:Name="ContentPresenter" Opacity="1"

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PopupBox.xaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3-
xmlns:controlz="clr-namespace:Controlz"
43
xmlns:wpf="clr-namespace:MaterialDesignThemes.Wpf"
5-
xmlns:converters="clr-namespace:MaterialDesignThemes.Wpf.Converters">
4+
xmlns:converters="clr-namespace:MaterialDesignThemes.Wpf.Converters"
5+
xmlns:controlzEx="clr-namespace:ControlzEx">
66

77
<ResourceDictionary.MergedDictionaries>
88
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Button.xaml" />
@@ -51,7 +51,7 @@
5151
Cursor="Hand"
5252
VerticalAlignment="Center"
5353
/>
54-
<controlz:PopupEx x:Name="PART_Popup" IsOpen="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsPopupOpen, Mode=TwoWay}"
54+
<controlzEx:PopupEx x:Name="PART_Popup" IsOpen="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsPopupOpen, Mode=TwoWay}"
5555
CustomPopupPlacementCallback="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=PopupPlacementMethod}"
5656
HorizontalOffset="5"
5757
VerticalOffset="5"
@@ -61,7 +61,7 @@
6161
AllowsTransparency="True">
6262
<wpf:Card Content="{TemplateBinding PopupContent}" ContentTemplate="{TemplateBinding PopupContentTemplate}"
6363
Margin="5" />
64-
</controlz:PopupEx>
64+
</controlzEx:PopupEx>
6565
</Grid>
6666
</ControlTemplate>
6767
</Setter.Value>
@@ -247,7 +247,7 @@
247247
</ContentControl>
248248
</Grid>
249249
</ToggleButton>
250-
<controlz:PopupEx x:Name="PART_Popup"
250+
<controlzEx:PopupEx x:Name="PART_Popup"
251251
IsOpen="False"
252252
CustomPopupPlacementCallback="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=PopupPlacementMethod}"
253253
PlacementTarget="{Binding ElementName=PART_Toggle}"
@@ -282,7 +282,7 @@
282282
</ContentControl.Resources>
283283
</ContentControl>
284284
</Grid>
285-
</controlz:PopupEx>
285+
</controlzEx:PopupEx>
286286
</Grid>
287287
<ControlTemplate.Triggers>
288288
<Trigger Property="IsPopupOpen" Value="True">

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ValidationErrorTemplate.xaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
33
xmlns:wpf="clr-namespace:MaterialDesignThemes.Wpf"
4-
xmlns:controlz="clr-namespace:Controlz">
4+
xmlns:controlzEx="clr-namespace:ControlzEx">
55
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
66

77
<ControlTemplate x:Key="MaterialDesignValidationErrorTemplate">
@@ -24,15 +24,15 @@
2424
<ContentPresenter Content="{Binding CurrentItem}" />
2525
</Border>
2626

27-
<controlz:PopupEx x:Name="ValidationPopup"
27+
<controlzEx:PopupEx x:Name="ValidationPopup"
2828
IsOpen="False"
2929
Placement="Bottom"
3030
PlacementTarget="{Binding ElementName=Placeholder, Mode=OneWay}"
3131
AllowsTransparency="True">
3232
<Border Background="{DynamicResource MaterialDesignPaper}">
3333
<ContentPresenter Content="{Binding CurrentItem}" />
3434
</Border>
35-
</controlz:PopupEx>
35+
</controlzEx:PopupEx>
3636
</StackPanel>
3737
<ControlTemplate.Triggers>
3838
<MultiDataTrigger>

paket-files/ControlzEx/ControlzEx/src/Controlz/paket.version

Lines changed: 0 additions & 1 deletion
This file was deleted.

paket-files/ControlzEx/ControlzEx/src/Controlz/PopupEx.cs renamed to paket-files/ControlzEx/ControlzEx/src/ControlzEx/PopupEx.cs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
using System.Windows.Input;
99
using System.Windows.Interop;
1010

11-
namespace Controlz
11+
namespace ControlzEx
1212
{
1313
/// <summary>
1414
/// This custom popup can be used by validation error templates or something else.
@@ -21,9 +21,9 @@ public class PopupEx : Popup
2121
{
2222
public static readonly DependencyProperty CloseOnMouseLeftButtonDownProperty
2323
= DependencyProperty.Register("CloseOnMouseLeftButtonDown",
24-
typeof(bool),
25-
typeof(PopupEx),
26-
new PropertyMetadata(false));
24+
typeof(bool),
25+
typeof(PopupEx),
26+
new PropertyMetadata(false));
2727

2828
/// <summary>
2929
/// Gets/sets if the popup can be closed by left mouse button down.
@@ -40,6 +40,17 @@ public PopupEx()
4040
this.Opened += this.PopupEx_Opened;
4141
}
4242

43+
/// <summary>
44+
/// Causes the popup to update it's position according to it's current settings.
45+
/// </summary>
46+
public void RefreshPosition()
47+
{
48+
var offset = this.HorizontalOffset;
49+
// "bump" the offset to cause the popup to reposition itself on its own
50+
SetCurrentValue(HorizontalOffsetProperty, offset + 1);
51+
SetCurrentValue(HorizontalOffsetProperty, offset);
52+
}
53+
4354
private void PopupEx_Loaded(object sender, RoutedEventArgs e)
4455
{
4556
var target = this.PlacementTarget as FrameworkElement;
@@ -126,10 +137,7 @@ private void hostWindow_StateChanged(object sender, EventArgs e)
126137

127138
private void hostWindow_SizeOrLocationChanged(object sender, EventArgs e)
128139
{
129-
var offset = this.HorizontalOffset;
130-
// "bump" the offset to cause the popup to reposition itself on its own
131-
this.HorizontalOffset = offset + 1;
132-
this.HorizontalOffset = offset;
140+
RefreshPosition();
133141
}
134142

135143
private void SetTopmostState(bool isTop)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
40a2be62474f0b78f2fd125a5b321e011acd5bb5

0 commit comments

Comments
 (0)