Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix that Backstage.IsOpen is not bindable #1104

Merged
merged 2 commits into from
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Fluent.Ribbon.Showcase/TestContent.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@
<Grid>
<!-- Backstage items can be keytipped -->
<Fluent:Backstage x:Name="Backstage"
Visibility="Collapsed">
Visibility="Collapsed"
IsOpen="{Binding IsBackstageOpen, Mode=TwoWay}">

<!--<Fluent:Backstage.Style>
<Style TargetType="Fluent:Backstage">
Expand Down Expand Up @@ -3213,6 +3214,12 @@
Size="Middle">
Show start screen
</Fluent:Button>

<Fluent:CheckBox x:Name="BackstageOpenBinding"
IsChecked="{Binding IsBackstageOpen}"
Visibility="{Binding ElementName=Backstage, Path=Visibility}">
Is backstage open binding
</Fluent:CheckBox>
</WrapPanel>
</GroupBox>

Expand Down
16 changes: 16 additions & 0 deletions Fluent.Ribbon.Showcase/ViewModels/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class MainViewModel : ViewModel
private bool? isCheckedToggleButton3 = true;

private bool areContextGroupsVisible = true;
private bool isBackstageOpen = false;

public MainViewModel()
{
Expand Down Expand Up @@ -95,6 +96,21 @@ public bool AreContextGroupsVisible
}
}

public bool IsBackstageOpen
{
get => this.isBackstageOpen;
set
{
if (value == this.isBackstageOpen)
{
return;
}

this.isBackstageOpen = value;
this.OnPropertyChanged();
}
}

public ColorViewModel ColorViewModel
{
get { return this.colorViewModel; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ protected override List<AutomationPeer> GetChildrenCore()
/// <inheritdoc />
void IExpandCollapseProvider.Collapse()
{
this.OwningBackstage.IsOpen = false;
this.OwningBackstage.SetIsOpen(false);
}

/// <inheritdoc />
void IExpandCollapseProvider.Expand()
{
this.OwningBackstage.IsOpen = true;
this.OwningBackstage.SetIsOpen(true);
}

/// <inheritdoc />
Expand Down
99 changes: 54 additions & 45 deletions Fluent.Ribbon/Controls/Backstage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public class Backstage : RibbonControl
/// <remarks>This is exposed to make it possible to show content on the same <see cref="AdornerLayer"/> as the backstage is shown on.</remarks>
public AdornerLayer? AdornerLayer { get; private set; }

#region IsOpen

/// <summary>
/// Gets or sets whether backstage is shown
/// </summary>
Expand All @@ -55,6 +57,50 @@ public bool IsOpen
public static readonly DependencyProperty IsOpenProperty =
DependencyProperty.Register(nameof(IsOpen), typeof(bool), typeof(Backstage), new PropertyMetadata(BooleanBoxes.FalseBox, OnIsOpenChanged, CoerceIsOpen));

private static object? CoerceIsOpen(DependencyObject d, object? baseValue)
{
var backstage = (Backstage)d;

if (backstage.CanChangeIsOpen == false)
{
return BooleanBoxes.Box(backstage.IsOpen);
}

return baseValue;
}

private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (Backstage)d;

var oldValue = (bool)e.OldValue;
var newValue = (bool)e.NewValue;

lock (syncIsOpen)
{
if ((bool)e.NewValue)
{
control.Show();
}
else
{
control.Hide();
}

// Invoke the event
control.IsOpenChanged?.Invoke(control, e);
}

(UIElementAutomationPeer.FromElement(control) as Fluent.Automation.Peers.RibbonBackstageAutomationPeer)?.RaiseExpandCollapseAutomationEvent(oldValue, newValue);
}

internal void SetIsOpen(bool isOpen)
{
this.SetCurrentValue(IsOpenProperty, BooleanBoxes.Box(isOpen));
}

#endregion

/// <summary>
/// Gets or sets whether backstage can be openend or closed.
/// </summary>
Expand Down Expand Up @@ -107,43 +153,6 @@ public bool CloseOnEsc
public static readonly DependencyProperty CloseOnEscProperty =
DependencyProperty.Register(nameof(CloseOnEsc), typeof(bool), typeof(Backstage), new PropertyMetadata(BooleanBoxes.TrueBox));

private static object? CoerceIsOpen(DependencyObject d, object? baseValue)
{
var backstage = (Backstage)d;

if (backstage.CanChangeIsOpen == false)
{
return BooleanBoxes.Box(backstage.IsOpen);
}

return baseValue;
}

private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (Backstage)d;

var oldValue = (bool)e.OldValue;
var newValue = (bool)e.NewValue;

lock (syncIsOpen)
{
if ((bool)e.NewValue)
{
control.Show();
}
else
{
control.Hide();
}

// Invoke the event
control.IsOpenChanged?.Invoke(control, e);
}

(UIElementAutomationPeer.FromElement(control) as Fluent.Automation.Peers.RibbonBackstageAutomationPeer)?.RaiseExpandCollapseAutomationEvent(oldValue, newValue);
}

/// <summary>Identifies the <see cref="UseHighestAvailableAdornerLayer"/> dependency property.</summary>
public static readonly DependencyProperty UseHighestAvailableAdornerLayerProperty = DependencyProperty.Register(nameof(UseHighestAvailableAdornerLayer), typeof(bool), typeof(Backstage), new PropertyMetadata(BooleanBoxes.TrueBox));

Expand Down Expand Up @@ -278,7 +287,7 @@ protected virtual void OnDismissPopup(object? sender, DismissPopupEventArgs e)
return;
}

this.IsOpen = false;
this.SetIsOpen(false);
}

#endregion
Expand All @@ -288,7 +297,7 @@ protected virtual void OnDismissPopup(object? sender, DismissPopupEventArgs e)
// Handles click event
private void Click()
{
this.IsOpen = !this.IsOpen;
this.SetIsOpen(!this.IsOpen);
}

#region Show / Hide
Expand Down Expand Up @@ -512,7 +521,7 @@ private static void HandleOpenBackstageCommandCanExecute(object sender, CanExecu
private static void HandleOpenBackstageCommandExecuted(object sender, ExecutedRoutedEventArgs args)
{
var target = ((BackstageAdorner)args.Source).Backstage;
target.IsOpen = !target.IsOpen;
target.SetIsOpen(!target.IsOpen);
}

private void CreateAndAttachBackstageAdorner()
Expand Down Expand Up @@ -690,7 +699,7 @@ private void HandleOwnerWindowSizeChanged(object sender, SizeChangedEventArgs e)

private void HandleTabControlRequestBackstageClose(object? sender, EventArgs e)
{
this.IsOpen = false;
this.SetIsOpen(false);
}

// We have to collapse WindowsFormsHost while Backstage is open
Expand Down Expand Up @@ -729,7 +738,7 @@ protected override void OnKeyDown(KeyEventArgs e)
{
if (this.IsFocused)
{
this.IsOpen = !this.IsOpen;
this.SetIsOpen(!this.IsOpen);
e.Handled = true;
}
}
Expand All @@ -749,7 +758,7 @@ private void HandleOwnerWindowKeyDown(object sender, KeyEventArgs e)
// only handle ESC when the backstage is open
e.Handled = this.IsOpen;

this.IsOpen = false;
this.SetIsOpen(false);
}

private void OnBackstageLoaded(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -786,7 +795,7 @@ protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
/// <inheritdoc />
public override KeyTipPressedResult OnKeyTipPressed()
{
this.IsOpen = true;
this.SetIsOpen(true);
base.OnKeyTipPressed();

return KeyTipPressedResult.Empty;
Expand All @@ -795,7 +804,7 @@ public override KeyTipPressedResult OnKeyTipPressed()
/// <inheritdoc />
public override void OnKeyTipBack()
{
this.IsOpen = false;
this.SetIsOpen(false);
base.OnKeyTipBack();
}

Expand Down