How to disable background GUI interaction when popup dialog opens - c#

Is there any way to disable background GUI interaction when popup dialog open?
My popup dialog is a UserControl so cannot manually set the content of that page using isEnabled to false property as my popup dismiss login is on that usercontrol page.
Thanks in advance.

You can set a background grid on your user control and on the background grid set IsHitTestVisible="False" Your popover will be defined after the grid so it's placed on top and can receive user input.
To disable the app bar, you can disable that when the popup opens. If there is a different app bar on every page then it's possible you could write a method which would find any app bar in the UI and disable it until the popup window is closed.
WinRTXAMLToolkit has a visual tree helper class, which could be used to find the app bars.
var AppBars = Window.Current.Content.GetDescendentsOfType<type of app bar>();
foreach(var appBar in AppBars)
{
appBar.IsEnabled=false;
}
When the popup window is hidden, re-enable the app bars.

In your event handler (Button) that opens the popup, write the following piece of code.
private void PopupButton_Click(object sender, RoutedEventArgs e)
{
this.IsHitTestVisible = false;
this.Opacity = 0.5;
MyPopup.IsOpen = true;
}
And when your popup closes, you may catch the event and write the following code.
private void MyPopup_Closed(object sender, object e)
{
this.IsHitTestVisible = true;
this.Opacity = 1;
}
This would give the same visual effect that you get when once opens a Dialog.

I have used SwapChainPanel to disable parent view content user interaction. Also I have added gray overlay while my custom popup is shown.
<SwapChainPanel x:Name="DirectXPanel" Visibility="{Binding IsOpen, Converter={StaticResource BooleanToVisibilityConverter}}" >
<Border CornerRadius="5" Opacity="0.60" Background="#000000" ></Border>
</SwapChainPanel>
<UserControls:CustomLoginPanel x:Name="CustomLoginPanel" Height="220" Width="400"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Row="0"
IsOpen="{Binding IsOpen, Mode=TwoWay}"
Margin="0,70,0,0"/>
Here ProgressDialog is my custom popover which I want to show while user is login.
SwapChainPanel is going to cover entire window while custom popover is shown. By default it is hidden.
IsOpen is property exist in my view. This property is used to Show/Hide the Popover.
"BooleanToVisibilityConverter" is a converter used to convert boolean to Visibility
BooleanToVisibilityConverter.cs:
public sealed class BooleanToVisibilityConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (value is bool && (bool)value) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value is Visibility && (Visibility)value == Visibility.Visible;
}
}

A workaround to disable the space that your popup control is not taking could be actually taking that space, and making the "unused" space transparent or partially transparent to get that nice message dialog effect.
For example, if your popup looks like a classic winrt message dialog (full width and vertically centered), make your popup control have the same width and height as your background and make the popup's content a grid with 3 row definitions. Place the actual content in the middle row, so it will be vertically centered. Then place a grid in the first row with black background color and opacity of 0.4, and with a rowspan of 3 so it will take all the space. Once you Open the popup, it will take focus over the whole background so the user cannot interact with it but still being able to see the background that the actual content doesn't overlap.
Here a simple example of what i say:
<UserControl ...>
<Popup x:Name="PopupControl"
IsLightDismissEnabled="False"
Loaded="PopupControl_Loaded">
<!-- The content of the Popup, a grid with 3 rows. The second row takes half of the space from the popup -->
<Grid x:Name="PopupGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Place a grid on the first row with black background, a rowspan of 3 will take all the rows so the user cannot interct with the actual background. -->
<Grid Grid.RowSpan="3"
Background="Black"
Opacity="0.4" />
<!-- Here place the actual content of your popup. -->
<Grid Grid.Row="1" Background="White">
[Acutal content of the popup]
</Grid>
</Grid>
</Popup>
</UserControl>
In the code behind of the user control:
// Finally make the popup control full screen.
private void PopupControl_Loaded(object sender, RoutedEventArgs e)
{
this.PopupGrid.Height = Window.Current.CoreWindow.Bounds.Height;
this.PopupGrid.Width = Window.Current.CoreWindow.Bounds.Width;
}

Related

How to handle ItemsControl size change correctly to show/collapse scroll buttons

I build a user control that should show a list of status indicators at the bottom of our application. I use an ItemsControl to create the list and enabled it to scroll horizontally via mouse wheel but also added two buttons (Left and Right) to replace the usual scroll bar (because the scrollbar would conflict with the look and feel and would be to big in this situation).
If there are not enough Items in the List or the control is wide enough to show all items, I want to collapse the buttons and of course show them again as soon as scrolling is needed.
Currently I use the ScrollViewer's SizeChanged event to detect if the width has changed and if any items of the ItemsControl are not visible so it needs scrolling. (See C# Code at the bottom of the post.)
My Issue is that it works fine as long as I change the size by gabbing the edge of the window with the mouse and resize it that way but it does not work as soon as the window size is programmaticaly changed or by double clicking on the window title to make it full screen (or use the maximize/minimize button).
This is my UserControl:
<Grid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<dx:SimpleButton x:Name="scroll_left_button" Grid.Column="0" Content="←"/>
<Border Background="#FF00ACDC" Grid.Column="1" BorderThickness="0">
<ItemsControl x:Name="items_control" w3ClientUi:ScrollViewerHelper.UseHorizontalScrolling="True"
ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="True" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer HorizontalScrollBarVisibility="Hidden">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- dummy template -->
<StackPanel.ToolTip>
<TextBlock Text="{Binding Name}"/>
</StackPanel.ToolTip>
<panda:PndLabel Padding="0 10 2 10" Content="{Binding Number}" FontSize="16" FontWeight="Normal"
Foreground="White" Margin="0 0 2 0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<!-- ItemsSource is set in Code -->
</ItemsControl>
</Border>
<dx:SimpleButton Grid.Column="2" x:Name="scroll_right_button" Content="→"/>
</Grid>
In Code behind I get the ScrollViewer instance from the ItemsControl as soon as it's loaded and then attach to the SizeChanged event.
When changing the window size via the window title or programmaticaly the event is thrown but the ScrollableWidth is not updated yet and therefore my buttons are still visible in full screen (or still collapsed when it gets smaller).
scroll_viewer.SizeChanged += (s, e) =>
{
if (!e.WidthChanged) return;
if (scroll_viewer?.ScrollableWidth > 0)
{
scroll_left_button.Visibility = Visibility.Visible;
scroll_right_button.Visibility = Visibility.Visible;
}
else
{
scroll_left_button.Visibility = Visibility.Collapsed;
scroll_right_button.Visibility = Visibility.Collapsed;
}
};
So, after coming back from the weekend with a fresh mind I figured that, in my case, handling the SizeChanged event is the wrong approach since all I actually need to know is if there are any items of my ItemsControl that need scrolling and if the number has changed.
In my question I already checked the ScrollViewer's ScrollableWidth property. It shows how many items are not visible and need scrolling, so it would be enough to check if it has changed and if it's new Value is greater than zero.
ScrollableWidth is a DependencyProperty so I thought about binding to it and listening to the changed event.
So what I did first is creating the new DependencyProperty on my UserControl
// Dependency Property is Private since I only need it internally
private static readonly DependencyProperty scrollable_width_property =
DependencyProperty.Register(nameof(scrollable_width), typeof(double),
typeof(MyUserControl),
new FrameworkPropertyMetadata(null) { BindsTwoWayByDefault = false, PropertyChangedCallback = property_changed_callback });
// Wrapper only has get because ScrollableWidth is read only anyway
private double scrollable_width => (double)GetValue(scrollable_width_property);
// Listening to the change
private static void property_changed_callback(DependencyObject dpo, DependencyPropertyChangedEventArgs args)
{
var o = dpo as MyUserControl;
o?.SetButtonVisibility((double)args.NewValue > 0);
}
I removed the scroll_viewer.SizeChanged event and instead created a new public method on my user control to change the button visibility.
public void SetButtonVisibility(bool visible)
{
if (scroll_viewer == null) return;
if (visible)
{
scroll_left_button.Visibility = Visibility.Visible;
scroll_right_button.Visibility = Visibility.Visible;
}
else
{
scroll_left_button.Visibility = Visibility.Collapsed;
scroll_right_button.Visibility = Visibility.Collapsed;
}
}
The last thing that has to be done is the actual binding.
I do it once, in the ItemsControl's Loaded event after obtaining the actual ScrollViewer.
var binding = new Binding(nameof(ScrollViewer.ScrollableWidth))
{
Source = scroll_viewer
};
SetBinding(scrollable_width_property, binding);
Now, whenever the ItemControl needs scrolling (or doesn't), the visibility of the buttons will change regardless of the size change. And now it also works when using the maximize/minimize buttons in the window title.
It's probably not the best implementation since it could probably better use style trigger in xaml instead of the SetButtonVisibility method but it gets the job done.
Edit:
In my case I also had to add a SetButtonVisibility(scroll_viewer.ScrollableWidth > 0); to the ItemsContorol's LoadedEvent because the callback is not triggered at startup.

Make XAML control with WebView full screen

Ultimate Goal
When a user clicks the Expand button, I want the WebContainerControl to be full screen, be focused, not allow scrolling in the ScrollViewer, and overlap the title grid (with the back button, page title, etc.)
Basically, it should be like clicking on a photo in a nice photo viewing app. Exapnd to full screen, have an X button in the top right corner and when you click it, it goes back to the regular view.
Problem
Since it's a WebView, I can't simply pass the view to a popup (It gives me an invalid args exception since the current browsing session can't be passed by reference... they logged in on a site, so it would be insecure I assume)
I have a XAML control with a webview in it:
<UserControl x:Class="App.WebContainerControl">
<Grid x:Name="grdWebContainer">
<StackPanel>
<Button Click="btnExpandView_Click"/>
<WebView x:Name="wvSite"/>
</StackPanel>
</Grid>
</UserControl>
Here is an example view it would be loaded into:
<Grid x:Name="grdMain">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Title Grid -->
<Grid x:Name="grdTitleBar" Grid.Row="0">
<TextBlock Text="App Title"/>
</Grid>
<!-- Web Views -->
<Grid Grid.Row="1">
<ScrollViewer>
<StackPanel>
<controls:WebContainerControl x:Name="First Site"/>
<controls:WebContainerControl x:Name="Second Site"/>
</StackPanel>
</ScrollViewer>
</Grid>
</Grid>
What I have so far
So far, when they press the Expand button, it makes the control full screen (using Current.Window.Bounds)
Then, I pass the event that the button is pressed to the main view:
private void OnAccount_Expanded(object sender, ExpandedEventArgs args) {
// Expanded button is pressed and control is made full screen
if (args.IsExpanded) {
// Hide titlebar
grdMain.RowDefinitions[0].Height = GridLength.Auto;
grdTitleBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
else {
// show titlebar again
GridLength gl = new GridLength(140);
grdMain.RowDefinitions[0].Height = gl;
grdTitleBar.Visibility = Windows.UI.Xaml.Visibility.Visible;
}
}
The Question
Right now, it makes it full screen, but I can still scroll. Any idea how to set the ScrollViewer to horizontally center on the control? If anyone has a better idea on how to achieve my Ultimate Goal, you would make me one happy camper! (Remember, it won't allow me to pass my control around, only manipulate it)
If I understand well, Put name on you Scroll Viewer
<ScrollViewer Name="uiScroll" >
............
</ScrollViewer >
When you doing full screen set visibility of you scrollBar
uiScroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;

Sometimes custom loading popup doesn't show

In my application loading popup is shown every time when I call It. But some times It just doesn't show and it is same situation. Popup is a custom UserControl object made with WPF.
Popup is in MainWindow.xaml:
<Viewbox Stretch="Fill">
<Grid>
<Grid x:Name="Body" Height="768" Width="1024" Background="{StaticResource SCBPassiveColor}" />
<src:InfoPane x:Name="InfoPaneMaster" Visibility="Collapsed" VerticalAlignment="Top" HorizontalAlignment="Center" />
</Grid>
</Viewbox>
In the Body of the main window application loads selected layout/view. Before new layout is loaded program calls :
LayoutCommands.DisplayInfoPane(msgLoginSuccess, ROPInfo.Info, null);
implementation:
public void DisplayInfoPane(string infoText, ROPInfo infoType, int? displayTime)
{
StopTimer();
SetTimer(displayTime ?? DefaultDisplayTime);
PrepareInfoPane(infoText, infoType);
colCloseIcon.Width = new GridLength(0);
this.Visibility = Visibility.Visible;
}
The popup automatically closes (sets visibility to collapsed) after default time.
Why sometimes this popup just doesn't show? Is this associated with rendering?

In Windows phone,How to change checkbox state after questioning user?

In my app,there is a need to do this
At start,the checkbox is unchecked
user tap,and then pop up a messagebox as a alarm to make sure user indeed want to do it(At the moment the checkmark is still collapse)
If user click "Yes,I want to do it",then checkmark is visible and now it is checked
vice versa
I found that,when I tap the checkbox,Checked event is always triggering
and
the checkmark is always turn to "checked" state
How to solve the problem???
Any advice would be great,Thanks!!!
Just a trick is needed. Sharing a sample with you.
overlap a transparent background grid over your checkbox with a transparent background like this.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<Grid>
<CheckBox Name="cb" Content="cb" Checked="CheckBox_Checked_1"/>
<!--Grid that overlaps the checkbox-->
<Grid Background="Transparent" Tap="Grid_Tap_1"/>
</Grid>
</StackPanel>
</Grid>
This overlapping wont call any checkbox event even if you tap on it
now in code of the event
private void Grid_Tap_1(object sender, GestureEventArgs e)
{
if(MessageBox.Show("Message")==MessageBoxResult.Ok)
{
cb.IsChecked=True;
}
}
Instead of Tap Event, Try Checked and Unchecked Events of the checkbox.
Note: You can track the checked status in "Checked" and "UnChecked" events of the Check Box using IsChecked Property and write your code in appropriate events.
After Asking confirmation to user.
If the user clicks "Yes" , set chkBox.IsChecked=true;
else
If the user clicks "No", set chkBox.IsChecked=false;
I think there is no way to stop checkbox default behaviors. So you can create a custom control with a image and a textbolck inside a stack panel. You should use pair of images for "Image" Control Source one for unchecked and another for checked.
//At start,the checkbox is unchecked
<StackPanel x:Name="panelCheckBox" Tap="panelCheckBox_Tap_1" Orientation="Horizontal">
<Image Source="UncheckImageSourc" x:Name="ImgeCheckBox"/>
<TextBlock Text="CheckBox Content"/>
</StackPanel>
In Code Behind
bool IsChecked=false;
private void panelCheckBox_Tap_1(object sender, System.Windows.Input.GestureEventArgs e)
{
//If user click "Yes,I want to do it",then checkmark is visible and now it is checked
if(!IsChecked)
{
IsChecked =true;
ImgeCheckBox.Source = "CheckImageSource";
}
else
{
IsChecked =false;
ImgeCheckBox.Source = "UncheckImageSourc";
}
}

Make Child control more Opaque than Parent

I have a Page like in the Xaml below which i want to use like a ModalDialog.
The Problem is that when I Pop the Dialog up, that the Opacity of the second Grid which holds the Content is not changed back to 100% and I see from the Page where it is Popuped the underlying controls. For more Detail see the Screenshot.
Is there a way that I can change back the Opacity of the second Grid to 100% that no control behind it can see through?
For completneness I have added the Code which i'm using to bring up the Popup.
ModalDialog Xaml:
<Page>
<Grid x:Name="RootPanel" Background="{StaticResource LucentBlue}" Opacity=".75">
<Border >
<Grid VerticalAlignment="Center"
Height="300" Background="{StaticResource PremiumBlue}" Opacity="1">
</Grid>
</Border>
</Grid>
</Page>
Code Behind Hosted Page:
private Popup _saveDialog;
private void SaveSettingsCommandLogic(object obj)
{
ModalDialog dlg = new ModalDialog();
dlg.CloseRequested += DlgOnCloseRequested;
_saveDialog = new Popup();
_saveDialog.Child = dlg;
_saveDialog.IsOpen = true;
}
Here's a solution in metro :
Please remove the Opacity property of both the elements and from the code behind of the ModalDialog class use the following code:
public ModalDialog()
{
this.InitializeComponent();
Color color = Color.FromArgb(150,255,0,0);
RootPanel.Background = new SolidColorBrush(color);
}
The method FromArgb is used to specify the transparency red green and blue values respectively and can rancge from 0-255 .. please test according to ur convinience :)

Categories

Resources