Grid Splitter working on diagonal? - c#

I'm trying to do a Window with a transparent square inside it, and I want to allow the user to re-size it in whatever way s/he wants. This code is working for vertical and horizontal re-size
<Window x:Class="TransparentWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="PloofTAS" Height="355" Width="539" Topmost="True"
ResizeMode="NoResize"
AllowsTransparency="True"
Background="Transparent"
WindowStyle="None" MouseLeftButtonDown="Window_MouseLeftButtonDown">
<Grid Name="GlobalGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="8" />
<RowDefinition Height="*" />
<RowDefinition Height="8" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Fill="Gray" Grid.Column="0" Grid.RowSpan="5" />
<Rectangle Fill="Gray" Grid.Column="4" Grid.RowSpan="5" />
<Rectangle Fill="Gray" Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="3" />
<Rectangle Fill="Gray" Grid.Column="1" Grid.Row="4" Grid.ColumnSpan="3" />
<GridSplitter Grid.Column="2" Grid.Row="1" Height="Auto" HorizontalAlignment="Stretch" />
<GridSplitter Grid.Column="1" Grid.Row="2" Height="Auto" HorizontalAlignment="Stretch" />
<GridSplitter Grid.Column="3" Grid.Row="2" Height="Auto" HorizontalAlignment="Stretch" />
<GridSplitter Grid.Column="2" Grid.Row="3" Height="Auto" HorizontalAlignment="Stretch" />
<Rectangle Fill="Orange" Grid.Row="1" Grid.Column="1" />
<Rectangle Fill="Orange" Grid.Row="1" Grid.Column="3" />
<Rectangle Fill="Orange" Grid.Row="3" Grid.Column="1" />
<Rectangle Fill="Orange" Grid.Row="3" Grid.Column="3" />
<Rectangle Fill="Transparent" Stroke="Red" Grid.Column="2" Grid.Row="2"/>
</Grid>
</Window>
Here is the resulting window
I'd like for the orange squares (the corners of the red/transparent square) to be able to work diagonally, or both vertical and horizontal. Is it possible?

I don't know elegant solution for this problem as GridSplitter is not possible to set up programmatically.
My solution is just dirty mouse capture and set Column and Row measures according to mouse movement.
Set style and events. Tag property store index of a row and column we gonna to change in code behind.
<Window.Resources>
<Style x:Key="DiagonalSplitterRectangle" TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="Orange"/>
<EventSetter Event="MouseDown" Handler="UIElement_OnMouseDown"/>
<EventSetter Event="MouseMove" Handler="UIElement_OnMouseMove"/>
<EventSetter Event="MouseUp" Handler="UIElement_OnMouseUp"/>
<EventSetter Event="LostMouseCapture" Handler="UIElement_OnLostMouseCapture"/>
</Style>
</Window.Resources>
<Rectangle Grid.Row="1" Grid.Column="1" Style="{StaticResource DiagonalSplitterRectangle}" Tag="0,0"/>
<Rectangle Grid.Row="1" Grid.Column="3" Style="{StaticResource DiagonalSplitterRectangle}" Tag="0,4"/>
<Rectangle Grid.Row="3" Grid.Column="1" Style="{StaticResource DiagonalSplitterRectangle}" Tag="4,0"/>
<Rectangle Grid.Row="3" Grid.Column="3" Style="{StaticResource DiagonalSplitterRectangle}" Tag="4,4"/>
Simple mouse capture events:
private bool _isMouseCaptured;
public MainWindow()
{
InitializeComponent();
}
private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
{
var uiElement = sender as UIElement;
if (uiElement == null)
return;
if (uiElement.CaptureMouse())
_isMouseCaptured = true;
}
private void UIElement_OnMouseMove(object sender, MouseEventArgs e)
{
if (!_isMouseCaptured)
return;
var clientWindow = Content as FrameworkElement;
if (clientWindow == null)
return;
var rectangle = sender as Rectangle;
if (rectangle == null)
return;
Point position = Mouse.GetPosition(GlobalGrid); ;
if (position.X < 0 || position.Y < 0 || position.X > clientWindow.ActualWidth || position.Y > clientWindow.ActualHeight)
return;
GridUpdate(position, rectangle, clientWindow);
}
private void UIElement_OnMouseUp(object sender, MouseButtonEventArgs e)
{
if (!_isMouseCaptured)
return;
var uiElement = sender as UIElement;
if (uiElement == null)
return;
uiElement.ReleaseMouseCapture();
}
private void UIElement_OnLostMouseCapture(object sender, MouseEventArgs e)
{
_isMouseCaptured = false;
}
Resize grid columns and rows according to value stored in rectangle.Tag property.
For correct behavior was needed to change opposite column and row measures too.
private void GridUpdate(Point position, Rectangle rectangle, FrameworkElement clientWindow)
{
var gridPosition = new GridPosition(rectangle.Tag.ToString());
var oppositeGridPosition = GetOppositeGridPosition(gridPosition);
var rowHeight = GetMeasure(gridPosition.Row, position.Y, clientWindow.ActualHeight);
var columnWidth = GetMeasure(gridPosition.Column, position.X, clientWindow.ActualWidth);
var oppositeRowHeight = GlobalGrid.RowDefinitions[oppositeGridPosition.Row].ActualHeight;
var oppositeColumnWidth = GlobalGrid.ColumnDefinitions[oppositeGridPosition.Column].ActualWidth;
GlobalGrid.RowDefinitions[gridPosition.Row].Height = new GridLength(rowHeight);
GlobalGrid.ColumnDefinitions[gridPosition.Column].Width = new GridLength(columnWidth);
GlobalGrid.RowDefinitions[oppositeGridPosition.Row].Height = new GridLength(oppositeRowHeight);
GlobalGrid.ColumnDefinitions[oppositeGridPosition.Column].Width = new GridLength(oppositeColumnWidth);
}
private GridPosition GetOppositeGridPosition(GridPosition gridPosition)
{
var row = (gridPosition.Row == 0) ? 4 : 0;
var column = (gridPosition.Column == 0) ? 4 : 0;
return new GridPosition(row, column);
}
private double GetMeasure(int gridPosition, double position, double windowMeasure)
{
return gridPosition == 0 ? position : windowMeasure - position;
}
GridPosition is structure that stores column and row index values.
public struct GridPosition
{
public int Row { get; private set; }
public int Column { get; private set; }
public GridPosition(int row, int column)
: this()
{
Row = row;
Column = column;
}
public GridPosition(string gridPostion)
: this()
{
Row = Convert.ToInt32(gridPostion.Split(',')[0]);
Column = Convert.ToInt32(gridPostion.Split(',')[1]);
}
}

Related

WPF sliders to change button colors on click

I am doing a project where I have to change button colors based on sliders in WPF. This is my XAML design.
XAML file
So, I have made 64 buttons, and I have tried implementing multiple options, and none worked for me.
I have this xaml code:
<Grid Grid.Column="0" Grid.RowSpan="4" Grid.ColumnSpan="4" HorizontalAlignment="Left" Height="790" Margin="0,10,0,0" Grid.Row="0" VerticalAlignment="Top" Width="800">
<Grid Margin="230,114,230,346" AutomationProperties.Name="ledMatrix" Tag="ledMatrix" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Grid.Column="0" Grid.Row="0" Height="40" Width="40" Command="{Binding LEDBtn}" Background="#FFAAAAAA" Tag="LED00" Click="changeLedIndicatiorColor" x:Name="LEDButton"/>
<Button Grid.Column="1" Grid.Row="0" Height="40" Width="40" Command="{Binding LEDBtn}" Background="#FFAAAAAA" Tag="LED01"/>
<Button Grid.Column="2" Grid.Row="0" Height="40" Width="40" Command="{Binding LEDBtn}" Background="#FFAAAAAA" Tag="LED02"/>
<Button Grid.Column="3" Grid.Row="0" Height="40" Width="40" Command="{Binding LEDBtn}" Background="#FFAAAAAA" Tag="LED03"/>
<Button Grid.Column="4" Grid.Row="0" Height="40" Width="40" Command="{Binding LEDBtn}" Background="#FFAAAAAA" Tag="LED04"/>
<Button Grid.Column="5" Grid.Row="0" Height="40" Width="40" Command="{Binding LEDBtn}" Background="#FFAAAAAA" Tag="LED05"/>
<Button Grid.Column="6" Grid.Row="0" Height="40" Width="40" Command="{Binding LEDBtn}" Background="#FFAAAAAA" Tag="LED06"/>
<Button Grid.Column="7" Grid.Row="0" Height="40" Width="40" Command="{Binding LEDBtn}" Background="#FFAAAAAA" Tag="LED07"/>
and sliders:
<Grid Margin="230,480,230,170">
<Slider x:Name="SeekR" Margin="0,0,0,120" Tag="seekR" Maximum="255" Background="Red" ></Slider>
<Slider x:Name="SeekG" Margin="0,50,0,70" Tag="seekG" Maximum="255" Background="Green"></Slider>
<Slider x:Name="SeekB" Margin="0,100,0,20" Tag="seekB" Maximum="255" Background="Blue"></Slider>
</Grid>
I have tried placing this in my xaml.cs file :
public void changeColor()
{
byte rr = (byte)SeekR.Value;
byte gg = (byte)SeekG.Value;
byte bb = (byte)SeekB.Value;
Color cc = Color.FromRgb(rr, gg, bb); //Create object of Color class.
SolidColorBrush colorBrush = new SolidColorBrush(cc); //Creating object of SolidColorBruch class.
LEDButton.Background = colorBrush; //Setting background of stack panel.
}
private void changeLedIndicatiorColor(object sender, RoutedEventArgs e)
{
changeColor();
}
But from this code, I have to name all the buttons differently butI want to have the same binding for all buttons and try to connect it all together, so for example I would like to set color by sliders and when I click the button color would change. Then, I can change the color, and make other buttons that different color.
Refactor ChangeColor to accept a Button, the button to change the color for:
private void ChangeLedIndicatiorColor_OnClick(object sender, RoutedEventArgs e)
{
ChangeColor(sender as Button);
}
public void ChangeColor(Button button)
{
byte rr = (byte)SeekR.Value;
byte gg = (byte)SeekG.Value;
byte bb = (byte)SeekB.Value;
Color cc = Color.FromRgb(rr, gg, bb);
SolidColorBrush colorBrush = new SolidColorBrush(cc);
button.Background = colorBrush;
}
Then register the ChangeLedIndicatiorColor event handler for each Button.Click:
...
<Button Click="ChangeLedIndicatiorColor" />
<Button Click="ChangeLedIndicatiorColor" />
<Button Click="ChangeLedIndicatiorColor" />
...
You can use the EventSetter so that the event can be applicable to all the buttons. You don't need to attach the click event handler to each button anymore.
<Window.Resources>
<Style TargetType="Button">
<EventSetter Event="Click" Handler="ChangeLedIndicatiorColor"/>
</Style>
</Window.Resources>
And inside event handler you can change the color of the button which triggered the click event.
private void changeLedIndicatiorColor(object sender, RoutedEventArgs e)
{
byte rr = (byte)SeekR.Value;
byte gg = (byte)SeekG.Value;
byte bb = (byte)SeekB.Value;
Color cc = Color.FromRgb(rr, gg, bb);
SolidColorBrush colorBrush = new SolidColorBrush(cc);
(sender as Button).Background = colorBrush;
}

wpf- making an entire box clickable

I have a rectangle textbox in WPF and there is already a button inside the textbox which is clickable. I need to make the entire rectangle textbox clickable, so users can click anywhere in the textbox rather than just the button to interact.
Is it possible to do so?
Here is my XAML:
<Grid Background="{StaticResource TinyGrayBrush}" Height="260" Width="530" Margin="10,10,10,10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120*"/>
<ColumnDefinition Width="140*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Image x:Name="imgCard" Source="{StaticResource Exception-NoImageAvailable}" Stretch="Fill" />
<Image x:Name="hotpickEn" Source="{StaticResource HotPickEn}" Height="20" Width="70" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,30,0,0" Visibility="Hidden" />
<Image x:Name="hotpickCh" Source="{StaticResource HotPickCH}" Height="20" Width="70" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,30,0,0" Visibility="Hidden" />
</Grid>
<Grid x:Name="gdEnglish" Visibility="Visible" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="12*"/>
<RowDefinition Height="62*"/>
<RowDefinition Height="90*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="55*"/>
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="25,5,25,5"/>
</Style>
</Grid.Resources>
<TextBlock Grid.Row="1" x:Name="txtTitle" Text="SPARKLING SUNDAY BRUNCH BUFFET" FontSize="20" TextWrapping="Wrap" FontWeight="Medium" Foreground="{StaticResource SemiDarkGrayBrush}" Margin="5,0,5,6.5" />
<TextBlock Grid.Row="2" x:Name="txtDesc" Text="Pop your Sunday Morning with luxury sparkling bubble" FontSize="16" TextWrapping="Wrap" Foreground="{StaticResource GrayBrush}" Margin="5,3.5,5,6.5" />
<TextBlock Grid.Row="3" x:Name="txtPoint" Text="138,900 GP" FontSize="21" TextWrapping="Wrap" FontWeight="Medium" Foreground="{StaticResource GrayBrush}" Margin="25,3.5,25,6" />
<Button Grid.Row="4" x:Name="btnFindOutMore" Content="FIND OUT MORE OR REDEEM" Style="{StaticResource SmallWhiteRedButton}" Margin="12,0,12,0" FontSize="20" />
</Grid>
<Grid x:Name="gdChinese" Visibility="Hidden" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="12*"/>
<RowDefinition Height="62*"/>
<RowDefinition Height="90*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="55*"/>
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="25,5,25,5"/>
</Style>
</Grid.Resources>
<TextBlock Grid.Row="1" x:Name="txtCHTitle" Text="SPARKLING SUNDAY BRUNCH BUFFET" FontSize="20" TextWrapping="Wrap" FontWeight="Medium" Foreground="{StaticResource SemiDarkGrayBrush}" HorizontalAlignment="Left" Margin="5,4.667,0,5.333" />
<TextBlock Grid.Row="2" x:Name="txtCHDesc" Text="Pop your Sunday Morning with luxury sparkling bubble" FontSize="16" TextWrapping="Wrap" Foreground="{StaticResource GrayBrush}" HorizontalAlignment="Left" Margin="5,4.667,0,5.667" />
<TextBlock Grid.Row="3" x:Name="txtCHPoint" Text="138,900 GP" FontSize="21" TextWrapping="Wrap" FontWeight="Medium" Foreground="{StaticResource GrayBrush}" HorizontalAlignment="Left" Margin="25,3.5,25,6" Width="105" />
<Button x:Name="btnCHFindOutMore" Grid.Row="4" Content="FIND OUT MORE OR REDEEM" Style="{StaticResource SmallWhiteRedButton}" Margin="15,0,10,0"/>
</Grid>
As you are using Code-Behind for this:
You basically subscribe to the events of the Grid too
gdEnglish.TouchDown += gdEnglish_TouchDown;
gdEnglish.TouchUp += gdEnglish_TouchUp;
gdEnglish.TouchLeave += gdEnglish_TouchLeave;
gdEnglish.MouseDown += gdEnglish_MouseDown;
gdEnglish.MouseUp += gdEnglish_MouseUp;
gdEnglish.MouseLeave += gdEnglish_MouseLeave;
add a new private variable to indicate the current state
private bool gdEnglish_clickflag = false;
and create the different event handlers
private void gdEnglish_MouseLeave(object sender, MouseEventArgs e)
{
gdEnglish_clickflag = false;
}
private void gdEnglish_MouseUp(object sender, MouseButtonEventArgs e)
{
if (gdEnglish_clickflag)
{
gdEnglish_clickflag = false;
e.Handled = true;
//////////
// YOUR //
// CODE //
//////////
}
}
private void gdEnglish_MouseDown(object sender, MouseButtonEventArgs e)
{
gdEnglish_clickflag = true;
}
private void gdEnglish_TouchLeave(object sender, TouchEventArgs e)
{
gdEnglish_clickflag = false;
}
private void gdEnglish_TouchUp(object sender, TouchEventArgs e)
{
if (gdEnglish_clickflag)
{
gdEnglish_clickflag = false;
e.Handled = true;
//////////
// YOUR //
// CODE //
//////////
}
}
private void gdEnglish_TouchDown(object sender, TouchEventArgs e)
{
gdEnglish_clickflag = true;
}
I still want to recommend that you research the topic MVVM with WPF
it will make things like this more clean and easy

How to set custom-column-property in xaml file?

GridSplitterControl.xaml
<sdk:GridSplitter x:Class="JustLogIt.Common.GridSplitterControl"
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"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d">
<sdk:GridSplitter.Template>
<ControlTemplate TargetType="sdk:GridSplitter">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<telerik:RadButton Grid.Row="0"
Width="10"
Height="20"
HorizontalAlignment="Center"
Click="Click"
Cursor="Hand" />
<Border Grid.Row="1"
BorderBrush="LightGray"
BorderThickness="5" />
</Grid>
</ControlTemplate>
</sdk:GridSplitter.Template>
</sdk:GridSplitter>
GridSplitterControl.xaml.cs
public partial class GridSplitterControl : GridSplitter
{
GridLength AutoSize = new GridLength(1.0, GridUnitType.Auto);
GridLength ZeroSize = new GridLength(0.0);
public ColumnDefinition Left{ set; get;}
public GridSplitterControl()
{
InitializeComponent();
}
public GridSplitterControl(ColumnDefinition ColLeft)
{
InitializeComponent();
Left = ColLeft;
}
public void Click(object sender, RoutedEventArgs e)
{
if (Left != null)
{
Left.MinWidth = 10.0;
if ((Left.Width.Value + 10) == Left.MinWidth)
Left.Width = AutoSize;
else if (Left.Width.Value != AutoSize.Value)
Left.Width = AutoSize;
else Left.Width = ZeroSize;
}
//ClickNotify(sender, e);
}
public event EventHandler ClickCompleted;
private void ClickNotify(object senderAIF, RoutedEventArgs eAIF)
{
if (ClickCompleted != null)
ClickCompleted(senderAIF, eAIF);
}
}
The Click event can work, but I have no idea to set the Left(ColumnDefinition) in xaml file which used this Element.
<Grid x:Name="LayoutRoot1"
Grid.Row="1"
Margin="5"
Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="LvCol_10" Width="*" />
<ColumnDefinition x:Name="LvCol_11" Width="*" />
</Grid.ColumnDefinitions>
<Mylayout:GridSplitterControl x:Name="GridSplitter_Left"
Grid.RowSpan="7"
Grid.Column="0"
Width="10"
VerticalAlignment="Stretch"
IsEnabled="True"
Left=? /> < !-- How to set "LvCol_11" in here? -->
</Grid>`
It seems like that you want to set the grid.row as property which is used when the button click.
Maybe you can try this...
GridSplitterControl.xaml.cs
private void UI_Loaded(object sender, RoutedEventArgs e)
{
if (sender is GridSplitter)
{
Grid ParentGrid = this.ParentOfType<Grid>();
SetLocation(ParentGrid);
}
}
public void SetLocation(Grid p_Layout)
{
int index = Grid.GetColumn(this);
ColumnDefinition ColLocation = p_Layout.ColumnDefinitions[index];
ColLocation.MinWidth = 10;
Left = ColLocation;
}
Becarefully, besure your element's parent(Up one level) is grid.
If parent is stackPanel, border, or rectangle, it will be not working, maybe.

Drag item from Listbox and start method on drop into specific Canvas

I am quite new to C# so please keep things as simple as possible.
My problem is as follows: I have a Listbox to which I add Items dynamically at runtime and I also have four different Canvases within my UI.
Now the user has to be able to drag any Item from the Listbox and drop it into one of the four Canvases.
Upon drop a method will be started which needs to know which Item has been draged and into which Canvas it was dropped.
I have not implemented anything yet but here at least my XAML:
<Grid Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="gridMenu" VerticalAlignment="Stretch" Width="Auto" Background="#FFE6E6E6">
<ListBox Grid.Row="2" Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="listBox1" VerticalAlignment="Stretch" Width="Auto" Background="#FFE6E6E6" BorderBrush="{x:Null}" Panel.ZIndex="1" PreviewMouseDown="listBox1_PreviewMouseLeftButtonDown">
<ListBoxItem Content="test1" />
<ListBoxItem Content="test2" />
<ListBoxItem Content="test3" />
<ListBoxItem Content="test4" />
<ListBoxItem Content="test5" />
</ListBox>
</Grid>
<Grid Grid.Column="1" Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="gridImage" VerticalAlignment="Stretch" Width="Auto" TextBlock.Drop="grid1_Drop">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Canvas Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage1" VerticalAlignment="Stretch" Width="Auto" />
<Canvas Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage2" VerticalAlignment="Stretch" Width="Auto" Grid.Column="1" />
<Canvas Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage3" VerticalAlignment="Stretch" Width="Auto" Grid.Row="1" />
<Canvas Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage4" VerticalAlignment="Stretch" Width="Auto" Grid.Column="1" Grid.Row="1" />
</Grid>
I think Drag and Drop isn't an easy topic, so I am afraid I can't make it that simple and I agree with ekholm: You will definitely need a decent c#/wpf knowledge to succesfully implement this. Even when you get your code to run you will be stuck when you want to modify/extend your DragDrop Code.
Here's an example to get you started based on your provided markup:
XAML:
<Grid Grid.Row="1" Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="gridImage" VerticalAlignment="Stretch" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Canvas Background="LightGreen" AllowDrop="True" Drop="canvasImage_Drop" DragEnter="canvasImage_DragEnter" Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage1" VerticalAlignment="Stretch" Width="Auto" />
<Canvas Background="LightYellow" AllowDrop="True" Drop="canvasImage_Drop" DragEnter="canvasImage_DragEnter" Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage2" VerticalAlignment="Stretch" Width="Auto" Grid.Column="1" />
<Canvas Background="LightPink" AllowDrop="True" Drop="canvasImage_Drop" DragEnter="canvasImage_DragEnter" Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage3" VerticalAlignment="Stretch" Width="Auto" Grid.Row="1" />
<Canvas Background="LightSteelBlue" AllowDrop="True" Drop="canvasImage_Drop" DragEnter="canvasImage_DragEnter" Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage4" VerticalAlignment="Stretch" Width="Auto" Grid.Column="1" Grid.Row="1" />
</Grid>
</Grid>
Code behind:
private Point _startPoint;
private static readonly string _dropIdentifier = "dropIdentifier";
private void listBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// The initial mouse position
_startPoint = e.GetPosition(null);
}
private void listBox_PreviewMouseMove(object sender, MouseEventArgs e)
{
// Get the current mouse position
Point mousePos = e.GetPosition(null);
Vector diff = _startPoint - mousePos;
if (e.LeftButton == MouseButtonState.Pressed &&
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
// Get the dragged ListBoxItem
var listBox = sender as ListBox;
var listBoxItem = listBox.SelectedItem;
// Initialize the drag & drop operation
DataObject dragData = new DataObject(_dropIdentifier, listBoxItem);
DragDrop.DoDragDrop(listBox, dragData, DragDropEffects.Move);
}
}
private void canvasImage_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(_dropIdentifier))
{
var item = e.Data.GetData(_dropIdentifier) as ListBoxItem;
DropOnCanvas(sender as Canvas, item);
}
}
private void canvasImage_DragEnter(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent(_dropIdentifier) ||
sender == e.Source)
{
e.Effects = DragDropEffects.None;
}
}
public void DropOnCanvas(Canvas targetCanvas, ListBoxItem item)
{
// do your stuff here ...
int textHeight = 20;
var text = new TextBlock() { Text = item.Content.ToString(), Height = textHeight };
Canvas.SetTop(text, targetCanvas.Children.Count * textHeight);
targetCanvas.Children.Add(text);
}
This tutorial should get you started: http://wpftutorial.net/DragAndDrop.html

NullReferenceException in DragDrop after adding Items to ListBox

I am trying to implement a dynamic ListBox that contains the "open files" of my program. Those files can be dragged from the ListBox into one of four Canvases.
That works all fine as long as the items are added in XAML before starting the program, however, once I add items to the ListBox via fileList.Items.Add("myitemname"); I get a NullReferenceException if I try to drop (dragging works) them into the Canvas at
DragDrop.DoDragDrop(listBox, dragData, DragDropEffects.Move);
Here the relevant part of my code:
public partial class MainWindow : Window
{
InitialDataObject _initData = new InitialDataObject();
public MainWindow()
{
InitializeComponent();
}
#region DragImage
private void DragImageStart(object sender, MouseButtonEventArgs e)
{
_initData._mousePoint = e.GetPosition(null);
}
private void DragImageMove(object sender, MouseEventArgs e)
{
Point mousePos = e.GetPosition(null);
Vector diff = _initData._mousePoint - mousePos;
if (e.LeftButton == MouseButtonState.Pressed && (
Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance) && ((sender as ListBox).SelectedItem != null))
{
var listBox = sender as ListBox;
var listBoxItem = listBox.SelectedItem;
DataObject dragData = new DataObject(_initData._dropIdentifier, listBoxItem);
DragDrop.DoDragDrop(listBox, dragData, DragDropEffects.Move);
}
}
private void CanvasDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(_initData._dropIdentifier))
{
var item = e.Data.GetData(_initData._dropIdentifier) as ListBoxItem;
(sender as Canvas).Background = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
DropImage(sender as Canvas, item);
fileList.UnselectAll();
}
}
private void CanvasDragEnter(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent(_initData._dropIdentifier) || sender == e.Source)
{
(sender as Canvas).Background = new SolidColorBrush(Color.FromArgb(255, 240, 240, 240));
e.Effects = DragDropEffects.None;
}
}
private void DropImage(Canvas targetCanvas, ListBoxItem item)
{
//just to check if I got the right item in this method
MessageBox.Show(item.Content.ToString());
}
private void CanvasDragLeave(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent(_initData._dropIdentifier) || sender == e.Source)
{
(sender as Canvas).Background = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
}
}
#endregion
private void sdfsdf(object sender, RoutedEventArgs e)
{
fileList.Items.Add("test");
}
}
class InitialDataObject
{
public Point _mousePoint = new Point();
public readonly string _dropIdentifier = "dropIdentifier";
}
XAML:
<Grid Height="Auto" HorizontalAlignment="Stretch" Margin="0,23,0,0" Name="gridSubmain" VerticalAlignment="Stretch" Width="Auto" Panel.ZIndex="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250" MaxWidth="250" MinWidth="250" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox Height="Auto" Name="fileList" Width="Auto" Background="#FFE6E6E6" BorderBrush="{x:Null}" Panel.ZIndex="1" PreviewMouseLeftButtonDown="DragImageStart" PreviewMouseMove="DragImageMove" FontSize="16" ItemsSource="{Binding}" Margin="0" Grid.Row="2">
<ListBoxItem Content="dfgdfg" />
<ListBoxItem Content="sfsdf" />
<ListBoxItem Content="ghjgh" />
<ListBoxItem Content="cvbcvb" />
</ListBox>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="112,196,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="sdfsdf" />
</Grid>
<Grid Grid.Column="1" Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="gridImage" VerticalAlignment="Stretch" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Canvas Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage1" VerticalAlignment="Stretch" Width="Auto" AllowDrop="True" Drop="CanvasDrop" DragEnter="CanvasDragEnter" Background="White" DragLeave="CanvasDragLeave" />
<Canvas Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage2" VerticalAlignment="Stretch" Width="Auto" Drop="CanvasDrop" DragEnter="CanvasDragEnter" Grid.Column="1" AllowDrop="True" Background="White" DragLeave="CanvasDragLeave"/>
<Canvas Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage3" VerticalAlignment="Stretch" Width="Auto" Drop="CanvasDrop" DragEnter="CanvasDragEnter" Grid.Row="1" AllowDrop="True" Background="White" DragLeave="CanvasDragLeave"/>
<Canvas Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="canvasImage4" VerticalAlignment="Stretch" Width="Auto" Drop="CanvasDrop" DragEnter="CanvasDragEnter" Grid.Column="1" Grid.Row="1" AllowDrop="True" Background="White" DragLeave="CanvasDragLeave"/>
</Grid>
Any ideas why it is working with existing items but not with ones added via fileList.Items.Add("..");? Also, with existing Items the fileList.UnselectAll(); works fine, but the extra added items stay selected and I can't get rid of the selection.
Problem in you CanvasDrop method. You expect ListBoxItem there, but get string, because SelectedItem property of list box have different values for items you create in xaml and items you add dynamically.

Categories