What alternatives do I have to flyout/ContentDialog? (c#, xaml) - c#

I currently have a program where you can load a text in it.
Now I created a button that Pops up a flyout/ContentDialog but Im not happy with it because Limits me of what Im trying to achieve.
When I click the button it opens a flyout, the flyout gets the full Focus. That means I cannot scroll to the text WHILE the flyout-box is open. And if I click outside the flyout-box the flyout-box disappears.
I have a similar Problem to the ContentDialog.
When I click the button and the ContentDialog Pops up, everything behind the ContentDialog goes a bit into White/Grey Color. Also the ContentDialog does not allow any Focus outside the ContentDialog itself.
So what do I want to have?
I want that when I click on the button that a Window appears. I should be able to customize the window (writing text in it and it should have a button).
While this Window is open I want to be able to do Actions outside that window without the window Closing. For example Scrolling through the text I loaded.
Is there something I can achieve this with?

Take a look at the Popup class. This will let you display content on top of other content within your app's window. It's similar to the Flyout but without all of the built-in Flyout behavior that you don't want. The Popup class documentation has more details and commentary on when and how to use it.
Here's a really bland example with no styling.
<Grid>
<Popup x:Name="popup">
<StackPanel>
<TextBlock Text="Poppity pop pop" />
<Button Click="ClosePopup_Click">Close</Button>
</StackPanel>
</Popup>
<Button Click="OpenPopup_Click">Open Popup</Button>
</Grid>
private void OpenPopup_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = true;
}
private void ClosePopup_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = false;
}
There is a slightly more complicated example in the Popup documentation

I just hide and show grids with whatever I want inside.

Related

How to focus on an element after button click

I'm relatively new to WPF and I am struggling to manage the focus of an element at runtime.
I have a simple user control with a TextBox inside
<UserControl [...]
IsVisibleChanged="UserControl_IsVisibleChanged">
[...]
<TextBox x:Name="myTextBox" [...] />
</UserControl>
That I added on my WPF window
<ctrl:MyPanel
x:Name="myPanel"
Visibility="{Binding MyBooleanProperty}"
Panel.ZIndex="999" />
MyBooleanProperty is changing at runtime under some logic and the panel is showing up accordingly.
I need to have keyboard focus on myTextBox everytime myPanel becomes visible so user can enter data without using mouse, tab key or anything else.
Here's the logic on the event handler of IsVisibleChanged
private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.Visibility == Visibility.Visible)
{
myTextBox.Focus();
myTextBox.SelectAll();
}
}
This works, but if I click any button on the window before myPanel becomes visible then I cannot set focus in myTextBox.
I've tried many things, for example setting
Focusable="False"
on the buttons with no luck.
Thanks in advance for your help!
After a little more searching I found a workaround based on this answer by Rachel:
Dispatcher.BeginInvoke(DispatcherPriority.Input,
new Action(delegate () {
myTextBox.Focus();
Keyboard.Focus(myTextBox);
myTextBox.SelectAll();
}));
Delegating the focus action actually works.

WPF Popup vs Tooltip

I have seen a lot of debate about when to use tooltip and when to use popup but I don't know which one is better for my case.
I have a button. When I click on it, the popup panel will appear and it has a lot of text and a small image (so it will be a quite big panel). The panel must stay there until I move my cursor OFF THE BUTTON (it must still close when the cursor is still on the panel but off the button).
<Button Click="clicked" MouseLeave="mouseleaved"/>
<Popup Name="mypopup">
<stuff>
</Popup>
private void clicked(object sender, RoutedEventArgs e) {
mypopopup.isopen = true;
}
private void mouseleaved(object sender, MouseEventArgs e) {
mypopup.isopen = false;
}
This is where I got to so far. The problem is that sometimes, the Popup appears on top of the button (which blocks the view of the button and so MouseLeave event kicks off, and Popup instantly disappears). I want the Popup to stay until i move the cursor away off the button.
So I did some google, and I think Tooltip may avoid this problem. But how to get Tooltip to appear on button click and not button hover?
Which one is better for me? Tooltip or Popup?
EDIT
I think I was not too clear with my question. I am asking which one i should use- Tooltip vs Popup based on MY SPECIFIC SITUATION (paragraph 2) and not in general. I think Popup is the right one to use but I have problems with using it (paragraph 3). so my question is can I solve this problem with Popup or should I use Tooltip better for this?
But how to get Tooltip to appear on button click and not button hover?
Handle the Click event for the Button and set the IsOpen property of the Popup to true:
private void Button_Click(object sender, RoutedEventArgs e)
{
popup1.IsOpen = true;
}
<Popup x:Name="popup1" StaysOpen="False">
<TextBlock>popup content...</TextBlock>
</Popup>
<Button Click="Button_Click" Content="op" />
Which one is better for me? Tooltip or Popup?
Popup is preferable whenever you want to customize the behaviour in any way.
Edit: If I understand your issue correctly, this should work:
<Button x:Name="button" Content="Button" Click="clicked" MouseLeave="mouseleaved"/>
<Popup Name="popup" PlacementTarget="{Binding ElementName=button}" StaysOpen="True" MouseLeave="mouseleaved">
<Border Background="Yellow">
<TextBlock>contents...</TextBlock>
</Border>
</Popup>
private void clicked(object sender, RoutedEventArgs e)
{
popup.IsOpen = true;
}
private void mouseleaved(object sender, MouseEventArgs e)
{
if (!button.IsMouseOver && !popup.IsMouseOver)
popup.IsOpen = false;
}

How to not focus element on application startup?

Simplest application possible:
<Page
x:Class="TestApp.MainPage"
...>
<Grid>
<TextBox />
</Grid>
</Page>
Question: is there any elegant way to prevent the cursor (focus) from being set in the TextBox on application start up?
To expand: My real issue is that I have a PopUp that is opened when the TextBox receives focus. If I click on an element in my PopUp it should close, but since the TextBox is the first focusable element in my page it automatically receives focus and thus the PopUp immediately opens again. The core of the problem I think is represented by the example above.
Focus is managed by various properties like IsTabStop, TabIndex, IsHitTestVisible, and the FocusManager class. There is built-in functionality to focus the first focusable element once the window is activated, and this behavior is generally not customizable.
We could designate a different element to be focused instead of the textbox like, say, the page itself:
<Page IsTabStop="True">
<TextBox/>
</Page>
This works in that the page gets initial focus instead of the textbox, but now the page participates in tabbing behavior, which is slightly undesirable.
Typically the framework will set focus to the RootScrollViewer when you click out of a focused control, even though the RootScrollViewer isn't a tab stop (so it can't receive focus by tabbing). If we can focus the RootScrollViewer upon page load, the framework will detect that something has focus and won't attempt to focus the first element.
<Page Loaded="onPageLoaded">
<TextBox/>
</Page>
private ScrollViewer getRootScrollViewer()
{
DependencyObject el = this;
while (el != null && !(el is ScrollViewer))
{
el = VisualTreeHelper.GetParent(el);
}
return (ScrollViewer)el;
}
private void onPageLoaded(object sender, RoutedEventArgs e)
{
getRootScrollViewer().Focus(FocusState.Programmatic);
}
This is the most "elegant" way that I know to prevent the textbox from getting focused automatically.

How to programmatically hide the keyboard

I have a textbox with a button inside (Telerik's RadTextBox with an Action configured).
When the user presses the Action, a progress bas is displayed, the screen goes dark, and some magic happens.
My problem is that since the action doesn't result in the textbox losing focus, the on-screen keyboard is not hidden, and keeps covering half the screen.
I would like to programmatically hide the on-screen keyboard, but don't know how.
Just set focus to the main page:
this.Focus();
this will focus a control that doesn't use the keyboard and thus hide the keyboard. Unfortunately there is no API to the keyboard to hide it.
Instead try disabling and then enabling the textbox in question in an appropriate place (like once a query has been submitted or an action triggered):
TextBox.IsEnabled = false;
TextBox.IsEnabled = true;
(Via https://stackoverflow.com/a/23905874/1963978)
Not clean, but it does the job (in Windows 10 mobile).
here lot solution is available for a Textblock only but in my case AutoCompleteBox
<toolkit:AutoCompleteBox Name="autoComplateTxt"
Grid.Row="4"
Margin="15,5,2,10"
Padding="0"
Height="65"
Text=""
BorderThickness="1"
BorderBrush="Black"
VerticalAlignment="Center"
DropDownClosed="autoComplateTxt_DropDownClosed"
/>
private void autoComplateTxt_DropDownClosed(object sender, RoutedPropertyChangedEventArgs<bool> e)
{
this.Focus();
}

Toolbar Overlay over WindowsFormsHost

I have a SWF object embedded in a WindowsFormsHost Control inside a WPF window.
I'd like to add a toolbar over the swf movie.
The problem with the snippet of code I have below, is that when the new child is added to the host control (or the movie is loaded, I haven't figured out which yet), the toolbar is effectively invisible. It seems like the z-index of the swf is for some reason set to the top.
Here is what it looks like:
XAML:
<Grid Name="Player">
<WindowsFormsHost Name="host" Panel.ZIndex="0" />
<Grid Name="toolbar" Panel.ZIndex="1" Height="50"
VerticalAlignment="Bottom">
[play, pause, seek columns go here]
</Grid>
</Grid>
C#:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
flash = new AxShockwaveFlashObjects.AxShockwaveFlash();
host.Child = flash;
flash.LoadMovie(0, [movie]); // Movie plays, but no toolbar :(
}
Any insight on this issue would be much appreciated.
Update: Since no suitable answer was posted, I've placed my own solution below. I realize this is more of a hack than a solution so I'm open to other suggestions.
Here is my hackaround the WindowsFormsHost Z-index issue.
The idea is to place whatever you need to be overlayed nested inside a Popup. Then to update that popup's position as per this answer whenever the window is resized/moved.
Note: You'll probably also want to handle events when the window becomes activated/deactivated, so the pop disappears when the window goes out of focus (or behind another window).
XAML:
<Window [stuff]
LocationChanged="Window_LocationChanged"
SizeChanged="Window_SizeChanged" >
<Grid Name="Player">
[same code as before]
<Popup Name="toolbar_popup" IsOpen="True" PlacementTarget="{Binding ElementName=host}">
[toolbar grid goes here]
</Popup>
</Grid>
</Window>
C#:
private void resetPopup()
{
// Update position
// https://stackoverflow.com/a/2466030/865883
var offset = toolbar_popup.HorizontalOffset;
toolbar_popup.HorizontalOffset = offset + 1;
toolbar_popup.HorizontalOffset = offset;
// Resizing
toolbar_popup.Width = Player.ActualWidth;
toolbar_popup.PlacementRectangle = new Rect(0, host.ActualHeight, 0, 0);
toolbar_popup.Placement = System.Windows.Controls.Primitives.PlacementMode.Top;
}
private void Window_LocationChanged(object sender, EventArgs e)
{ resetPopup(); }
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{ resetPopup(); }
Another solution I've discovered is to use Windows Forms' ElementHost control. Since I'm using a Windows Form inside a WPF window anyway, why not just use an entire Windows Form and save myself Z-Issue headaches.
The ElementHost control is really useful, because I can still use my toolbar UserControl, and embed it inside the Windows Form. I've discovered that adding a child can be finicky with Windows Forms, so here's a snippet describing the solution:
First, toss in the ActiveX object, then an ElementHost Control, using the designer.
Form1.Designer.cs:
private AxShockwaveFlashObjects.AxShockwaveFlash flash;
private System.Windows.Forms.Integration.ElementHost elementHost1;
Form1.cs
public Form1(string source)
{
InitializeComponent();
toolbar = new UserControl1();
this.elementHost1.Child = this.toolbar;
this.flash.LoadMovie(0, source);
}
Note that the child was not set in the designer. I found that for more complex UserControls the designer will complain (though nothing happens at runtime).
This solution is, of course, still not entirely ideal, but it provides the best of both worlds: I can still code my UserControls in XAML, but now I don't have to worry about Z-indexing issues.

Categories