Drop event not firing on wpf grid - c#

I'm trying to develop an ancient form of chess, Chaturaji, as an assignment for school. I've got some very basic xaml setup that should allow me to drag and drop an image element within a grid.
<Page
x:Class="Projectg.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Projectg"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid AllowDrop="True" Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition>
</ColumnDefinition>
<ColumnDefinition Width="900">
</ColumnDefinition>
<ColumnDefinition>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="900"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid Background="Transparent" x:Name="grdGrid" AllowDrop="True" Grid.Column="1" Grid.Row="1" Drop="grdGrid_Drop" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image CanDrag="True" x:Name="Image" Canvas.ZIndex="1" Height="80" Width="80" Grid.Row="0" Grid.Column="0" Source="/images/boat.png" DragStarting="Boat_DragStarting" Drop="Boat_Drop" DragOver="Image_DragOver" ></Image>
<Image CanDrag="True" Canvas.ZIndex="1" Height="80" Width="80" Grid.Row="1" Grid.Column="0" Source="/images/horse.png" ></Image>
<Image Canvas.ZIndex="1" Height="80" Width="80" Grid.Row="2" Grid.Column="0" Source="/images/elephant.png" ></Image>
<Image Canvas.ZIndex="1" Height="80" Width="80" Grid.Row="3" Grid.Column="0" Source="/images/crown.png" ></Image>
<Image Canvas.ZIndex="1" Height="80" Width="80" Grid.Row="0" Grid.Column="1" Source="/images/pawn.png" ></Image>
<Image Canvas.ZIndex="1" Height="80" Width="80" Grid.Row="1" Grid.Column="1" Source="/images/pawn.png" ></Image>
<Image Canvas.ZIndex="1" Height="80" Width="80" Grid.Row="2" Grid.Column="1" Source="/images/pawn.png" ></Image>
<Image Canvas.ZIndex="1" Height="80" Width="80" Grid.Row="3" Grid.Column="1" Source="/images/pawn.png" ></Image>
</Grid>
</Grid>
</Page>
When I try to drag the image over the grid the mouse shows the “Drop Not Allowed” cursor and releasing the image does not fire the Drop event. I asked a teacher about this and she said it was probably because I did not set a background for my grid.
I quickly updated the code, but no luck, the event still did not fire. She didn't really know what was going on and told me to email her if the problem persisted.
I thought I would ask here first.
Thanks in advance for any help.

A quick glance at the MSDN UWP Drag and Drop page suggests that you need to handle the DragOver event, and indicate what drop operations the control will accept (true in any form of XAML and IIRC winforms etc. as well). In UWP, that's the AccepttedOperation property on the event args object (WPF calls that property Effects and it's a different enum type):
private void Grid_DragOver(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Copy;
}

Related

Drag and Drop a control between grid cells within an Windows 10 Universal App

What I try to achieve is being able to drag an image from one cell and drop it into another cell in the same grid. This grid in xaml is defined as below:
<Grid Grid.Row="1" HorizontalAlignment="Center" AllowDrop="True" VerticalAlignment="Center" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Margin="10,10,10,10" CanDrag="True" Grid.Row="0" Grid.Column="0" Source="Assets\mock.png" Width="64" Height="64" DropCompleted="Image_DropCompleted"/>
<Image Margin="10,10,10,10" CanDrag="True" Grid.Row="1" Grid.Column="1" Source="Assets\mock.png" Width="64" Height="64" DropCompleted="Image_DropCompleted"/>
<Image Margin="10,10,10,10" CanDrag="True" Grid.Row="2" Grid.Column="2" Source="Assets\mock.png" Width="64" Height="64" DropCompleted="Image_DropCompleted"/>
</Grid>
When I drop an image from one cell to another, Image_DropCompleted is triggered, and I can use static function in Grid to set the row and column index.
So my questions is how to calculate these indexes from current mouse position?

TextBox/Grid overlapping ComboBox entries

I'm using Visual Studio 2013 and I wrote some code for Windows Phone 8.1 Apps in C#. Now I've got a little problem with the layout in XAML with grids.
Elements in grids should be ordered/layered in the order in the code, but this didn't work for me. I've got two grids in a grid and the comboboxlist of the first grid is overlapped by the other grid/textblock. I tried to rearrange the grid in XAML, but that also did not solved the problem.
overlapping image from the app
In this image there should be 2 more items in the open combobox list, but those are overlapped by the grid below it.
Here is the code snippet:
<Grid Margin="0, 50, 0, 0">
<Grid.RowDefinitions>
<RowDefinition Height="115"/>
<RowDefinition Height="80"/>
<RowDefinition Height="80"/>
<RowDefinition Height="115"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--Third Row-->
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Style="{StaticResource StandardAppHeaderTextBlock}"
Text="Woche:"/>
<ComboBox Name="WochenComboBox"
Grid.Column="0"
Style="{StaticResource StandardAppComboBox}"/>
<TextBlock Grid.Column="1"
Style="{StaticResource StandardAppHeaderTextBlock}"
Text="Ort:"/>
<TextBox Name="OrtTextBox"
Grid.Column="1"
Style="{StaticResource StandardAppTextBox}"/>
</Grid>
<!--Second Row-->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Style="{StaticResource StandardAppHeaderTextBlock}"
Text="Stunde:"/>
<ComboBox Name="StundenZeitenComboBox"
Grid.Column="0"
Style="{StaticResource StandardAppComboBox}"
ItemsSource="{Binding Einstellung, Converter={StaticResource EinstellungsStundenToComboBoxListConverter}}"
DisplayMemberPath="Value"
SelectionChanged="StundenZeitenComboBox_SelectionChanged"/>
<TextBlock Grid.Column="1"
Style="{StaticResource StandardAppHeaderTextBlock}"
Text="Veranstaltungsart:"/>
<ComboBox Name="VeranstaltungsartComboBox"
Grid.Column="1"
Style="{StaticResource StandardAppComboBox}"/>
</Grid>
</Grid>
What should I use/do to remove this overlpapping.
Use stack panels. Items inside a stack panel will not overlap.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="115" />
<RowDefinition Height="80" />
<RowDefinition Height="80" />
<RowDefinition Height="115" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--Third Row-->
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Text="Woche:" />
<ComboBox Name="WochenComboBox" Grid.Column="0" />
</StackPanel>
<StackPanel Grid.Column="1">
<TextBlock Text="Ort:" />
<TextBox Name="OrtTextBox" Grid.Column="1" />
</StackPanel>
</Grid>
<!--Second Row-->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Text="Stunde:" />
<ComboBox Name="StundenZeitenComboBox" Grid.Column="0" DisplayMemberPath="Value" />
</StackPanel>
<StackPanel Grid.Column="1">
<TextBlock Text="Veranstaltungsart:" />
<ComboBox Name="VeranstaltungsartComboBox" Grid.Column="1" />
</StackPanel>
</Grid>
</Grid>

Content of ScrollViewer won't extend

I have the following Window
Now if I try to pull down the Gridsplitter I can only as far as the blue Grid fits in the visible Window. But when sliding down the splitter I want a scrollbar to appear and be able to pull it down to the botton until the blue Grid is not visible any more.
<Window.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Menu Name="MainMenu" Grid.Row="0">
</Menu>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<DockPanel x:Name="Green" Grid.Column="0" Width="Auto" Height="Auto">
<views:MyView></views:MyView>
</DockPanel>
<GridSplitter Grid.Column="0" Width="6"></GridSplitter>
<Grid Grid.Column="1" >
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="7" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<views:ListView x:Name="Yellow" ></views:ListView>
</Grid>
<GridSplitter Grid.Row="1" Height="7" HorizontalAlignment="Stretch" />
<Grid Grid.Row="2" >
<ContentControl Content="{Binding LoadedControl}" x:Name="Blue" />
</Grid>
</Grid>
</ScrollViewer>
</Grid>
</Grid>
<StatusBar x:Name="StatusBar" Grid.Row="2">
</StatusBar>
</Grid>
</Window.Content>
What do I have to change here?
Move your ScrollViewer further down so it wraps the blue ContentControl in row 2, and ensure the ContentControl has a Height or MinHeight set.
ScrollViewers allow their child to take up as much space as they want, and only shows scrollbars if the child object gets larger than the ScrollViewer size.
Also as a side note, you can remove some of those extra Grid's in your layout to make it easier to read. Here's an example with a bunch of them removed, and the first one being replaced with a DockPanel :)
<DockPanel>
<Menu Name="MainMenu" DockPanel.Dock="Top" Height="25" />
<StatusBar x:Name="StatusBar" DockPanel.Dock="Bottom" Height="25"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="6" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<views:MyView x:Name="Green" Grid.Column="0" />
<GridSplitter Grid.Column="1" Width="6" />
<Grid Grid.Column="2" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="7" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<views:ListView x:Name="Yellow" Grid.Row="0" />
<GridSplitter Grid.Row="1" Height="7" HorizontalAlignment="Stretch" />
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
<ContentControl x:Name="Blue" MinHeight="400"/>
</ScrollViewer>
</Grid>
</Grid>
</DockPanel>
Hope you find a better solution XD as mine use a code behind
I used the DragDelta event of the control GridSplitter and enlarge the height of the grid so the ScrollBar can be activated
The xaml Code:
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<DockPanel x:Name="Green" Grid.Column="0" Width="Auto" Height="Auto" Background="#FF0CFA8F" >
<local:BusyUserControl Width="200" Height="200"/>
</DockPanel>
<GridSplitter ResizeDirection="Rows" Grid.Column="0" Width="6"></GridSplitter>
<ScrollViewer x:Name="MainScrollViewer" VerticalScrollBarVisibility="Auto" Grid.Column="1" >
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="7" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid >
<views:ListView x:Name="Yellow" ></views:ListView>
</Grid>
<GridSplitter Grid.Row="1" Height="7" ResizeBehavior="PreviousAndNext" HorizontalAlignment="Stretch" DragDelta="GridSplitter_DragDelta" />
<Grid Grid.Row="2">
<ContentControl Content="{Binding LoadedControl}" x:Name="Blue" />
</Grid>
</Grid>
</ScrollViewer>
</Grid>
The code Behind:
private void GridSplitter_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
if (e.VerticalChange > 1500 || e.VerticalChange > -15000) return;
if (e.VerticalChange > 0 || Visibility.Visible.Equals(MainScrollViewer.ComputedVerticalScrollBarVisibility))
{
this.MainGrid.Height = this.MainGrid.ActualHeight + e.VerticalChange;
}
e.Handled = true;
}
Note:
When the scrollbar is no more visible I stop shrinking the grid (keep the grid stretshed) that’s the meaning of the condition
Visibility.Visible.Equals(MainScrollViewer.ComputedVerticalScrollBarVisibility)
Hope this could help you and thx for the question :)
if you want to display a vertical scroll bar for each part in the splitted grid try the following code :
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<DockPanel x:Name="Green" Grid.Column="0" Width="Auto" Height="Auto" Background="#FF0CFA8F" >
<local:BusyUserControl Width="200" Height="200"/>
</DockPanel>
<GridSplitter Grid.Column="0" Width="6"></GridSplitter>
<Grid Grid.Column="1" >
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="7" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="0" >
<Grid >
<views:ListView x:Name="Yellow" ></views:ListView>
</Grid>
</ScrollViewer>
<GridSplitter Grid.Row="1" Height="7" HorizontalAlignment="Stretch" />
<ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="2" >
<Grid Grid.Row="2" >
<ContentControl Content="{Binding LoadedControl}" x:Name="Blue" />
</Grid>
</ScrollViewer>
</Grid>
</Grid>
</Grid>
otherwise clarify your need

Avoid inheritance of opacity between nested Grids

I have a Grid with its background as black an opacity to 0.5 and in it is there another grid with opacity to 1 and background as White. But the inner grid still shows as its opacity was 0.5
<Grid Grid.ColumnSpan="2" Grid.RowSpan="2" Background="Black" Opacity="0.5" Visibility="{Binding Alertar, Converter={cnv:boolToVisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="2*"></RowDefinition>
<RowDefinition Height="5*"></RowDefinition>
<RowDefinition Height="2*"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="1" Background="Black" Opacity="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="7*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10*"/>
<RowDefinition Height="1.5*"/>
</Grid.RowDefinitions>
<Rectangle Grid.ColumnSpan="3" Grid.RowSpan="2" Fill="Black" Opacity="1"/>
<TextBlock Grid.Column="1" Margin="0,15,0,0" Text="{Binding ReporteInconsistencias}" />
<Button Grid.Column="1" Grid.Row="1" Content="Aceptar" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/>
</Grid>
</Grid>
I'm trying to emulate a win8 alert screen there is another way to do this? or How to prevent this inheritance? why this happen?
A little messy but this should work i think. Basically controls are stacked. So having the grid come after the first grid it shouldn't effect the opacity. May need to be tweaked, but something along the lines of this should work:
<Grid Grid.ColumnSpan="2" Grid.RowSpan="2" Visibility="{Binding Alertar, Converter={cnv:boolToVisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="2*"></RowDefinition>
<RowDefinition Height="5*"></RowDefinition>
<RowDefinition Height="2*"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.RowSpan="3" Background="Black" Opacity="0.5" />
<Grid Grid.Row="1" Background="Black" Opacity="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="7*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10*"/>
<RowDefinition Height="1.5*"/>
</Grid.RowDefinitions>
<Rectangle Grid.ColumnSpan="3" Grid.RowSpan="2" Fill="Black" Opacity="1"/>
<TextBlock Grid.Column="1" Margin="0,15,0,0" Text="{Binding ReporteInconsistencias}" />
<Button Grid.Column="1" Grid.Row="1" Content="Aceptar" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/>
</Grid>
</Grid>

Handle click event or MouseDown in a disabled WPF StackPanel

It's been a while I'm trying to do something like that and I am about throwing a NotImplementedException now... I mean, throwing in the towel. You are my last hope.
So, there is my goal: Enabling a StackPanel when the user has clicked on it for user-friendly purpose.
I've got some items in this disabled StackPanel which is inside a ScrollViewer inside a Grid inside a Window.
There is a part of my code for understanding:
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition MinHeight="30" MaxHeight="30"/>
<RowDefinition MinHeight="22" MaxHeight="22"/>
<RowDefinition MinHeight="155" Height="155"/>
<RowDefinition MinHeight="130"/>
<RowDefinition MinHeight="25" MaxHeight="25"/>
<RowDefinition MinHeight="22" MaxHeight="22"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="355" Width="360" />
<ColumnDefinition MinWidth="330" />
<ColumnDefinition MinWidth="280" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="2" Grid.Row="3" VerticalScrollBarVisibility="Auto">
<StackPanel IsEnabled="False" IsEnabledChanged="ioStackPanel_IsEnabledChanged">
<Grid Height="22">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
</Grid>
</StackPanel>
</ScrollViewer>
</Grid>
I tried something like that already:
<ScrollViewer Grid.Column="2" Grid.Row="3" VerticalScrollBarVisibility="Auto" MouseDown="ScrollViewer_MouseDown">
private void ScrollViewer_MouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Well done bro!");
}
But nothing is raised. No MessageBox is displayed.
The following code is working fine, follow it.
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition MinHeight="30" MaxHeight="30" />
<RowDefinition MinHeight="22" MaxHeight="22" />
<RowDefinition Height="155" MinHeight="155" />
<RowDefinition MinHeight="130" />
<RowDefinition MinHeight="25" MaxHeight="25" />
<RowDefinition MinHeight="22" MaxHeight="22" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="360" MinWidth="355" />
<ColumnDefinition MinWidth="330" />
<ColumnDefinition MinWidth="280" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Row="3"
Grid.Column="2"
PreviewMouseLeftButtonDown="InnerPanel_PreviewMouseLeftButtonDown_1"
VerticalScrollBarVisibility="Auto">
<StackPanel Name="InnerPanel"
Background="Gray"
IsEnabled="False"
IsEnabledChanged="StackPanel_IsEnabledChanged_1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110" />
<ColumnDefinition />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Button Grid.Column="2" Content="Inner Panel" />
</Grid>
</StackPanel>
</ScrollViewer>
</Grid>
private void InnerPanel_PreviewMouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
{
}
This is working fine and implement your logic in the above event.
Unfortunately when a control is disabled, it consumes all its events and does nothing.
How about using a grid to put it behind a transparent panel. When the user clicks on the panel then you hide the panel and enable your stackpanel.
Something like...
<scrollviewer ...>
<grid> <!--New grid just to align the two panels-->
<stackpanel x:Name="enableMe" IsEnabled="False" ...>
....
</stackpanel>
<border x:name="hideMe" Background="Transparent" Click="EnableStackPanel" ZIndex="1"/>
</grid>
</stackpanel>
public void EnableStackPanel(...)
{
enableMe.IsEnabled=true;
hideMe.Visibilty = Visibility.Collapsed;
}

Categories