Hi,
Based on the image above, I would like to align the words "Action", "Adventure", "Arcade" to left most and align it to appear same height as the blue right arrow
my code for this is created dynamically:
Dim intRow As Integer
Dim intColumn As Integer
intRow = 0
intColumn = 0
Dim rd As RowDefinition
For Each abc In ArrayOfItems
Dim newButton As New Button
newButton.MaxHeight = 35
newButton.MaxWidth = 300
newButton.Background = Brushes.Transparent
newButton.BorderBrush = Brushes.Transparent
newButton.Tag = abc.application_category_id
Dim sp As New StackPanel
sp.Orientation = Orientation.Horizontal
sp.HorizontalAlignment = Windows.HorizontalAlignment.Left
sp.VerticalAlignment = Windows.VerticalAlignment.Center
Dim Image2 As New Image
Dim src As New Uri("/Images/chevron_blue.png", UriKind.Relative)
Dim img As New BitmapImage(src)
Image2.Width = 10
Image2.Height = 10
Image2.HorizontalAlignment = Windows.HorizontalAlignment.Left
Image2.VerticalAlignment = Windows.HorizontalAlignment.Left
Image2.Source = img
Dim LabelApp As New Label
LabelApp.Content = abc.category_name
LabelApp.FontWeight = FontWeights.Bold
LabelApp.FontSize = 9
LabelApp.MaxWidth = 270
LabelApp.Foreground = Brushes.Black
LabelApp.HorizontalContentAlignment = Windows.HorizontalAlignment.Left
LabelApp.VerticalAlignment = Windows.HorizontalAlignment.Left
sp.Children.Add(LabelApp)
sp.Children.Add(Image2)
newButton.Content = sp
Grid.SetColumn(newButton, intColumn)
Grid.SetRow(newButton, intRow)
gridCategoryGames.Children.Add(newButton)
intRow = intRow + 1
rd = New RowDefinition With {.Height = GridLength.Auto}
gridCategoryGames.RowDefinitions.Add(rd)
gridCategoryGames.UpdateLayout()
Next abc
End If
Ouch, that is an ugly way to do it :)
Fortunately WPF has something that will cut your code down substantially, the ItemsControl. As you already have ArrayOfItems which is obviously IEnumerable, you can craft you XAML like this:
<ItemsControl ItemsSource="{Binding ArrayOfItems}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate >
<StackPanel Orientation="Vertical" HorizontalAlignment="Right" >
<TextBlock Text="myText"/>
<Image Source="path to my image" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can then get rid of all that code that is manually creating items. The controls specified in ItemsControl.ItemTemplate will be repeated for every item in your list. The sky is the limit with this approach (there are literally thousands of examples of how to use this control).
Related
The problem
WPF Datagrid. A dataset with one table and three columns. Price, Discount, Total. The only editable column is the discount. If I enter the data with the grid fully visible, everything works as it should.
But if I narrow the window and enter the data, they get mixed up. And it just messes up the values that I can't see at the end of editing the current cell. Seems to do it out of spite!
The result when I view the whole grid by enlarging the window is this:
As you can see the totals are mixed!
The code
I've recreated a minimal example that you can test yourself.
XAML
<Window x:Class="DataGrid"
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:TestDatagrid"
mc:Ignorable="d"
Title="DataGrid" Height="450" Width="800" Loaded="Window_Loaded">
<Grid>
<DataGrid x:Name="grid" Margin="0,28,0,38"
CanUserDeleteRows="True"
CanUserSortColumns="True"
CanUserAddRows="False"
SelectionUnit="CellOrRowHeader"
CellEditEnding="grid_CellEditEnding"/>
</Grid>
</Window>
VB.NET
Imports System.Data
Imports System.Globalization
Public Class DataGrid
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
Dim ds As New DataSet
Dim tb As New DataTable("Orders")
Dim price As New DataColumn
price.ColumnName = "Price"
price.DataType = System.Type.GetType("System.Decimal")
tb.Columns.Add(price)
Dim discount As New DataColumn
discount.ColumnName = "Discount"
discount.DataType = System.Type.GetType("System.Decimal")
tb.Columns.Add(discount)
Dim total As New DataColumn
total.ColumnName = "Total"
total.DataType = System.Type.GetType("System.Decimal")
tb.Columns.Add(total)
For i As Integer = 0 To 20
Dim dr As DataRow = tb.NewRow()
dr("Price") = CDec((i + 1) * 10)
dr("Discount") = 0
dr("Total") = CDec((i + 1) * 10)
tb.Rows.Add(dr)
Next
ds.Tables.Add(tb)
grid.ItemsSource = ds.Tables(0).DefaultView
For Each c In grid.Columns
If c.Header = "Price" Then c.IsReadOnly = True
If c.Header = "Total" Then c.IsReadOnly = True
Next
End Sub
Private Sub grid_CellEditEnding(sender As Object, e As DataGridCellEditEndingEventArgs)
If e.EditAction = DataGridEditAction.Commit Then
Dim nfi As NumberFormatInfo = New NumberFormatInfo()
nfi.NumberDecimalSeparator = "."
Try
Dim tPrice As TextBlock = TryCast(grid.Columns(0).GetCellContent(e.Row), TextBlock)
Dim Price As Double = CDbl("0" & Replace(tPrice.Text, ".", ","))
Dim Discount As Double = CDbl("0" & Replace(TryCast(e.EditingElement, TextBox).Text, ".", ","))
Dim Total As Double = Price * (1 - (Discount / 100))
' Format the discount value
e.EditingElement.SetValue(TextBox.TextProperty, String.Format(nfi, "{0:0.00#}", Discount))
' Format and show the value on datagrid
TryCast(grid.Columns(2).GetCellContent(e.Row), TextBlock).Text = String.Format(nfi, "{0:0.00#}", Total)
' Update the value on grid
TryCast(grid.CurrentItem, DataRowView).Item(2) = Total
Catch ex As Exception
End Try
End If
End Sub
End Class
I really have no idea what's going on!
Thanks for any hints or help you will give me.
I really have no idea what's going on!
Virtualization, i.e. the elements that you wrongfully edit are resued for for performance reasons.
The obvious and recommended solution is to avoid editing the visual elemens directly and instead edit the columns of the underlying DataRowView.
The other solution is to disable the virtualization:
<DataGrid VirtualizingPanel.IsVirtualizing="False" EnableRowVirtualization="False" ... />
Below I am adding log entries divided by a horizontal line
Dim vLogText = vLog.Split("^")
Dim vRows As Integer = vLogText.Length - 1
For i As Integer = 0 To vRows
Dim Subrow As String = vLogText(i)
LogTB.Inlines.Add(Subrow)
LogTB.Inlines.Add(New Line With {.X1 = 0, .Y1 = 0, .X2 = 300, .Y2 = 0, .Stroke = New SolidColorBrush(Colors.Gray), .StrokeThickness = 4.0})
Next
This is OK if I want a preset length (say 300 in the above example) - but if it needs to stretch to the entire width of the container how is that accomplished?
Thanks
Added in reply to answer supplied by Anjum
Here is how the grid is added...
#Region "Right Grid"
Private Function RightGrid() As Grid
Try
Dim MainGrid As New Grid
Dim vGrid As New Grid
Dim SV As New ScrollViewer
With SV
.Name = "RightGrid_SV"
.Content = vGrid
.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
End With
RegisterControl(WorkOrder_Grid, SV)
MainGrid.Children.Add(SV)
'Add in the status and log
Dim LogLB As New Label
With LogLB
.Name = "WorkOrder_LogLB"
End With
RegisterControl(WorkOrder_Grid, LogLB)
vGrid.Children.Add(LogLB)
If IsNewRecord = True Then
'Add some help data
Dim SP As New StackPanel
Dim HeaderTB As New TextBlock
With HeaderTB
.Text = "ADDING A NEW WORK ORDER" & Environment.NewLine
.HorizontalAlignment = HorizontalAlignment.Center
.FontWeight = FontWeights.Bold
End With
Dim DatesHeaderTB As New TextBlock
With DatesHeaderTB
.Text = "Dates"
.TextDecorations = TextDecorations.Underline
End With
Dim DatesContentTB As New TextBlock
With DatesContentTB
.Text = "Enter the Work Order date and the date the Work needs to be completed by." & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim UnitHeaderTB As New TextBlock
With UnitHeaderTB
.Text = "Unit/Common Area"
.TextDecorations = TextDecorations.Underline
End With
Dim vUnit As String = "If the Work Order relates to a homeowners property, insert the details using the button. "
vUnit += "If the homeowners have a registered account they will be updated by email each time the Work Order status is changed!" & Environment.NewLine & Environment.NewLine
vUnit += "If the Work Order relates to a common area (e.g. Recreation grounds, Clubhouse...) just enter a short description of that area." & Environment.NewLine
Dim UnitContentTB As New TextBlock
With UnitContentTB
.Text = vUnit
.TextWrapping = TextWrapping.Wrap
End With
Dim TypeHeaderTB As New TextBlock
With TypeHeaderTB
.Text = "Work Type"
.TextDecorations = TextDecorations.Underline
End With
Dim TypeContentTB As New TextBlock
With TypeContentTB
.Text = "A short description of the type of work (e.g. Spinklers, Lights not working...)" & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim DetailsHeaderTB As New TextBlock
With DetailsHeaderTB
.Text = "Details/Instructions"
.TextDecorations = TextDecorations.Underline
End With
Dim DetailsContentTB As New TextBlock
With DetailsContentTB
.Text = "Add any more details or instructions to help the supplier." & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim SupplierHeaderTB As New TextBlock
With SupplierHeaderTB
.Text = "Supplier"
.TextDecorations = TextDecorations.Underline
End With
Dim SupplierContentTB As New TextBlock
With SupplierContentTB
.Text = "Insert the supplier using the button." & Environment.NewLine & Environment.NewLine & "You can still save the Work Order without entering a supplier, but the Work Order document will not be generated!" & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim EmailHeaderTB As New TextBlock
With EmailHeaderTB
.Text = "Supplier Email"
.TextDecorations = TextDecorations.Underline
End With
Dim EmailContentTB As New TextBlock
With EmailContentTB
.Text = "The default email address will be loaded when you insert the supplier (this can be overridden) " & Environment.NewLine & Environment.NewLine & "If the email address is blank, or not valid, the Work Order document will not be emailed, but generated as a PDF to print locally and mail!" & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim ImageHeaderTB As New TextBlock
With ImageHeaderTB
.Text = "Upload Image"
.TextDecorations = TextDecorations.Underline
End With
Dim ImageContentTB As New TextBlock
With ImageContentTB
.Text = "If you have a photograph of the work required, browse to the image. It will be included in the Work Order document." & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim CostHeaderTB As New TextBlock
With CostHeaderTB
.Text = "Estimated Cost"
.TextDecorations = TextDecorations.Underline
End With
Dim vCost As String = "If you enter an estimated cost the Work Order will be authorised up to that amount" & Environment.NewLine & Environment.NewLine
vCost += "If the supplier is unable to carry out the work for this amount or less (or the field is left at zero) the work will not be authorised and they must revert back to the sender with a quote!" & Environment.NewLine & Environment.NewLine
vCost += "When estimated costs are used a lot it is a good idea to check the supplier invoices do not regularly equal (or a dollar or two less) than the estimated amount!!" & Environment.NewLine
Dim CostContentTB As New TextBlock
With CostContentTB
.Text = vCost
.TextWrapping = TextWrapping.Wrap
End With
Dim SiteHeaderTB As New TextBlock
With SiteHeaderTB
.Text = "Smart Manager"
.TextDecorations = TextDecorations.Underline
.Foreground = New SolidColorBrush(Colors.Blue)
End With
Dim SiteContentTB As New TextBlock
With SiteContentTB
.Text = "You can also enter Work Orders, whilst on-site, with a Smart Phone or Tablet using Smart Manager!" & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
.Foreground = New SolidColorBrush(Colors.Blue)
End With
With SP.Children
.Add(HeaderTB)
.Add(DatesHeaderTB)
.Add(DatesContentTB)
.Add(UnitHeaderTB)
.Add(UnitContentTB)
.Add(TypeHeaderTB)
.Add(TypeContentTB)
.Add(DetailsHeaderTB)
.Add(DetailsContentTB)
.Add(SupplierHeaderTB)
.Add(SupplierContentTB)
.Add(EmailHeaderTB)
.Add(EmailContentTB)
.Add(ImageHeaderTB)
.Add(ImageContentTB)
.Add(CostHeaderTB)
.Add(CostContentTB)
.Add(SiteHeaderTB)
.Add(SiteContentTB)
End With
LogLB.Content = SP
End If
Return MainGrid
Catch ex As Exception
EmailError(ex)
Return Nothing
End Try
End Function
..and that is part of the main grid...
Private Function CentreGrid() As Grid
Try
Dim vGrid As New Grid
For i As Integer = 0 To 2
Dim vCol As New ColumnDefinition
If i = 1 Then
vCol.Width = New GridLength(5, GridUnitType.Auto)
End If
vGrid.ColumnDefinitions.Add(vCol)
Next
Dim vLeftGrid As Grid = LeftGrid()
Grid.SetColumn(vLeftGrid, 0)
vGrid.Children.Add(vLeftGrid)
Dim vGridSplitter As New GridSplitter
With vGridSplitter
.VerticalAlignment = Windows.VerticalAlignment.Stretch
.HorizontalAlignment = Windows.HorizontalAlignment.Center
.ResizeBehavior = GridResizeBehavior.PreviousAndNext
.Background = New SolidColorBrush(Colors.Blue)
.Width = 5
.Margin = New Thickness(5)
End With
Grid.SetColumn(vGridSplitter, 1)
vGrid.Children.Add(vGridSplitter)
Dim vRightGrid As Grid = RightGrid()
Grid.SetColumn(vRightGrid, 2)
vGrid.Children.Add(vRightGrid)
Return vGrid
Catch ex As Exception
EmailError(ex)
Return Nothing
End Try
End Function
When the page is opened this is what the horizontal line looks like (the one in blue)
..and this is what happens when the GridSplitter is moved to the left (same thing if the window is made larger)
Best would be to set a Binding for the X2 property and set it to ActualWidth of the TextBlock.
Below is C# code, you can change it to VB.net :
Line line = new Line() { Stroke = Brushes.Blue};
Binding binding = new Binding("ActualWidth");
binding.RelativeSource = new RelativeSource() { Mode=RelativeSourceMode.FindAncestor, AncestorType=typeof(TextBlock) };
BindingOperations.SetBinding(line, Line.X2Property, binding);
LogTB.Inlines.Add(line);
I would not use code-behind for something like this. Absolutely painful. You'll find WPF much easier to work with if you confine the majority of UI development to an XAML front-end. Try something like this
<Window x:Class="WpfApplication3.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:WpfApplication3"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="MyTemplate">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding}" />
<Line X1="0" X2="{Binding ActualWidth, RelativeSource={RelativeSource Self}}" Stroke="Black" />
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ItemsControl ItemTemplate="{StaticResource MyTemplate}">
<ItemsControl.Items>
<sys:String>One</sys:String>
<sys:String>Two</sys:String>
<sys:String>Three</sys:String>
</ItemsControl.Items>
</ItemsControl>
</Grid>
</Window>
I would like to ask you if it's possible to change autogeneradetcolumn cells color using Converter?
My Datagrid in xaml:
<DataGrid ItemsSource="{Binding FillDG}" x:Name="ListHoliday"
HorizontalAlignment="Left" Height="186" VerticalAlignment="Top"
Width="880" Grid.Column="1" Margin="10.4,103,0,0" Grid.Row="1"/>
codebehind:
Dim sql As String
Dim startDate As Date = dtStartV.SelectedDate
Dim endDate As DateTime = dtEndV.SelectedDate
Dim numberOfDays As Integer = ((endDate.Date) - (startDate.Date)).Days + 1
sql = "SELECT Enumber, HType, HStartDate, HEndDate from tbl_HolidayLog"
Dim da As New SqlDataAdapter(sql, cnn)
Dim dt As New DataSet
da.Fill(dt, "Holiday")
With Me.ListHoliday
.ItemsSource = dt.Tables("Holiday").DefaultView
End With
For dayCount As Integer = -1 To (numberOfDays - 0)
Dim currentDate As Date = Convert.ToDateTime(startDate.AddDays(dayCount))
Dim formatedD As String = currentDate.ToString("dd/MM")
If currentDate.DayOfWeek <> DayOfWeek.Saturday AndAlso currentDate.DayOfWeek <> DayOfWeek.Sunday Then
Dim c1 As New DataGridTextColumn
c1.Header = Format(currentDate, "MMMM") & vbCrLf & formatedD
ListHoliday.Columns.Add(c1)
For Each item As DataRowView In ListHoliday.ItemsSource
Dim saDate As DateTime = item.Item("HStartDate")
Dim enDate As DateTime = item.Item("HEndDate")
Dim numberOfHeader As Integer = ((enDate.Date) - (saDate.Date)).Days - 0
For dayCountHeader As Integer = 0 To (numberOfHeader - 0)
count(dayCountHeader) = 0
Next dayCountHeader
Next
End If
Next dayCount
I don't have any name for columns because 4 of theme are from table and the rest (dates) are created programmatically. And I would like to color cells in those programmatically created columns. Converter could be like:
Dim V As SolidColorBrush = Brushes.White
Dim holi As New HolidayLog
For Each hitem As DataRowView In holi.dgMyTeamView.ItemsSource
Dim hType As String = hitem.Item("HType")
If hType.Trim() = "Vacation" Then
V = Brushes.Blue
End If
Next
Return V
But I don't know how can I bind this to each autogenerated date cell/column.
Thank you very much for any advice!
You can set CellStyle of DataGrid which will be picked up by autogenerated columns cell.
<DataGrid>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background"
Value="{Binding Converter={StaticResource ColorConverter}}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
UPDATE:
You can pass the Column to converter and color only in case Column is the one you want to color.
<DataGrid>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background"
Value="{Binding Column,
RelativeSource={RelativeSource Self},
Converter={StaticResource ColorConverter}}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
Converter:
DataGridColumn column = value as DataGridColumn;
// Check for property name here.
if (column != null && column.Header.ToString() == "Name")
{
return Brushes.Blue;
}
return Brushes.White;
I am building a WPF D.A.L. generator.
In my main page, I have a DataGrid populated with a list of the tables in my database.
I also have an extra checkbox column called ShouldInclude? I intend to use this to determine whether or not the table should be included in the generation... yes if checked, no if un-checked.
Because I am populating the DataGrid's ItemSource with a strongly typed list of some basic info TableName, Schema, Columns, I am now finding myself at a loss as to how I can get the checked value of the checkbox so I can make that determination on whether to include it or not.
Here are my functions that build out my table typing class code files:
Private Sub GenerateTyping(ByVal _DG As DataGrid)
For Each i As TableTyping In _DG.Items
'check if should be generated
Dim _TString As String = String.Empty
Using _sr As New StreamReader(Common.GetPath() & "Class Templates\CSharp\Typing\XXX_Typing.txt")
_TString = _sr.ReadToEnd()
_sr.Close()
End Using
Dim _FN As String = i.Name & "_Typing.cs"
Dim _Props As New StringBuilder()
Dim _CL As List(Of ColumnTyping) = i.Columns
For Each col In _CL
With _Props
Dim _PropStr As String = "public " & Common.GetClrType(col.Type) & " " & col.Name & " { get; set; }"
.AppendLine(" " & _PropStr)
End With
Next
'Write the new class files
_TString = _TString.Replace("##TABLENAME##", If(i.Schema.Length > 0, i.Schema & "_", "") & i.Name).Replace("##THE_PROPERTIES##", _Props.ToString())
If Not Directory.Exists(FilePath & "\Typing\") Then
Directory.CreateDirectory(FilePath & "\Typing\")
End If
Using _sw As New StreamWriter(FilePath & "\Typing\" & If(i.Schema.Length > 0, i.Schema & "_", "") & i.Name & "_Typing.cs", False)
_sw.Write(_TString)
_sw.Close()
End Using
_TString = String.Empty
_Props.Clear()
Next
End Sub
Partial Public Class TableTyping
Public Property ID As Integer
Public Property Name As String
Public Property Schema As String
Public Property Columns As List(Of ColumnTyping)
End Class
Partial Public Class ColumnTyping
Public Property ID As Integer
Public Property Name As String
Public Property Type As SqlDataType
Public Property Length As Integer
Public Property DefaultValue As String
Public Property Precision As Integer
Public Property Scale As Integer
End Class
My datagrid simply consists of 3 columns. Include?, Table Schema, Table Name, which is populated via:
<DataGrid EnableRowVirtualization="True" Name="dgTables" IsReadOnly="True" AutoGenerateColumns="False" FontFamily="Calibri" FontSize="14" IsEnabled="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Include?">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Tag="{Binding ID}" HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="True" Name="ckTblInclude" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding Schema}" Header="Schema"/>
<DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
</DataGrid.Columns>
</DataGrid>
AND:
_tg.ItemsSource = _Table
Private Sub GrabTables()
Dim _Db As Database = Srv.Databases(DBName)
Dim _Tbls As TableCollection = _Db.Tables
Dim _tct As Integer = _Tbls.Count
Dim _i As Integer = 0
For i = 0 To _tct - 1
If Not _Tbls(i).IsSystemObject Then
_i += 1
_Tables.Add(New TableTyping() With {
.ID = _i,
.Name = _Tbls(i).Name,
.Schema = _Tbls(i).Schema,
.Columns = ProcessColumns(_Tbls(i).Columns)})
End If
Next
_TCount = _Tables.Count
End Sub
_Tables is a List(of TableTyping)
How can I do the Include? check inside the GenerateTyping procedure?
I had to change my checkbox template to the following:
<CheckBox Tag="{Binding ID}" HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding Include, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Name="ckTblInclude" />
And change the _Tables list to populate via:
Private Sub GrabTables()
Dim _Db As Database = Srv.Databases(DBName)
Dim _Tbls As TableCollection = _Db.Tables
Dim _tct As Integer = _Tbls.Count
Dim _i As Integer = 0
For i = 0 To _tct - 1
If Not _Tbls(i).IsSystemObject Then
_i += 1
_Tables.Add(New TableTyping() With {
.ID = _i,
.Name = _Tbls(i).Name,
.Schema = _Tbls(i).Schema,
.Columns = ProcessColumns(_Tbls(i).Columns),
.Include = True})
End If
Next
_TCount = _Tables.Count
End Sub
I've been hunting through stackoverflow for a while to answer this.
I've got a Listview who's items are Listviews whose children are actually a list(of string) that is a member of the parent listviewitem.
Drag and drop functionality is the goal. However this is proving hard for a variety of reasons, one of which is casting. I need to get the type before I do a direct cast to make it work - at least I think that will get me over one problem.
However I can't get this syntax to even begin to work, so I'll start here:
Dim itemType = listView.ItemContainerGenerator.ItemFromContainer(listViewItem)
Dim g As Type = GetType(itemtype)
This is the entire drag n drop implementation I'm trying:
Dim startpoint As Point
Public Sub List_PreviewMouseLeftButtonDown(sender As Object, e As MouseEventArgs)
' Store the mouse position
startpoint = e.GetPosition(Nothing)
End Sub
Private Sub List_MouseMove(sender As Object, e As MouseEventArgs)
Dim mousePos As Point = e.GetPosition(Nothing)
Dim diff As Vector = startpoint - mousePos
If e.LeftButton = MouseButtonState.Pressed And Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance Or Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance Then
Dim listView As ListView = DirectCast(sender, ListView)
Dim listViewItem As ListViewItem = FindAncestor(Of ListViewItem)(DirectCast(e.OriginalSource, DependencyObject))
Dim itemType = listView.ItemContainerGenerator.ItemFromContainer(listViewItem)
Dim g As Type = GetType(itemtype)
Dim item As String = DirectCast(listView.ItemContainerGenerator.ItemFromContainer(listViewItem), String)
Dim dragData As New DataObject("myFormat", item)
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Move)
End If
End Sub
Private Shared Function FindAncestor(Of T As DependencyObject)(current As DependencyObject) As T
Do
If TypeOf current Is T Then
Return DirectCast(current, T)
End If
current = VisualTreeHelper.GetParent(current)
Loop While current IsNot Nothing
Return Nothing
End Function
Private Sub DropList_DragEnter(sender As Object, e As DragEventArgs)
If Not e.Data.GetDataPresent("myFormat") OrElse sender = e.Source Then
e.Effects = DragDropEffects.None
End If
End Sub
Private Sub DropList_Drop(sender As Object, e As DragEventArgs)
If e.Data.GetDataPresent("myFormat") Then
Dim contact As String = TryCast(e.Data.GetData("myFormat"), String)
Dim listView As ListView = TryCast(sender, ListView)
listView.Items.Add(contact)
End If
End Sub
Here is the nested listView:
<!--DataContext="{StaticResource RcpdInsertViewSource}" This is a collectionviewsource.
RCPDInsert has a list(of string) member that is created from a single string property
and whose order needs to be alterable.
Eg rcpdInsert.template="[stuff] [more stuff]" so rcpdInsert.templateList = list(of String) from template.split("] [") -->
<ListView Grid.Column="1" Grid.Row="1" ItemsSource="{Binding}"
PreviewMouseLeftButtonDown="List_PreviewMouseLeftButtonDown"
PreviewMouseMove="List_MouseMove"
Drop="DropList_Drop"
DragEnter="DropList_DragEnter"
AllowDrop="True">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBox Text="{Binding Path=cpID}"></TextBox>
<TextBox Text="{Binding Path=fieldRef}"></TextBox>
<ListView ItemsSource="{Binding Path=InsertsList}" >
<ListView.ItemTemplate>
<DataTemplate DataType="DataClasses1:RcpdInsert.template" >
<StackPanel Orientation="Horizontal" Grid.Row="0">
<TextBlock Text="{Binding}" Margin="5" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Goal: Drag and drop reordering of child listviews, ideally being able to pull individual items from one child listView to another. When saved, the code behind will actually concat the strings back together and update the template member.
For context here are the relevant members of RcpdInsert:
Sub SetupInsertList()
_insertsList = template.Split(" ").ToList()
For Each item In InsertsList
Dim t = item
RcpdList.Add(RcpdSet.RpcdListShared.Where(Function(x) x.insertID = t).ToList())
Next
End Sub
Public Property RcpdList As New List(Of List(Of Rcpd))
Private Property _insertsList As New List(Of String)
Public Property InsertsList As List(Of String)
Get
If _insertsList.Count = 0 Then setupInsertList()
Return _insertsList
End Get
Set(value As List(Of String))
Dim combine As String = value.Aggregate("", Function(current, i) current + (i & " "))
template = combine
End Set
End Property
The casting is one issue with this, I'm hoping being able to do this part means that the others will be easier to resolve.
Thanks in advance to anyone who can help :)