WP7: Rotating a popup + content? - silverlight

I've been googling this issue for some time now, but havent been able to find a solution that worked for me.
The thing is I have a popup control with a user control, in which the user can enter a new value for a listpicker. This all works fine in portrait mode, but if the phone is rotated (emulator), the popup remains in portrait mode. Opening the popup when phone is already in landscape, has no effect either.
Is there any way to correct this issue? I've seen some people suggesting using Rotatetransform, but if I do this on a textbox etc., it disappears completely :/

I think this is potentially a bug in the Popup control; I've certainly heard the question asked before. However, I've also heard that the performance of the Popup controls is not that great, so I think you'd be better off just using a regular framework element (such as a Grid) to contain your popup content and show/hide it (with animation if appropriate) accordingly. At least that way it will get rotated properly when the page orientation changes.

Do not rorate the popup but place a border inside the popup and load the content in the border.
I got it to work like this:
//In .xaml
<Popup x:Name="myPopup">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="480" />
</Grid.RowDefinitions>
<Border x:Name="popupBorder"/>
</Grid>
</Popup>
//In .xaml.cs
popupBorder.Child = new MyPopupPage(); //MyPopupPage is the "Windows Phone Landscape Page"
myPopup.IsOpen = true;

Related

WindowStyle None and touch input

In Windows 10, when using touch device like Surface, touching an input control like a TextBox in a not maximized window, causes moving the whole window up, so that the user can see what he is typing (if keyboard is docked). But it does not happen when WindowStyle is set to none. Why it does not happen? We need this behavior in our app. Can it be fixed on WindowStyle=None? I found it's not connected with it's style - there are no build in triggers or something. We need WindowsStyle=None for custom close button bar (we want the bar to be transparent, only the button is visible).
I faced a similar issue trying to get my application to react to the presence of the Windows 10 touch keyboard properly, but it wouldn't do so unless WindowStyle was set to something other than None.
Struggled with it for a while, until I decided to just try and style the Window myself and removing the borders manually, which led me to discover the WindowChrome class.
The WindowChrome documentation mentions this about WindowStyle="None":
One way to customize the appearance of a WPF application window is to set the Window.WindowStyle property to None. This removes the non-client frame from the window and leaves only the client area, to which you can apply a custom style. However, when the non-client frame is removed, you also lose the system features and behaviors that it provides, such as caption buttons and window resizing. Another side effect is that the window will cover the Windows taskbar when it is maximized. Setting WindowStyle.None enables you to create a completely custom application, but also requires that you implement custom logic in your application to emulate standard window behavior.
So it seems that because this non-client (or OS) frame is missing, it causes the application to not be able to react to the keyboards presence.
The solution is to implement a custom WindowChrome. This can be done like this:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
Title="MainWindow" Height="350" Width="525" WindowState="Maximized">
<shell:WindowChrome.WindowChrome>
<shell:WindowChrome NonClientFrameEdges="None"
UseAeroCaptionButtons="False"
CornerRadius="0"
GlassFrameThickness="0"
ResizeBorderThickness="0"
CaptionHeight="0" />
</shell:WindowChrome.WindowChrome>
<Grid Background="DarkOrange">
<TextBlock Text="TEST" VerticalAlignment="Center"
HorizontalAlignment="Center" FontSize="32" />
</Grid>
</Window>
If you absolutely must use WindowStyle="None", then according to the documentation above, the Window logic must be custom. Fortunately there's a nice example from Microsoft on how to write custom logic to react to the presence of a touch keyboard: See this link.
If you would like to add your own custom buttons to the title bar, check out this excellent post about styling your Window.
Hope this helps!
UPDATE:
After further investigation, it turned out that this solution only worked on Windows 10 version 1903. When tried on 1809 which we use in production, it didn't work. The reason is that apparently Microsoft have changed the way applications react to the touch keyboard when in full-screen mode.
This can be easily tested by maximizing Explorer in both versions of Windows, and to see how in 1809 nothing happens, but in 1903 the Window is resized to fit the remaining space on the screen.
Another important thing I noticed is that when I start the application from Visual Studio (whether debugger is attached or not), when the touch screen shows up, the UI doesn't react to it, but when I run the executable from explorer, then it does work. So in my testing I would always build, then go to bin\Debug, and start the exe from there.
Take the Grid Layout divide it into 3 rows and add the one custom button to the top right corner of row and on that button event handler do the Window closing code and same for minimizing
and Set the WindowStyle=none

Click through semit transparent WPF application

I created a WPF application that has an overlay mode. In this mode, the whole application gets semi transparent. I'd now like to be able to click through this window to operate with elements behind it [other program UI's, desktop icons etc.]
I wonder if there is the possibility to configure the window right away to represent this behaviour. I set up my application window like this:
WindowStyle="None" AllowsTransparency="True" Opacity="0.5" Background="Black" IsHitTestVisible="True" Focusable="True" IsTabStop="False"
If I set the Background to x:Null or Transparent, I can click through the application. However, the application is not visible at all any more then.
If this is not possible directly, I thought about another solution:
When clicking on the Application, minimize it, execute another mouse click, and then maximize the application. I found some example code for a global mouse click which looks like this:
MouseEventArgs e = new MouseEventArgs(Mouse.PrimaryDevice, 0);
e.RoutedEvent = Mouse.MouseEnterEvent;
youUIElement.RaiseEvent(e);
// Or
InputManager.Current.ProcessInput(e);
However, I think this will not work when trying to do double-clicks.
So, general desire in a few words:
Semi-transparent WPF application, always on top, click-through. Also Keyboard input should pass through.
I set up a special hotkey that brings the application back.
Any helps / ideas?

WP7/Silverlight: Inactive Buttons inside a ScrollViewer with IsHitTestVisible=False… inside a Pivot

I was making some good progress on my App, but ran into a problem that's stumped me. I was hoping someone could offer their expertise?
My app is intended to be a "scoresheet"... one of the PivotItems features a ScrollViewer (Horizontal scrolling, vertical disabled), with a Horizontal-orientation StackPanel inside. This StackPanel contains a "ScoreSheet" UserControl, which is basically a Grid with various text-boxes on it. So... kind of like this (except the ScoreSheet items are added to the StackPanel programmatically):
<controls:PivotItem>
<controls:PivotItem.Header>
<TextBlock Text="score sheet" FontSize="45" Height="80" />
</controls:PivotItem.Header>
<ScrollViewer Width="470" Height="560" VerticalAlignment="Top" x:Name="sv_scoresheets" MaxHeight="560" MinHeight="560" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled" IsHitTestVisible="False">
<StackPanel Name="sp_scoresheets" Orientation="Horizontal">
<local:ScoreSheet></local:ScoreSheet>
<local:ScoreSheet></local:ScoreSheet>
<local:ScoreSheet></local:ScoreSheet>
</StackPanel>
</ScrollViewer>
</controls:PivotItem>
The concept was that "Previous" and "Next" buttons are in the ApplicationBar at the bottom of the page, and they trigger an Animation of the ScrollViewer left or right (ie. Current Round * Width of ScoreSheet). By having "IsHitTestVisible" set to "False" on the ScrollViewer, a user can't manually move the displayed ScoreSheet to a weird position, and swiping left/right between PivotItems still works as expected.
That all worked nicely. :)
However... the problem is on the ScoreSheet control, I want a few Buttons and TextBoxes so the user can enter in a score into the grid. By having "IsHitTestVisible" on the ScrollViewer, the taps/etc. just get ignored.
I tried setting "IsHitTestVisible" to "True" and instead running a function on the ScrollViewer's ManipulationStarted event (calling "e.Complete()")... but although that lets me access controls inside the ScoreSheet, I can't swipe left/right between PivotItems anymore.
So… can anyone help? I was thinking maybe I could refine the ManipulationStarted behavior somehow, maybe "passing along" the action to the Pivot control instead of having the ScrollViewer move? Or some other way I can make the ScrollViewer "inactive" but allow the controls within to be interactive?
I'd really appreciate any help.
Thanks for your time!
Firstly, I would say that your intended usage of the scrollviewer breaks the intended design of the scrollviewer and the pivot (a common mistake windows phone developers, including myself, have made). The main reason this is generally considered a bad practice is that it implements a side ways navigation paradigm that is intended to only be provided by the Pivot control and the Panorama control.
With that said, it doesn't mean your particular use is 100% bad, I think that there are times when breaking the rules is okay. I would just encourage you to do some research and really make sure you're not going to confuse the user, or force them to learn a navigation paradigm that they are not already familiar with through the phone's operating system, and apps that properly make use of the controls provided by the SDK.
Okay, so now that's out of the way, if you determine this really is the best design for your app, you'll need to do the following to accomplish what you want:
Instead of Using a Horizontal ScrollViewer, use a Pivot control inside your Pivot control
You'll need create a header template that is essentially empty so that you don't take up any space in the upper area of inner scrolling section.
This also makes a lot more sense because the horizontal scrolling you are trying to accomplish is by "section" instead of a continuous scroll. This saves you the trouble of having to think about exactly how many pixels you are scrolling (instead you can just use XAML to change the width of your PivotItems
Disable the scrolling functionality of the pivot scroll by the user
This can be done a number of different ways of varying complexity, and almost warrants a question on it's own. See here for one way to accomplish this.
Another thing to do (which gives you more control) is to capture the ManipulationStarted, ManipulationDelta, and ManipulationCompleted events on the inner pivot item. if you detect the delta manipulation containing a horizontal component, then inside the method handler for the ManipulationDelta event, set e.Handled = true. To cancel the inner Pivot's ability to handle the horizontal scrolling. That will look something like the following:
// Event handler for ManipulationDelta event on your inner Pivot control
public void OnManipulationDelta(ManipulationDeltaEventArgs e)
{
if(e.DeltaManipulation.Translation.X != 0)
e.Handled = true;
}
As you will discover, this can provide some odd behavior. Ideally, you'll want to figure out what works best for your app, but typically you want to check for more than just != 0 on the X component, and allow the user some little bit of x, just incase they hit the control at a weird angle such that the X component has a value of 1.
Implementing the buttons to move to the right or the left:
This should be pretty simple, just make use of the Pivot.SelectedIndex property.
However, in most cases, this is a bad idea. Be REALLY sure you are a good exception to standard practice (preferably by giving your app to someone who has never used it but owns a windows phone, and see if they intuitively understand how to use your app.
Many thanks to Paul for his input and advice. A Pivot offered some extra flexibility, but still had similar issues to the ScrollViewer control when IsHitTestVisible="False" (in that buttons and other controls on the contained elements would become unusable). Also, aesthetically for this app, I found I preferred the multiple ScoreSheets being right next to each other when the Previous/Next buttons were pressed and they were animated to show the new sheet (as PivotItems, one would scroll out of view before the next scrolled into place).
After some more thought and experimentation, I achieved the desired effect like this:
<Canvas Width="470" Height="560" VerticalAlignment="Top" MaxHeight="560" MinHeight="560" MinWidth="470" MaxWidth="470">
<Canvas.Clip>
<RectangleGeometry Rect="0,0,470,560" />
</Canvas.Clip>
<StackPanel Name="sp_scoresheets" Orientation="Horizontal" CacheMode="BitmapCache">
<local:ScoreSheet /></local:ScoreSheet>
<local:ScoreSheet /></local:ScoreSheet>
<local:ScoreSheet /></local:ScoreSheet>
</StackPanel>
</Canvas>
The "Canvas.Clip" let me hide the ScoreSheets on either side of the currently visible one, and I could animate the Canvas.Left position of the StackPanel when the Previous/Next buttons were pressed.
By avoiding the ScrollViewer or Pivot, there were no events to handle/override, and the controls in the StackPanel could then be accessed as I intended.
'hopefully that might be of help to others. :)

Lightbox-style popup in WPF -- how?

(I am trying to learn WPF using tutorials and documentation, and trying to develop a user interface for my backend-complete application while I do say. I've heard people say that the learning curve is quite steep. But sometimes I wonder whether what I'm trying to do is actually something that's hard to do in WPF, or if it's simple but I'm thinking in wrong terms, or if it's neither, it's quite simple but I just happen not to know how.)
Here's my current question. I wanted clicking that clicking some part of my UI will bring up a 'popup' where the user can enter more information. I would like a 'lightbox-style' popup, i.e. the popup is modal to the page, it darkens the rest of the page to become the center of attention, etc. These are seen commonly on Web sites.
A bit of searching led me to the WPF Popup control. I added it, put my content in, set the IsOpen property to True, and -- presto! A popup. Then I added an invisible Rectangle that covers my whole window, and set it to Visible as well when I want my popup to open. Great!
So now I wanted to do this dynamically, because sometimes I will be loading a record which will sometimes have a need to open another control (a UserControl) in a popup to edit its information. So I made myself a method called OpenPopup. But I can't seem to find a way to write this method using WPF. In Windows Forms I'd have written: (I use VB.NET)
Sub ShowPopup (form as Form, ctrl as Control)
'Create 'rect' as new dark rectangle control
'Z-order it to the top
'form.Controls.Add 'rect'
'form.Controls.Add ctrl
'Z-order 'ctrl' to the top
'Center 'ctrl'
'Set focus to it
End Sub
But with WPF I run into problems:
1) I can't add it to the WPF window, because it already has a child.
2) If that child is a Canvas, that's not too bad. I can detect that, and add it to the Canvas. I have to find some way to set its Left, Top etc. properties and Width and Height, since those do not seem to be properties of the Rectangle control but rather extended by the Canvas object -- in XAML they're called Cavnas.Top etc. but Intellisense is not showing them when I try to use it in code.
3) But if it's a StackPanel? Then my rectangle will just be stacked below the other controls! And not covering them! Is there a way around this?
4) And if the window contains only one control and no container control at all?
5) I think there were more problems I ran into. But let's start with these.
Thanks in advance for your help.
1) I can't add it to the WPF window, because it already has a child.
Ah, the evils of codebehind. The solution is not to add it to the visual tree, it is to place it in the visual tree, ready and waiting to pounce, but hide it from the user's view.
Here's a sample you can drop in Kaxaml that demonstrates the point. Set the Lightbox Grid's Visibility to Hidden to access the hidden content.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Viewbox>
<TextBox Text="SIMULATING CONTENT" />
</Viewbox>
<Grid x:Name="Lightbox" Visibility="Visible">
<Rectangle Fill="Black" Opacity=".5"/>
<Border
Margin="100"
Background="white"
BorderBrush="CornflowerBlue"
BorderThickness="4"
CornerRadius="20">
<Viewbox Margin="25">
<TextBox Text="SIMULATING LIGHTBOX"/>
</Viewbox>
</Border>
</Grid>
</Grid>
</Page>
2) (snip) Intellisense is not showing them when I try to use it in code.
Canvas.Top etal are Attached Properties. Attached Properties are extremely convenient and easy to use in XAML, but they are very confusing and hard to use from code. Another reason why codebehind is evil.
3) But if it's a StackPanel? Then my rectangle will just be stacked below the other controls! And not covering them! Is there a way around this?
I redirect you back to 1. There are also many other container controls in WPF. You should investigate them and observe how they control layout. For instance, my use of the Grid was not to make use of its ability to block off sections of UI for controls, but for its ability to layer controls ontop of each other and to stretch them out to their maximum available size for the available space (the viewboxes are just there to zoom the controls instead of stretch them).
4) And if the window contains only one control and no container control at all?
The root of a window would almost always be a container control. But you control that, so if you needed to add controls to the visual tree at runtime you could easily ensure the child of the window is a container control you could deal with.
5) I think there were more problems I ran into. But let's start with these.
No kidding. My number one suggestion for people in your situation is to drop what you're doing and learn about MVVM. The Model-View-ViewModel is a very simple way to code WPF applications that takes advantage of many of the features of WPF--databinding, templating, commands, etc. It allows you to code your logic not in codebehind (RETCH) but in easy to create and test classes.

WPF Notifications

How can I create notifications for my WPF apps, like those on browsers where they show messages via a "toolbar" at the top of the browser or a "MSN" style notification via a popup that slides up/down on the bottom right of the screen. Maybe a panel that fades in/out at the center of the app will do to
Your question is a little vague, in that with WPF, your options here are really only limited by your imagination.
Here are some options:
MessageBox
This is the simplest option - if you want to notify your user with a simple message that he must acknowledge to continue, then just show a message in a MessageBox.
Roll Your Own Dialog
If MessageBox doesn't quite do it, and you want to show more or different kinds of information, then you can simply create a new Window, and open it with the ShowDialog() method, forcing the user to close it (acknowledge it) before proceeding.
StatusBar
If you simply want to convey information, you can just add a StatusBar to the bottom of your dialog. I've linked to a nice example from fellow SO'er Kent Boogaart. Note that you aren't limited to just text in a StatusBar - you can add any UIElement to it, so you could have images, progressbars, whatever.
Some Other Panel
You could also have another panel of some sort (using your example, a StackPanel or something at the top of your application) that has Visibility set to Collapsed unless it is needed. You could also have, for example, a Border with some content in it, that shows up in front of the rest of the UIElements in your dialog. You can use a PopUp control.
If you go the "extra panel" route (which perhaps sounds most in line with what you are asking), then it may be nice to do some tricks with animations to add just a little flash to your app. Stuff like sliding the panel into place, or animating the opacity, etc. If you are putting the information over the rest of your window content, you can also play with the Opacity to make the panel semi-transparent - dark enough to see and read, but also allowing the user to see a little bit of the window behind it.
Here's a very basic example of what I mean. I'll leave it as an exercise for the user to add any formatting, slick animations, handle multiple messages, etc.
<Window ...>
<Grid x:Name="gridMainLayout">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel x:Name="stackNotificationArea"
Grid.Row="0"
Orientation="Horizontal"
Background="LemonChiffon"
Visibility="Collapsed">
<TextBlock x:Name="txtMessage"
Text="{Binding NotificationMessage}" />
<Button x:Name="btnAcknowledge"
Content="Acknowledge" />
</StackPanel>
<!-- Rest of your window goes here -->
<Grid x:Name="gridContent"
Grid.Row="1">
<!-- Content of window -->
</Grid>
</Window>
In the above example, I assume that there is a property called NotificationMessage that returns the latest notification message. You could hard-code this in text, or whatever. It would probably be best to bind the Visibility of the StackPanel as well, based on if there were any notifications. In any case, you will have to toggle the StackPanel to Visible as needed. Setting it to Visible will automatically move the content of your window down, as you described.
Be sure to set Visibility to Collapsed when the message is acknowledged. If you set it to Hidden, the StackPanel will not be shown, but the real estate will still be held for it (i.e. there will be a blank space at the top of your application).
Of course, you can be as fancy as you need to be here - you could have a small listbox with all the messages, or a couple of buttons to scroll through messages, or a button to launch a window with all messages, or...

Resources