Reputation: 6147
So in my application I have to types of class objects, Circles and Rectangles. Both which got plotted using a ListBox. The rectangles are green and the circles are the yellow shapes.
You may be asking why am i using the listbox to display them. The benefit here is the freebie of making it possible for users to select the items when the click within the window as seen here.
The problems which i need help on, they all relate to the same topic which is clicking/selection.
Updated: 1/7/2016
The Problem (Left)| The Desired Goal (Right)
As far as the code, its rather short, and i combined it for simplicity into lesser files.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
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:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
Background="Gray">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type local:RectangleViewModel}" >
<Border Cursor="Hand" Background="Green" CornerRadius="4" Width="100" Height="100" Margin="10"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CircleViewModel}" >
<Path Data="M0,0 C0,0 10,100 100,100" Stroke="Gold" StrokeThickness="5" Cursor="Hand"/>
</DataTemplate>
</Window.Resources>
<!-- Presents the Rectangles -->
<ListBox x:Name="listBox" ItemsSource="{Binding Items}" SelectionMode="Extended" Background="Transparent">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" >
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.Resources>
</ListBox>
</Window>
MainWindowViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApplication1
{
public class MainWindowViewModel
{
private ObservableCollection<ItemViewModel> items = new ObservableCollection<ItemViewModel>();
public ObservableCollection<ItemViewModel> Items { get { return items; } }
public MainWindowViewModel()
{
// Populate the view model with some example data.
items.Add(new RectangleViewModel(250, 200));
items.Add(new RectangleViewModel(320, 370));
items.Add(new RectangleViewModel(100, 50));
items.Add(new RectangleViewModel(350, 25));
items.Add(new RectangleViewModel(70, 270));
items.Add(new CircleViewModel(20, 20));
items.Add(new CircleViewModel(300, 270));
items.Add(new CircleViewModel(350, 100));
items.Add(new CircleViewModel(50, 315));
items.Add(new CircleViewModel(100, 170));
}
}
public class ItemViewModel
{
// position coordinates
public double X { get; set; }
public double Y { get; set; }
}
public class CircleViewModel : ItemViewModel
{
// Constructors
public CircleViewModel(double x, double y)
{
this.X = x;
this.Y = y;
}
}
public class RectangleViewModel : ItemViewModel
{
// Constructors
public RectangleViewModel(double x, double y)
{
this.X = x;
this.Y = y;
}
}
}
UPDATED - Closer - ATTEMPT #2
Now I have the ability to drag and move items in the canvas with the hitTest of the click being correct. However for some reason when i try to move shapes in the bottom blue canvas they don't move, where as they do move in the top one. Try it out....
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace DragShapes
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
bool captured = false;
double x_shape, x_canvas, y_shape, y_canvas;
UIElement source = null;
private void shape_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Console.WriteLine("MouseDown--Pressed");
source = (UIElement)sender;
Mouse.Capture(source);
captured = true;
x_shape = Canvas.GetLeft(source);
x_canvas = e.GetPosition(LayoutRoot).X;
y_shape = Canvas.GetTop(source);
y_canvas = e.GetPosition(LayoutRoot).Y;
}
private void shape_MouseMove(object sender, MouseEventArgs e)
{
if (captured)
{
Console.WriteLine("MouseMove--Pressed");
double x = e.GetPosition(LayoutRoot).X;
double y = e.GetPosition(LayoutRoot).Y;
x_shape += x - x_canvas;
Canvas.SetLeft(source, x_shape);
x_canvas = x;
y_shape += y - y_canvas;
Canvas.SetTop(source, y_shape);
y_canvas = y;
}
}
private void
shape_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Console.WriteLine("MouseUp--Pressed");
Mouse.Capture(null);
captured = false;
}
}
}
MainWindowViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DragShapes
{
public class MainWindowViewModel
{
private ObservableCollection<ItemViewModel> items = new ObservableCollection<ItemViewModel>();
public ObservableCollection<ItemViewModel> Items { get { return items; } }
public MainWindowViewModel()
{
// Populate the view model with some example data.
items.Add(new RectangleViewModel(250, 200));
items.Add(new RectangleViewModel(320, 370));
items.Add(new RectangleViewModel(100, 50));
items.Add(new RectangleViewModel(350, 25));
items.Add(new RectangleViewModel(70, 270));
items.Add(new CircleViewModel(20, 20));
items.Add(new CircleViewModel(300, 270));
items.Add(new CircleViewModel(350, 100));
items.Add(new CircleViewModel(50, 315));
items.Add(new CircleViewModel(100, 170));
}
}
public class ItemViewModel : INotifyPropertyChanged
{
// position coordinates
private double x = 0;
public double X
{
get { return x; }
set
{
if (x != value)
{
x = value;
OnPropertyChanged("X");
}
}
}
private double y = 0;
public double Y
{
get { return y; }
set
{
if (y != value)
{
y = value;
OnPropertyChanged("Y");
}
}
}
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class CircleViewModel : ItemViewModel
{
// Constructors
public CircleViewModel(double x, double y)
{
this.X = x;
this.Y = y;
}
}
public class RectangleViewModel : ItemViewModel
{
// Constructors
public RectangleViewModel(double x, double y)
{
this.X = x;
this.Y = y;
}
}
}
MainWindow.xaml
<Window x:Class="DragShapes.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="600"
xmlns:local="clr-namespace:DragShapes">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type local:RectangleViewModel}" >
<Rectangle Cursor="Hand" Fill="Green" Width="100" Height="100" Margin="10"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseMove="shape_MouseMove"
MouseLeftButtonUp="shape_MouseLeftButtonUp"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CircleViewModel}" >
<Path Data="M0,0 C0,0 10,100 100,100" Stroke="Gold" StrokeThickness="5" Cursor="Hand"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseLeftButtonUp="shape_MouseLeftButtonUp"
MouseMove="shape_MouseMove"/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Canvas x:Name="LayoutRoot" Background="White">
<Ellipse Fill="Blue" HorizontalAlignment="Center" Height="100" Stroke="Black" VerticalAlignment="Center" Width="100" Canvas.Left="200" Canvas.Top="100"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseMove="shape_MouseMove"
MouseLeftButtonUp="shape_MouseLeftButtonUp" />
<Rectangle Fill="Red" Height="100" Stroke="Black" Width="100" HorizontalAlignment="Left" VerticalAlignment="Bottom" Canvas.Left="10" Canvas.Top="10"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseLeftButtonUp="shape_MouseLeftButtonUp"
MouseMove="shape_MouseMove"/>
</Canvas>
<Canvas Grid.Row="1" Background="White" >
<ItemsControl ItemsSource="{Binding Path=Items}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="LightBlue" Width="500" Height="500" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!--<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Fill="Green" Width="25" Height="25"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseLeftButtonUp="shape_MouseLeftButtonUp"
MouseMove="shape_MouseMove"/>
</DataTemplate>
</ItemsControl.ItemTemplate>-->
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
<!--<ItemsControl ItemsSource="{Binding Path=Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>-->
<!--<ItemsControl ItemsSource="{Binding Path=Items}">
--><!--<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>--><!--
</ItemsControl>-->
</Canvas>
</Grid>
</Window>
Upvotes: 1
Views: 724
Reputation: 96
Default ListBoxItem template has active background, so we need reset the template like this:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" >
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter/>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="LightBlue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
Then, we need modify the rectangle and circle templates, to get selection effect, when they are selected:
<DataTemplate DataType="{x:Type local:RectangleViewModel}" >
<Grid>
<Border CornerRadius="4"
Background="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}},
Path=Background}"/>
<Border Cursor="Hand" Background="Green" CornerRadius="4" Width="100" Height="100" Margin="10"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CircleViewModel}" >
<Grid>
<Path Data="M0,0 C0,0 10,100 100,100" StrokeThickness="15"
Stroke="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}},
Path=Background}"/>
<Path Data="M0,0 C0,0 10,100 100,100" Stroke="Gold" StrokeThickness="5" Cursor="Hand"/>
</Grid>
</DataTemplate>
Upvotes: 2