I have a working code with a Datagrid
as the main control.
I used a Datagrid as it is very easy to bind data into it.
My code requires moving cells into other columns so I always need to check which cell I am on when the mouse is clicked, as well as when it is released.
My current implementation is working as expected. However, the way I check for the row and cell is through the VIEW's code-behind. My project leader is looking for an alternative to have this done thru binding as he wants to keep the VIEW's code-behind as clean as possible. I have tried all I could but I can't find properties which would give me both the cells column and row index.
Please see the code below. (Omitted some of the columns as it would exceed the limit.)
the XAML:
<UserControl x:Class="Widget5.View.WorkItemsDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:converter="clr-namespace:Widget5.Converter"
mc:Ignorable="d"
d:DesignHeight="630" Width="690" Padding="0" Margin="0">
<UserControl.Resources>
<converter:RowNumberConverter x:Key="rowNumberConverter" />
<converter:HourSlotToBrushConverter x:Key="hourSlotColorConverter" />
</UserControl.Resources>
<Grid Margin="0" Width="690" HorizontalAlignment="Left" MouseRightButtonUp="Grid_MouseRightButtonUp" MouseUp="Grid_MouseUp">
<Grid.RowDefinitions>
<RowDefinition Height="24"></RowDefinition>
<RowDefinition></RowDefinition>
<!--<RowDefinition Height="30"></RowDefinition>-->
</Grid.RowDefinitions>
<!--<Grid HorizontalAlignment="Left" Height="24" VerticalAlignment="Bottom" Grid.Row="2"
Width="680">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="2" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="2" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Button Grid.Column="1" Width="48"
Command="{Binding AddCommand}">Add</Button>
<Button Grid.Column="3" Width="48"
Command="{Binding DeleteCommand}">Delete</Button>
<Button Grid.Column="5" Width="48"
Command="{Binding SaveCommand}">Save</Button>
<Button Grid.Column="7" Width="48"
Command="{Binding RefreshCommand}">Refresh</Button>
</Grid>-->
<Grid HorizontalAlignment="Left" Height="24" VerticalAlignment="Top" Width="690" Grid.Row="0"
Background="LightGray">
<Grid.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="10"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="123"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="1" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="2" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="3" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="4" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="5" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="6" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="7" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="8" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="9" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="10" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="11" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="12" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="13" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="14" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="15" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="16" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="17" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="18" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="19" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="20" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="21" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="22" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="23" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="24" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="25" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="26" BorderThickness="1,1,0,1" BorderBrush="Black"/>
<Border Grid.Column="27" BorderThickness="1,1,1,1" BorderBrush="Black"/>
<TextBlock Text="NO" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0" FontSize="12"/>
<TextBlock Text="削" HorizontalAlignment="Center" Grid.Column="1" VerticalAlignment="Center" Margin="0" FontSize="12"/>
<TextBlock Text="中項目名称" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0" FontSize="12"/>
<TextBlock Text="回数" HorizontalAlignment="Center" Grid.Column="3" VerticalAlignment="Center" Margin="0" FontSize="12"/>
<TextBlock Text="5" Grid.Row="0" Grid.Column="4" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="6" Grid.Row="0" Grid.Column="5" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="7" Grid.Row="0" Grid.Column="6" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="8" Grid.Row="0" Grid.Column="7" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="9" Grid.Row="0" Grid.Column="8" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="10" Grid.Row="0" Grid.Column="9" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="11" Grid.Row="0" Grid.Column="10" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="12" Grid.Row="0" Grid.Column="11" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="13" Grid.Row="0" Grid.Column="12" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="14" Grid.Row="0" Grid.Column="13" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="15" Grid.Row="0" Grid.Column="14" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="16" Grid.Row="0" Grid.Column="15" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="17" Grid.Row="0" Grid.Column="16" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="18" Grid.Row="0" Grid.Column="17" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="19" Grid.Row="0" Grid.Column="18" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="20" Grid.Row="0" Grid.Column="19" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="21" Grid.Row="0" Grid.Column="20" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="20" Grid.Row="0" Grid.Column="21" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="23" Grid.Row="0" Grid.Column="22" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="0" Grid.Row="0" Grid.Column="23" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="1" Grid.Row="0" Grid.Column="24" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="2" Grid.Row="0" Grid.Column="25" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="3" Grid.Row="0" Grid.Column="26" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
<TextBlock Text="4" Grid.Row="0" Grid.Column="27" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0"/>
</Grid>
<DataGrid Name="ScheduleDG" ItemsSource="{Binding ScheduleTable, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1" AutoGenerateColumns="False" HeadersVisibility="None"
IsReadOnly="False" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden"
SelectionUnit="CellOrRowHeader" SelectionMode="Extended" Padding="0" FontSize="10" BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Left" Width="690"
Margin="0,-1,-2,0" Height="Auto" AllowDrop="True" RowHeight="18"
PreviewMouseLeftButtonUp="ScheduleTable_PreviewMouseLeftButtonUp"
PreviewMouseLeftButtonDown="ScheduleTable_PreviewMouseLeftButtonDown" MouseMove="ScheduleDG_MouseMove">
<!--<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.CellSelectedCommand}"
CommandParameter="{Binding SelectedCells, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.StartCellCommand}"
CommandParameter="{Binding CurrentCell, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseRightClick">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.RightClickCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>-->
<DataGrid.Columns>
<DataGridTextColumn Header="NO" Width="22" IsReadOnly="True">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="FontSize" Value="10" />
<Setter Property="Margin" Value="0"/>
</Style>
</DataGridTextColumn.HeaderStyle>
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource rowNumberConverter}">
<Binding />
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}" />
</MultiBinding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
<DataGridTemplateColumn Header="削">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="TestCheckBox" VerticalAlignment="Center" HorizontalAlignment="Center"
IsChecked="{Binding isSelected, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="中項目名称" Binding="{Binding TaskName}" Width="123"/>
<DataGridTextColumn Header="回数" Width="30"/>
<!--<DataGridTemplateColumn Header="5" MaxWidth="10">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Background="{Binding _5, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="False">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}},
Path=DataContext.StartCellCommand}"
CommandParameter="{Binding CurrentCell, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>-->
<DataGridTextColumn Header="5" MaxWidth="10" FontSize="8" Width="10" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding _5, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Margin" Value="-1" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="" MaxWidth="10" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding _5_5, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Margin" Value="-1" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="6" MaxWidth="10" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding _6, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Margin" Value="-1" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="" MaxWidth="10" IsReadOnly="True" >
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding _3_5, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Margin" Value="-1" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="4" MaxWidth="10" IsReadOnly="True" >
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding _4, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Margin" Value="-1" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="" MaxWidth="9" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding _4_5, Converter={StaticResource ResourceKey=hourSlotColorConverter}, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Margin" Value="-1" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
the code-behind
using System;
using System.Collections.Generic;
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;
using System.ComponentModel.Composition;
using MainModule.Infrastructure.Interface;
using Widget5.ViewModel;
namespace Widget5.View
{
/// <summary>
/// Interaction logic for ExcelDisplay.xaml
/// </summary>
[Export(typeof(IMainModulePage))]
[ExportMetadata("WidgetName", "Widget5")]
[ExportMetadata("MenuNo", 1)]
[ExportMetadata("PageTitle", "WorkItemsPage")]
public partial class WorkItemsDisplay : UserControl, IMainModulePage
{
public WorkItemsDisplay()
{
DataContext = eVM;
InitializeComponent();
}
// inherit
public string WidgetName
{
get { return "Widget5"; }
}
public int MenuNo
{
get { return 1; }
}
public string PageTitle
{
get { return "WorkItemsPage"; }
}
ExcelGridViewModel eVM = new ExcelGridViewModel();
bool isClicked;
List<int> trueCells;
bool hasMoved;
private void ScheduleTable_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DependencyObject dep = (DependencyObject)e.OriginalSource;
// iteratively traverse the visual tree
while ((dep != null) &&
!(dep is DataGridCell))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep == null)
return;
if (dep is DataGridCell)
{
DataGridCell cell = dep as DataGridCell;
DataGridCellInfo cellInfo = new DataGridCellInfo(cell);
while ((dep != null) && !(dep is DataGridRow))
{
dep = VisualTreeHelper.GetParent(dep);
}
DataGridRow row = dep as DataGridRow;
hasMoved = false;
if (eVM.DoEndCell(cell, row, hasMoved))
ScheduleDG.UnselectAllCells();
ScheduleDG.CurrentCell = cellInfo;
}
isClicked = false;
}
private void ScheduleTable_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DependencyObject dep = (DependencyObject)e.OriginalSource;
// iteratively traverse the visual tree
while ((dep != null) &&
!(dep is DataGridCell))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep == null)
return;
if (dep is DataGridCell)
{
DataGridCell cell = dep as DataGridCell;
while ((dep != null) && !(dep is DataGridRow))
{
dep = VisualTreeHelper.GetParent(dep);
}
DataGridRow row = dep as DataGridRow;
trueCells = eVM.DoStartCell(cell, row);
}
isClicked = true;
}
private void Grid_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
private void ScheduleDG_MouseMove(object sender, MouseEventArgs e)
{
DependencyObject dep = (DependencyObject)e.OriginalSource;
// iteratively traverse the visual tree
while ((dep != null) &&
!(dep is DataGridCell))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep == null)
return;
if (dep is DataGridCell)
{
DataGridCell cell = dep as DataGridCell;
DataGridCellInfo cellInfo = new DataGridCellInfo(cell);
while ((dep != null) && !(dep is DataGridRow))
{
dep = VisualTreeHelper.GetParent(dep);
}
DataGridRow row = dep as DataGridRow;
if (isClicked && (trueCells.Count <= 1))
{
hasMoved = true;
eVM.DoEndCell(cell, row, hasMoved);
}
}
}
private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
{
isClicked = false;
hasMoved = false;
}
}
}
EDIT
I proceeded to multibind the datagridcell
's column and datacontext properties as parameters for my command
. An option I started before but set aside due to time constraints. Instead of looking for the datagridrow's index, I used the datacontext
to compare to my viewmodel
. Did the trick.