I have a XAML user control with a collection of buttons.
My XAML is as follows:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" Width="85"
>
<Grid Background="#7F010305" HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="Zoom" Grid.Row="0" Grid.Column="0" Width="40" Height="40" Margin="15,0,15,15" Click="OnClicked" Tapped="OnClicked" />
<Button x:Name="Pan" Grid.Row="1" Grid.Column="0" Width="40" Height="40" Margin="15,0,15,15" Click="OnClicked" Tapped="OnClicked" />
<Button x:Name="Contrast" Grid.Row="2" Grid.Column="0" Width="40" Height="40" Margin="15,0,15,15" Click="OnClicked" Tapped="OnClicked"/>
<Button x:Name="Brightness" Grid.Row="3" Grid.Column="0" Width="40" Height="40" Margin="15,0,15,15" Click="OnClicked" Tapped="OnClicked"/>
</Grid>
Somehow the click or the tap event is not getting raised. I tried various options but the Click or Tapped event is not getting fired.
Any hints?
From looking at your code I notice that you have both the Click and Tapped event handlers are pointing to the same method ("OnClicked"). These events, however, have different signatures for delegates. The Click event expects a method with signature (http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.primitives.buttonbase.click.aspx):
void ClickDelegate(object sender, RoutedEventArgs e)
while the Tapped event expects a method with signature (http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.input.tappedeventhandler.aspx):
void TappedDelegate(object sender, TappedRoutedEventArgs e)
So the signatures of the two methods aren't equivalent and it seems unlikely that you would be able to use the same method for both events since they require different delegate signatures (The code that runs behind the scenes to merge the logic in your xaml to your code behind should be looking for a method void OnClick(object, RoutedEventArgs) for your Click handler and a method void OnClick(object, TappedRoutedEventArgs) for your Tapped handler). Also if the runtime doesn't find a matching handler method (at least for wirnt in 8.1) I have found through testing that the event handler hook up will silently fail rather than throwing an exception (I am pretty sure that for WPF this causes an error, which makes it slightly confusing).
Long story short without being able to see your code behind my best guess is that OnClick doesn't have a signature that matches the delegate types of either the Clicked or Tapped event. Beyond that I am also wondering why you hooked into both Tapped and Clicked. Tapped is the generalized event that basically does the same thing as Clicked and then some (see Are Click, Tapped, and PointerPressed synonymous in WinRT-XAML?). I can't say for sure whether or not hooking into both of them may cause some weird issues (such as both the Clicked and Tapped being called for a single press) but it seems like you would probably just want to be subscribing to the Tapped event.
EDIT:
Just to add another point. Sometimes I have had it happen that even if you do everything right (where right here equals you have painstakingly double checked everything and it is all correct as far as you can tell) the event handler still doesn't work. Honestly I have only ever seen this happening when there are much more intricate combinations of components than what you have (such as those involving pretty much every custom type of thing you can imagine... custom panels, datatemplateselectors, itemtemplateselectors, etc) and am not sure if I am just constantly overlooking something from time to time or if there are legitimate bugs in the Microsoft code.
Anyway, the workaround is always to avoid hooking it up the event handler in the 'normal' way (like what you are doing here). To do this give the button a name and add the handler in the code behind (either by directly using the name if the button isn't in a template or by using GetTemplateChild from OnApplyTemplate to grab it if it is in a template). Then you can just do something like this for a button named 'foo':
foo.Tapped += (sender, args) => { /*do something here */ };
Related
I'm writing a .Net MAUI application and am using SwipeGestureRecognizer. This is all working great. But what I can seem to find is if you can detect where the swipe occurred.
.xaml
<Grid x:Name="myGrid" >
<Grid.GestureRecognizers>
<SwipeGestureRecognizer Direction="Right" Swiped="SwipeGestureRecognizer_Swiped" />
</Grid.GestureRecognizers>
...
.xaml.cs
private void SwipeGestureRecognizer_Swiped(object sender, SwipedEventArgs e)
{
...
}
But I specifically want to detect if you swipe in from an edge, primarily so I can show a popout menu on the edge. I can see nothing in the event args (of the Swiped event that I could use to detect where the swipe happened.
Consider the image attached. How can I tell (or detect) the difference between the wholly on-screen swipe action (green) from the off-screen swipe action (red). Some location parameters would be perfect, but they don't seem to exist.
I can't see anything in the MAUI docs to suggest this is even possible
Does anyone know if there is any way to achieve this, please?
Thanks?
It's not an elegant solution but you can place an invisible BoxView on the left:
<Grid>
<BoxView
HorizontalOptions="Start"
VerticalOptions="Center"
WidthRequest="40"
Color="Transparent">
<BoxView.GestureRecognizers>
<SwipeGestureRecognizer
Direction="Right"
Swiped="SwipeGestureRecognizer_Swiped"
Threshold="25" />
</BoxView.GestureRecognizers>
</BoxView>
<!-- your content -->
<VerticalStackLayout Margin="15,0,0,0">
<Button />
<Label Text="label" />
</VerticalStackLayout>
</Grid>
I have decreased the value of Threshold because the swipable distance is small.
Problem
This is the layout of my main pane:
<Page
x:Class="Communities.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Communities"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Loaded="Page_Loaded" DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="48" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
...
<SplitView Grid.Row="1" Name="hamburgerMenu" OpenPaneLength="200" PaneBackground="#F02A2A2A">
<SplitView.Pane>
<ListView ItemsSource="{Binding}" IsItemClickEnabled="True" ItemClick="HamburgerItemClick">
... </ListView>
</SplitView.Pane>
<Frame Name="frame" />
</SplitView>
<Grid Grid.RowSpan="3" Name="popupArea" />
</Grid>
</Page>
the frame is where I load all my pages, so that the layout is always consistant.
Now, in most of my child pages I have defined AppBar control and attached it to the BottomAppBar property of that child page:
PostView.xaml
...
<Page.BottomAppBar>
<CommandBar>
<AppBarButton Label="Back" Icon="Back" Click="TryGoBack" />
<AppBarButton Label="Refresh" Icon="Refresh" Click="TryRefreshComments" />
<AppBarButton Label="Go to Community" Icon="Go" Click="TryOpenCommunity" />
</CommandBar>
</Page.BottomAppBar>
...
Here's where the trouble starts. It works fine on PC, as the layout is mostly static on desktop. There are no software keyboards required most of the time etc. On mobile it's more problematic: Screenshots
My thoughts
It seems like the frame that is used to display the child page is causing all sorts of problems. When the AppBar is defined in the main page it positions correctly.
I'd like to avoid the keyboard covering the textbox as well as the AppBar but I don't want to get rid of the frame control. I'd also prefer it if the page got "squished" when the keyboard shows up, instead of getting pushed upwards, but I'm not sure how to display the keyboard on the frame level, instead of the entire MainPage, default level.
What would be the best way to solve this situation?
Cheers!
As you know, if we set the Page.BottomAppBar in the root of the Page, there is no issue with Touch keyboard. It seems it is the best way to add the Page.BottomAppBar.
If you want to add the Page.BottomAppBar in the other page in the Frame, you should be able to customize your UI. The UWP provides similar behavior on the appearance of the touch keyboard by handling the Showing and Hiding events exposed by the InputPane object.
We can use the InputPaneVisibilityEventArgs.OccludedRect to get the region of the application's window that the input pane is covering.
For example:
public PostView()
{
this.InitializeComponent();
InputPane.GetForCurrentView().Showing += PostView_Showing;
InputPane.GetForCurrentView().Hiding += PostView_Hiding;
}
private void PostView_Hiding(InputPane sender, InputPaneVisibilityEventArgs args)
{
MyTextBox.Margin = new Thickness(0, args.OccludedRect.Height, 0, 0);
}
private void PostView_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
MyTextBox.Margin = new Thickness(0, 0, 0, args.OccludedRect.Height);
}
I'm facing two issues with the code following while I'm making a simple chat app.
The code shows a textblock at the top of the page and two textbox stack at the bottom. Plus a listbox which will be auto height to fill the remaining gap.
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle Height="1" Fill="White" VerticalAlignment="Top"/>
<TextBlock Text="Hello World!" Grid.Row="0" FontSize="36"/>
<Listbox Grid.Row="1"/>
<TextBox Grid.Row="2"/>
<TextBox Grid.Row="3"/>
</Grid>
When I click on one of the top textboxes, the SIP keyboard becomes visible and all content in the page is pushed up. The main issue here is that the top textblock disappears and hides over the top. How can I keep it on top and not moving while the SIP keyboard is viewed?
When the most bottom textbox has focus, the SIP keyboard appears and pushes all content up. In this case, the keyboard will just fit and be sticky to that textbox. However, when the other textbox has focus, the keyboard will make a gap between them. How can I make the keyboard behave as it does when the most bottom one is focused?
When the keyboard pops and unpops, a TranslateTransform runs on the PhoneApplicationFrame, translating the whole screen up and down.
Based on this article, you should be able to get the value of the translation. As you can observe an animation moves the Y property from zero to a specific negative value (based on the control you took focus on).
Option 1: I have not been able to write a descent way of handling this value but you should be able to resize your controls to fit in what's left of the screen.
Option 2.0 (bad): You can cancel or remove this animation. The keyboard will be on top of the screen without any movement. Your turn now to move/resize your controls to fit the remaining space.
public MainPage()
{
this.InitializeComponent();
PhoneApplicationFrame frame = (App.Current as App).RootFrame;
var group = (frame.RenderTransform as TransformGroup);
group.Children.RemoveAt(0); // remove translate transform
}
Option 2.1: There's an issue with 2.0: removing the transform will prevent you from being notified about the keyboard. Setting up a reverse animation on your page's child when the Y property changes will "kind of cancel" the original translation.
<Grid x:Name="LayoutRoot" Background="Transparent" VerticalAlignment="Stretch">
<Grid.RenderTransform>
<TransformGroup>
<TranslateTransform />
</TransformGroup>
</Grid.RenderTransform>
static void OnRootFrameTransformChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
// ... edit from the blog article ...
MainPage page = source as MainPage;
page.lb.Items.Add(newvalue);
var oppositeTransform = (TranslateTransform)((TransformGroup)page.RenderTransform).Children[0];
if (newvalue < 0.0)
{
page.IsSipVisibleGuess.IsChecked = true;
oppositeTransform.Y = -newvalue;
}
else if (newvalue == 0.0)
{
page.IsSipVisibleGuess.IsChecked = false;
oppositeTransform.Y = 0;
}
I'm sorry none of these options will magically solve the problem but it may help you code what fits best for your app.
If you find a better solution out of this, please post it as an answer.
I have a full-screen Bing map control. Over the top, I want to overlay various other controls.
<Grid>
<maps:Map x:Name="Map" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Grid Style="{StaticResource LayoutRootStyle}" Background="Transparent"
x:Name="InnerGrid">
<Grid.RowDefinitions>
<RowDefinition Height="132" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="700" />
<ColumnDefinition Width="350" />
</Grid.ColumnDefinitions>
... Content ...
The trouble is that the InnerGrid consumes the mouse events which I need the map control to receive instead. Setting the background to transparent has done nothing useful.
So, I found the RoutedEvents stuff:
internal sealed partial class PageCodeBehind : Page
{
public PageCodeBehind()
{
InitializeComponent();
InnerGrid.AddHandler(PointerPressedEvent, new PointerEventHandler(OnPointerPressedEvent), true);
InnerGrid.AddHandler(PointerMovedEvent, new PointerEventHandler(OnPointerMovedEvent), true);
}
private void OnPointerPressedEvent(object sender, PointerRoutedEventArgs pointerRoutedEventArgs)
{
// I can hit a breakpoint here...
var peer = FrameworkElementAutomationPeer.FromElement(GigMap) as MapAutomationPeer;
peer.RaiseAutomationEvent(...);
So - I can capture the event, but I have no idea how to trigger the event on the Map control. Having looked at the automation peer stuff - it seems like they are concerned with higher-level concepts than mouse-down, such as open tool-tip etc.
Any idea how I forward all events from my InnerGrid control to the Map control?
Many thanks for any help,
Jon
Ok - I found a work-around. Setting Background="{x:Null}" on the InnerGrid makes it forward events. Beautifully undocumented as always on MSDN :-)
I'd still like to know any other methods available though if anyone knows more information.
Many thanks,
Jon
I‘m trying to create a page with Silver Light 4, that is similar in functionality to the main page at the Silver Light Showcase website (http://www.silverlight.net/showcase/).
Essentially I want to have buttons that change the view of the data in a Grid. One view might have just an image, another might have a smaller image with a smattering of data, and the third would be all the details.
I wondering if anyone has a recommendation of how to achieve this?
I would place a Border control inside of the Grid. Then on button click change the border.Child to the new view. You could define each view in a seperate UserControl xaml file.
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Border x:Name="contentFrame" />
<Button x:Name="changeViewButton" click="click_event" Grid.Row="1" Height="22" Width="150" />
</Grid>
// code behind
protected void click_event(object s, EventArgs e)
{
View1 view1 = new View1();
// add some code to decide which view to show, possible hold onto the view in memory etc.
this.ContentFrame.Child = view1;
}