We have a UWP application that uses a SwapChainPanel for rendering 2D content, we'd like to be able to drag and drop files on it.
First approach:
Firstly I just tried using the events on the SwapChainPanel itself, they never get called.
<SwapChainPanel x:Name="swap" AllowDrop="True" DragEnter="Swap_DragEnter" >
</SwapChainPanel>
Second approach:
I then tried putting a transparent rectangle in the SwapChainPanel. The drag events do work now, but the SwapChainPanel now doesn't receive any pointer events at all.
<SwapChainPanel x:Name="swap" >
<Rectangle Fill="Transparent" AllowDrop="True" DragEnter="Swap_DragEnter" />
</SwapChainPanel>
Third approach:
It seems the SwapChainPanel doesn't work like a normal XAML control, so I assumed I'd have to handle the drag events in the c++ code that runs the panel. But there doesn't seem to be any way of doing this, there are only references to the basic pointer events.
...
coreInput_ = renderPanel_.CreateCoreIndependentInputSource(deviceTypes);
coreInput_.PointerPressed({this, &InputManagerImpl::onPointerPressed});
coreInput_.PointerMoved({this, &InputManagerImpl::onPointerMoved});
coreInput_.PointerReleased({this, &InputManagerImpl::onPointerReleased});
coreInput_.PointerEntered({this, &InputManagerImpl::onPointerEntered});
coreInput_.PointerExited({this, &InputManagerImpl::onPointerExited});
coreInput_.PointerCaptureLost({this, &InputManagerImpl::onPointerCaptureLost});
coreInput_.PointerWheelChanged({this, &InputManagerImpl::onPointerWheelChanged});
...
So now I'm not sure how I can peform drag/drop operations? Thanks!
I think you could place your SwapChainPanel inside a Grid, and put the drag and drop onto the grid. You might loose interaction with your render scene though. And, make sure, since it's transparent, it accepts user input.
For example:
<!-- add attributes and drag and drop functionality on Grid -->
<Grid AllowDrop="True" DragEnter="Swap_DragEnter">
<SwapChainPanel x:Name="swap">
</SwapChainPanel>
</Grid>
Related
I have a canvas with a button that the user can press to add a new textbox to the canvas. How can I make it so the user can resize the text box by clicking and dragging on any of the corners of the textbox. Because the textbox is created in the C# code (not XAML), I would prefer code in C# not XAML.
Thanks
EDIT: My question is different than the one referenced because it is in UWP not WPF. These have very different controls. I would appreciate if you could translate the UWP information into UWP C#
You can use Thumb control instead of a textbox. The thumb control provides the functionality for you to write code to customize the drag and drop behavior. A simple code would be:
<Canvas x:Name="test">
<Thumb Width="100" Height="100">
<Thumb.Template>
<ControlTemplate>
<TextBlock HorizontalAlignment="Center" Text="12345"/>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Canvas>
A more complex sample could be found from this SO thread from Jay's answer. But please notice you need to customize the logic yourself in order to make it resize like what you need. The reference is just a direction.
I am creating a custom ToolBar control that I will be able to use in my WPF application.
My CustomToolBar control is based on a StackPanel control and will contain multiple CustomToolBarButton controls.
My CustomToolBarButtons are based on a vertical StackPanel and contain an Image control and a Label control.
I want to programmatically create a Click event for my CustomToolBarButtons that will fire when Image or label gets clicked. Unfortunately, neither Image nor Label controls have Click events in WPF.
It's a surprise for me because I am used to WinForms controls and vast majority of them have Click events by default. Do I have to create custom Image and Label controls and create Click events for them or is there a cleaner and simpler way of doing this?
Thanks for any help!
Well, there's not a great and simple way using standard functionality. I got around this by making my own trigger (derived from System.Windows.Interactivity.TriggerBase from the Blend SDK) so that in my projects I can do the following:
<Label>
<i:Interaction.Triggers>
<mu:MouseTrigger MouseButton="Middle" MouseAction="Click">
<i:InvokeCommandAction Command="{Binding Path=Close}" />
</mu:MouseTrigger>
</i:Interaction.Triggers>
</Label>
Effectively the MouseTrigger class will handle MouseDown and MouseUp events from the UIElement it's attached to and use that to invoke the actions associated with the trigger. The code is a bit more complex than just that, though, since I also do mouse capturing & I utilize an internal helper class so that I could add multiple triggers to the same element with only one instance of a helper class handling events & capturing the mouse for that element.
For the actual actions, I just use existing Blend or Prism actions such as InvokeCommandAction.
Here is the project if you're interested. It was too large to paste into this format. It uses some C# 6.0 features but you could easily modify it to work on an older version of C# by removing some null conditional operators. It requires you install the Blend SDK as it depends on System.Windows.Interactivity (should install with Visual Studio as long as you select that option). MouseTrigger is the publicly visible class that is the point of interaction with the functionality. MouseCatcher is the internal helper class mentioned.
I'd recommend not going down the route of custom controls, but rather of using some mechanism (this one or otherwise) to extend the existing functionality using the attached property framework that WPF and XAML bring to the table.
In WinForms you would create custom controls simply to get a nonstandard look, in WPF this is no longer necessary.
The WPF way: instead of making a Stackpanel's children implement Click behaviour, let's make a Button look like the desired Stackpanel.
Could do this setting the Content:
<Button>
<StackPanel >
<Image Source="C:\myFiles\myPic.png"/>
<Label HorizontalAlignment="Center">SomeTxt</Label>
</StackPanel>
</Button>
But this way it still looks like a Button, to overcome this we can set the Template instead:
<Button>
<Button.Template>
<ControlTemplate TargetType="Button">
<StackPanel >
<Image Source="C:\myFiles\myPic.png"/>
<Label HorizontalAlignment="Center">SomeTxt</Label>
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
Both solutions will raise a Click event clicking the image or label.
I just got started with an app for WP8.1, and encounter a problem with intercepting touch move events while leaving the original event treatment in place.
What I want to do is the following:
I have a ListView in a StackPanel in a ScrollViewer in a Grid. The ScrollViewer handles vertical scrolling of the StackPanel/ListView.
Whenever a horizontal touch move appears, I'd like to get a notification so I can adjust some ui element's position based on the horizontal movement.
Sounds simple enough, but any way I tried seems to cancel the original touch move treatment by the ScrollViewer, so the vertical scrolling is not working anymore. I'd really hate to implement the whole scrolling behavior myself ...
I tried already:
Putting a ManipulationMode="TranslationX" ManipulationDelta="handleXTranslation" on the ScrollViewer. The handelXTranslation handler is never called for whatever reason.
Putting the same Manipulation information on the ListView - now the handler gets called (and all handlers of the parent ui elements), but the ScrollViewer is not handling the scrolling anymore, probably because the ListView is not propagating the event to its parents anymore.
Adding a general touch handler to the xaml class when it is loaded. Same problem - either it is not called, and if it is called the scrolling of the ScrollViewer is not done anymore.
The XAML code looks like this (stripped of some data):
<Grid x:Name="LayoutRoot" Background="Transparent" ManipulationMode="TranslationX" ManipulationDelta="gridTranslationX">
<ScrollViewer x:Name="ScrollViewer" ManipulationMode="TranslationX" ManipulationDelta="scrollViewerTranslationX">
<StackPanel x:Name="StackPanel" Orientation="Horizontal" ManipulationMode="TranslationX" ManipulationDelta="scrollViewerTranslationX">
<ListView x:Name="ListView" ManipulationMode="TranslationX" ManipulationDelta="scrollViewerTranslationX">
</ListView>
</StackPanel>
</ScrollViewer>
</Grid>
And the handlers I tried to install in code look like this:
this.AddHandler(UIElement.ManipulationDeltaEvent, new ManipulationDeltaEventHandler(genericDeltaHandler), true);
ListView.PointerMoved += new PointerEventHandler(pointerEvent);
Is there any way to just observe the manipulation events without disturbing their normal treatment?
Sometimes it helps to talk about it ;-) ...
The answer was indeed as simple as adding the System value to the ManipulationMode on the ListView:
<ListView x:Name="ListView" ManipulationMode="TranslateX,System" ManipulationDelta="translationX">
I'm creating a WPF application that use the Bing Maps. I put it in a page control that at the same time is called from an iframe control. At the begining it displayed the Map and I can zoom in and out without a problem.
The thing is, that when I click the Map with the left button of my mouse what it does is to go down a little bit of the current location and a zoom in is done automatically instead of holding the point where the click was done to do a kind of drag and drop. Just like Google Maps does.
Here is my XAML code:
<Grid x:Name="LayoutRoot">
<TextBlock Text="News page" FontSize="32" />
<m:Map CredentialsProvider="..."
Center="25.6732109,-100.309201" ZoomLevel="12" Mode="Road"/>
</Grid>
I'm using the following assembly reference: xmlns:m="clr-namespace:Microsoft.Maps.MapControl.WPF;assembly=Microsoft.Maps.MapControl.WPF"
Does any one know how can I fix it?
Regards!
If you use the mouse up or down events on the Map control this will work fine. The map itself doesn't expose a Click event of it's own, but you don't need that if you use the mouse up/down events.
I had the same problem. The solution was to add a MouseDown Event to the map:
<m:Map
CredentialsProvider="<your Credentials>"
Center="{Binding Center, Mode=TwoWay}"
ZoomLevel="10"
MouseDown="Map_MouseDown">
</m:Map>
In the code behind you can add:
private void Map_MouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
This handles the event and no further processing is done. After this moving and draging the Map worked as usual maps do.
So I have a Panorama control and the PanoramaItems are programmatically added to the control using the following template.
<UserControl>
<Grid x:Name="LayoutRoot">
<controls:PanoramaItem Name="sitePanoramaItem" Header="{Binding Name}">
<Controls:DockPanel VerticalAlignment="Stretch">
<StackPanel Orientation="Horizontal" Margin="0,10,0,0" Controls:DockPanel.Dock="Top">
<Image Source="../Images/action.png" Width="64" />
<TextBlock Text="{Binding Stats, Mode=TwoWay}" FontSize="45" Margin="15,0,0,0" />
</StackPanel>
<Grid x:Name="graphCanvas" HorizontalAlignment="Stretch" Margin="10,10,10,10"> </Grid>
</Controls:DockPanel>
</controls:PanoramaItem>
</Grid>
</UserControl>
When I click on graphCanvas what I'd like to do is sorta pop the graphCanvas out and display that fullscreen then when I click again restore it to where it was. I've been all over this site and Google and can't find anything similar to what I'm looking for.
I would still like to maintain the Panorama control functionality so that the graphCanvas is still the only one visible but you can cycle through them. Currently I have it sorta working in that I remove the Grid from the DockPanel and put it directly in the LayoutRoot while making the sitePanoramaItem collapsed. However, it's not fullscreen as the Panorama name is still visible (I guess I could hide that as well...) When I put the graphCanvas back int he DockPanel the size of the canvas is all screwed up.
I was hoping there was a simpler way.
Is it even possible?
It is possible to create the UI you describe but it's not going to be simple. You're on the right track with removing it in code and adding it the LayoutRoot and making the Panorama hidden. However you would have to code the scrolling behavior yourself and that is going to be quite tricky - especially making it feel the way to panorama does.
One trick you could try is actually layer a PivotControl on top of your Panorama and have it be collapsed by default. Also edit it's template to remove all default content eg: remove the header control, set margins to 0, etc). Then when you want to go full screen you can remove all the graphCanvases from the Panorama items and and add them to new PivotItems in the PivotControl. Then hide the Panorama and show the Pivot. This will give you scrolling capability for free and the illusion of full screen.
Having said all that I'm not sure I would recommend this. The more common approach would be to simply be to navigate to another page when the user selects an item and handle the full screen aspects there (possibly using the Pivot control again for scrolling). And when you want to leave "fullscreen" mode simply navigate back to the first page. Handling Tombstoning of the fullscreen state will be much easier with this approach for one thing.
You can try making the graphCanvas a Page and putting it in a different XAML. Then add a frame (name it InnerFrame for example) in the same place where you have the graphCanvas right now and navigate to that page with InnerFrame. When the frame is clicked, you navigate with the RootFrame of the app to your graphCanvas page. When you decide to close it, just navigate back with the RootFrame.
Hope it's clear enough :)
Edit:
Navigation in WP7 works very similar as the standard navigation in Silverlight 4, but it's a bit more restrictive. Just throw a PhoneApplicationFrame in your XAML like this:
<phone:PhoneApplicationFrame x:Name="Frame" />
This is basically the same as a Silverlight frame. All the pages you create inherit from PhoneApplicationPage by default, so they can be showed in a frame without any changes.
Your whole application actually runs on a PhoneApplicationFrame. If you take a look at your App class you will see this:
public PhoneApplicationFrame RootFrame { get; private set; }
Here's the MSDN documentation for the navigation system on WP7