Silverlight using vb.net - silverlight-4.0

Dear Experts,
I am using VS2010, VB.NET, Silverlight 4.
I need the code for 2 way data binding the UI controls with VB class .Please find the code which i am working
xaml
<Grid x:Name="LayoutRoot" Background="White" Width="300" Height="300" Loaded="LayoutRoot_Loaded">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Rectangle Fill="blue" Width="100" Height="10" Grid.ColumnSpan="2" Margin="152,26,148,28"></Rectangle>
<TextBlock Text="Name" Grid.Row="1" Grid.Column="0"></TextBlock>
<TextBlock Text="Address 1" Grid.Row="2" ></TextBlock>
<TextBlock Text="Address 2" Grid.Row="3" Grid.Column="0"></TextBlock>
<TextBlock Text="City" Grid.Row="4" Grid.Column="0"></TextBlock>
<TextBlock Text="State" Grid.Row="5" Grid.Column="0"></TextBlock>
<TextBlock Text="Zipcode" Grid.Row="6" Grid.Column="0"></TextBlock>
<TextBox x:Name="txtName" Text="{Binding Name, Mode=TwoWay}" Grid.Row="1" Grid.Column="1" Height="20" Width="100"></TextBox>
<TextBox x:Name="txtAddress1" Text="{Binding Address1, Mode=TwoWay}" Grid.Row="2" Grid.Column="1" Height="20" Width="100"></TextBox>
<TextBox x:Name="txtAddress2" Text="{Binding Address2, Mode=TwoWay}" Grid.Row="3" Grid.Column="1" Height="20" Width="100"></TextBox>
<TextBox x:Name="txtCity" Text="{Binding City, Mode=TwoWay}" Grid.Row="4" Grid.Column="1" Height="20" Width="100"></TextBox>
<TextBox x:Name="txtState" Text="{Binding State, Mode=TwoWay}" Grid.Row="5" Grid.Column="1" Height="20" Width="100"></TextBox>
<TextBox x:Name="txtZipcode" Text="{Binding Zipcode, Mode=TwoWay}" Grid.Row="6" Grid.Column="1" Height="20" Width="100"></TextBox>
<Button Grid.Row="7" Grid.Column="0" Width="50" Content="Save" x:Name="btnSave" Click="btnSave_Click"></Button>
<Button Grid.Row="7" Grid.Column="1" Width="50" Content="Clear" x:Name="btnClear" Click="btnClear_Click"></Button>
</Grid>
VB code:
Partial Public Class MainPage
Inherits UserControl
Dim address As Address
Public Sub New()
address = New Address("nameit", "address1", "address2", "Alexandria", "VA", "22314")
txtName.DataContext = address
'txtAddress1.DataContext = address
'txtAddress2.DataContext = address
'txtCity.DataContext = address
'txtState.DataContext = address
'txtZipcode.DataContext = address
'LayoutRoot.DataContext = address
InitializeComponent()
End Sub
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
MessageBox.Show(address.Name + " " + address.Address1 + " " + address.Address2 + " " + address.City + " " + address.State + " " + address.Zipcode)
End Sub
Private Sub btnClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClear.Click
MessageBox.Show("click")
End Sub
Private Sub LayoutRoot_Loaded(ByVal sender As System.Object, ByVal e As RoutedEventArgs)
'to focus on particular text box - System.Windows.Browser.HtmlPage.Plugin.Focus() txt_Name.Focus()
End Sub
End Class
Address.vb
Imports System.ComponentModel
Public Class Address
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private _name As String
Private _address1 As String
Private _address2 As String
Private _city As String
Private _state As String
Private _zipcode As String
Public Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
If PropertyChangedEvent IsNot Nothing Then
RaiseEvent PropertyChanged(Me, e)
End If
End Sub
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
OnPropertyChanged(New PropertyChangedEventArgs("Name"))
End Set
End Property
Public Property Address1() As String
Get
Return _address1
End Get
Set(ByVal value As String)
_address1 = value
OnPropertyChanged(New PropertyChangedEventArgs("Address1"))
End Set
End Property
Public Property Address2() As String
Get
Return _address2
End Get
Set(ByVal value As String)
_address2 = value
OnPropertyChanged(New PropertyChangedEventArgs("Address2"))
End Set
End Property
Public Property City() As String
Get
Return _city
End Get
Set(ByVal value As String)
_city = value
OnPropertyChanged(New PropertyChangedEventArgs("City"))
End Set
End Property
Public Property State() As String
Get
Return _state
End Get
Set(ByVal value As String)
_state = value
OnPropertyChanged(New PropertyChangedEventArgs("State"))
End Set
End Property
Public Property Zipcode() As String
Get
Return _zipcode
End Get
Set(ByVal value As String)
_zipcode = value
OnPropertyChanged(New PropertyChangedEventArgs("Zipcode"))
End Set
End Property
Public Sub New(ByVal name As String, ByVal address1 As String, ByVal address2 As String, ByVal city As String, ByVal state As String, ByVal zipcode As String)
Me.Name = name
Me.Address1 = address1
Me.Address2 = address2
Me.City = city
Me.State = state
Me.Zipcode = zipcode
End Sub
End Class
Kind regards,
Kumar

Set the datacontext attribute of LayoutRoot to you address. Then in your xaml do something like this:
<TextBox ... Text="{Binding Name}" />
Here is a simple example:
XAML of MAinPage
<UserControl x:Class="VBSLTest.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="TextBox1" VerticalAlignment="Top" Width="192" Text="{Binding Name}" />
</Grid>
</UserControl>
VB Code Behind:
Partial Public Class MainPage
Inherits UserControl
Public Sub New()
InitializeComponent()
Dim address As Address
Address = New Address()
LayoutRoot.DataContext = address
End Sub
End Class
VB Simple Address Class:
Public Class Address
Private _name As String = "Some Text"
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
End Class
Notice I am only setting DataContext once and that is for LayoutRoot.

Related

How to bind a list(of string) on a combobox via Binding

I can't bind a list (of string) as the source of a combobox via Binding.
It works with
cb_ListTexts.ItemsSource = cKiosque.ListTexts
but not with
cb_ListTexts.DataContext = cKiosque
<Window x:Class="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:BindingWPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ComboBox x:Name="cb_ListTexts" SelectedValue="{Binding Path=ckiosque.ListTexts}" HorizontalAlignment="Left" Height="51" Margin="97,121,0,0" VerticalAlignment="Top" Width="367"/>
<TextBox x:Name="tb_SelectedItem" Text="{Binding Path=SelectedValue, ElementName=cb_ListTexts}" HorizontalAlignment="Left" Height="28" Margin="243,235,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="288"/>
</Grid>
</Window>
Imports System.ComponentModel
Class MainWindow
Private Property cKiosque As New Kiosque
Sub New()
' Cet appel est requis par le concepteur.
InitializeComponent()
' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
cb_ListTexts.DataContext = cKiosque.ListTexts
'cb_ListTexts.ItemsSource = cKiosque.ListTexts
End Sub
End Class
Class Kiosque
Implements INotifyPropertyChanged
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Private Property _ListTexts As New List(Of String)
Private Property _SelectedItem As String
Sub New()
ListTexts.Add("toto")
ListTexts.Add("titi")
End Sub
Public Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
If Not PropertyChangedEvent Is Nothing Then
RaiseEvent PropertyChanged(Me, e)
End If
End Sub
Public Property ListTexts As List(Of String)
Get
Return _ListTexts
End Get
Set(value As List(Of String))
_ListTexts = value
'OnPropertyChanged(New PropertyChangedEventArgs("ListTexts"))
End Set
End Property
Public Property SelctedItem As String
Get
Return _SelectedItem
End Get
Set(value As String)
_SelectedItem = value
End Set
End Property
End Class
Where is the error ?
DataContext is different from ItemsSource.
Exemple :
You set your Grid DataContext to point to your Kiosque.
Then, each child and subchilds will inherit their DataContext from your Grid (cascading).
Now, if a binding is found, it will try to apply a binding to a matching property name from the {Binding Path=MyProperty} in your Kiosque object (known as a ViewModel)
To debug, I suggest you to set this.DataContext = Kiosque. In the constructor of your window. Thus, no need to set DataContext.
Try with something like
<Grid>
<ComboBox SelectedItem="{Binding SelctedItem}" ItemsSource="{Binding ListTexts}" HorizontalAlignment="Left" Height="51" Margin="97,121,0,0" VerticalAlignment="Top" Width="367"/>
<TextBox Text="{Binding Path=ListTexts}" HorizontalAlignment="Left" Height="28" Margin="243,235,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="288"/>
</Grid>
Be careful : you typed SelctedItem instead of SelectedItem.
You don't need to use SelectedValue because you are binding a string. Selected value is to bind to a sub property of the item (eg : Engine to display the engine of SelectedCar.Engine)

Getting selected ItemsControl Item

Currentlly creating my windows 10 App, and I'm trying to move a rectangle on canvas following mvvm pattern. The code below works but I broke mvvm by using a uielemnt in my viewmodel PointerDragEvent.
Dim rec = TryCast(e.OriginalSource, Button)
Dim selrecitem = TryCast(rec.DataContext, RectItem)
Question
Is there a non hacky/proper way of doing this?
How can I retrieve the item I click on and pass it to my viewmodel?
All items on canvas will be dynamically created.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App11"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
x:Class="App11.MainPage"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.DataContext>
<local:myviewmodel/>
</Grid.DataContext>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="8*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="11*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ItemsControl x:Name="itemsControl" Grid.Column="1" Grid.Row="1" ItemsSource="{Binding myrectangles, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="ManipulationDelta">
<Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="PointerDrag"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button x:Name="PageItem" Background="Transparent" BorderBrush="DodgerBlue" Width="{Binding Width}" Height="{Binding Height}" ManipulationMode="TranslateX, TranslateY" IsHitTestVisible="{Binding IsChecked, ElementName=SelectToolButton, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Command="{Binding SendMyDC, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<Button.RenderTransform>
<CompositeTransform TranslateX="{Binding X}" TranslateY="{Binding Y}"/>
</Button.RenderTransform>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Viewmodel
Public Class myviewmodel
Implements INotifyPropertyChanged
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private _myrectangles As New ObservableCollection(Of RectItem)
Public Property myrectangles As ObservableCollection(Of RectItem)
Get
Return _myrectangles
End Get
Set(value As ObservableCollection(Of RectItem))
_myrectangles = value
NotifyPropertyChanged()
End Set
End Property
Public Sub New()
Dim newrect As New RectItem
newrect.Height = 100
newrect.Width = 150
newrect.X = 50
newrect.Y = 50
_myrectangles.Add(newrect)
End Sub
Public Sub PointerDrag(sender As Object, e As ManipulationDeltaRoutedEventArgs)
Dim dx_point = e.Delta.Translation.X
NotifyPropertyChanged()
Dim dy_point = e.Delta.Translation.Y
NotifyPropertyChanged()
Dim rec = TryCast(e.OriginalSource, Button)
Dim selrecitem = TryCast(rec.DataContext, RectItem)
selrecitem.X += dx_point
selrecitem.Y += dy_point
End Sub
End Class
RectItemClass
Public Class RectItem
Implements INotifyPropertyChanged
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public Property X As Double
Get
Return m_X
End Get
Set
m_X = Value
NotifyPropertyChanged()
End Set
End Property
Private m_X As Double
Public Property Y As Double
Get
Return m_Y
End Get
Set
m_Y = Value
NotifyPropertyChanged()
End Set
End Property
Private m_Y As Double
Public Property Width As Double
Get
Return m_Width
End Get
Set
m_Width = Value
NotifyPropertyChanged()
End Set
End Property
Private m_Width As Double
Public Property Height As Double
Get
Return m_Height
End Get
Set
m_Height = Value
NotifyPropertyChanged()
End Set
End Property
Private m_Height As Double
End Class
Edit #1 Instead of using an item control I used an ListView/Listbox and binded the selected item to a property in my vewimodel. With the listview there is some problem getting the item presenter aligned with the item its's presenting and with listbox, the pointer up event doesn't fire.
<ListView x:Name="itemsControl" Grid.Column="1" Grid.Row="1" ItemsSource="{Binding myrectangles, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Background="#FFF2F2F2" SelectedItem="{Binding selectedrec, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="ManipulationDelta">
<Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="PointerDrag"/>
</Core:EventTriggerBehavior>
<Core:EventTriggerBehavior EventName="PointerPressed">
<Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="PointerPressed"/>
</Core:EventTriggerBehavior>
<!--<Core:EventTriggerBehavior EventName="PointerReleased">
<Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="Up"/>
</Core:EventTriggerBehavior>-->
</Interactivity:Interaction.Behaviors>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White">
</Canvas>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<!--<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>-->
<ListView.ItemTemplate>
<DataTemplate>
<Rectangle x:Name="PageItem" Width="{Binding Width}" Height="{Binding Height}" Fill="Transparent" Stroke="DodgerBlue" ManipulationMode="TranslateX, TranslateY" IsHitTestVisible="{Binding IsChecked, ElementName=SelectToolButton, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" >
<Rectangle.RenderTransform>
<CompositeTransform TranslateX="{Binding X}" TranslateY="{Binding Y}"/>
</Rectangle.RenderTransform>
</Rectangle>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Updated ViewModel
Public _selectedrec As New RectItem
Public Property selectedrec As RectItem
Get
Return _selectedrec
End Get
Set(value As RectItem)
_selectedrec = value
NotifyPropertyChanged()
End Set
End Property
Public Sub PointerDrag(sender As Object, e As ManipulationDeltaRoutedEventArgs)
Dim dx_point = e.Delta.Translation.X
NotifyPropertyChanged()
Dim dy_point = e.Delta.Translation.Y
NotifyPropertyChanged()
selectedrec.X += dx_point
NotifyPropertyChanged()
selectedrec.Y += dy_point
NotifyPropertyChanged()
End Sub
Example of problems
No itemcontainerstyle - When trying to drag object snaps to 0,0 of canvas
MyHalfFix - Uncomment the ItemContainerStyle - Everything works correctly what im aiming for
The Overall Problem when implemented in the actual program
The red Item is the listviewitem presenter. It's being drawn correctly but the positioning is not aligned with the drawn rectangle it always snaps to point 0,0 of canvas. I can make it transparent but as you can also see when drawing the rectangle it doesn't follow the cursor correctly
You can use a InvokeCommandAction for the ManipulationDelta event will avoid breaking the MVVM pattern. InvokeCommandAction can pass a parameter to the viewmodel and we can pass the selecteditem by the parameter. The object of ManipulationDelta should be the button instead of the ItemsControl and the InvokeCommandAction will work, what you actually drag is the button itself. Updated code as follows:
XAML
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Name="root">
...
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button x:Name="PageItem" Background="Transparent" BorderBrush="DodgerBlue" Width="{Binding Width}" Height="{Binding Height}" ManipulationMode="TranslateX, TranslateY" IsHitTestVisible="{Binding IsChecked, ElementName=SelectToolButton, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" >
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="ManipulationDelta" SourceObject="{Binding ElementName=PageItem}">
<Core:InvokeCommandAction Command="{Binding DataContext.SendMyDC, ElementName=root}" CommandParameter="{Binding}"></Core:InvokeCommandAction>
<Core:CallMethodAction TargetObject="{Binding DataContext, ElementName=root, Mode=OneWay}" MethodName="PointerDrag" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<Button.RenderTransform>
<CompositeTransform TranslateX="{Binding X}" TranslateY="{Binding Y}"/>
</Button.RenderTransform>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
myviewmodel
Public Class myviewmodel
...
Private m_sendCommand As IDelegateCommand
Public Property SendMyDC As IDelegateCommand
Get
Return m_sendCommand
End Get
Protected Set(value As IDelegateCommand)
m_sendCommand = value
End Set
End Property
Public Sub New()
Me.SendMyDC = New DelegateCommand(AddressOf ExecuteSendMyDC)
Dim newrect As New RectItem
newrect.Height = 100
newrect.Width = 150
newrect.X = 50
newrect.Y = 50
_myrectangles.Add(newrect)
End Sub
Dim selrecitem As RectItem
Public Sub PointerDrag(sender As Object, e As ManipulationDeltaRoutedEventArgs)
Dim dx_point = e.Delta.Translation.X
NotifyPropertyChanged()
Dim dy_point = e.Delta.Translation.Y
NotifyPropertyChanged()
'Dim rec = TryCast(e.OriginalSource, Button)
'Dim selrecitem = TryCast(rec.DataContext, RectItem)
If selrecitem IsNot Nothing Then
selrecitem.X += dx_point
selrecitem.Y += dy_point
End If
End Sub
Private Sub ExecuteSendMyDC(param As Object)
selrecitem = CType(param, RectItem)
End Sub
End Class
DelegateCommand class
Public Class DelegateCommand
Implements IDelegateCommand
Private _execute As Action(Of Object)
Private _canExecute As Func(Of Object, Boolean)
#Region "Constructors"
Public Sub New(execute As Action(Of Object), canExecute As Func(Of Object, Boolean))
Me._execute = execute
Me._canExecute = canExecute
End Sub
Public Sub New(execute As Action(Of Object))
Me._execute = execute
Me._canExecute = AddressOf Me.AlwaysCanExecute
End Sub
#End Region
#Region "IDelegateCommand"
Private Function AlwaysCanExecute(param As Object) As Boolean
Return True
End Function
Public Function CanExecute(parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
Return _canExecute(parameter)
End Function
Public Event CanExecuteChanged(sender As Object, e As EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged
Public Sub Execute(parameter As Object) Implements System.Windows.Input.ICommand.Execute
_execute(parameter)
End Sub
Public Sub RaiseCanExecuteChanged() Implements IDelegateCommand.RaiseCanExecuteChanged
RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
End Sub
#End Region
End Class
Public Interface IDelegateCommand
Inherits ICommand
Sub RaiseCanExecuteChanged()
End Interface
DelegateCommand is a common class for you further invoking other commands. More details please reference Command binding inside DataTemplate.

UWP App Dynamic Pivot MVVM always creating new instance of viewmodel

I need help with my code. I'm trying to achieve a layout like in the image below
So far I have created an UWP Windows 10 app and it looks like this below
I'm using Vb.net but C# is welcomed as well. Trying to follow Mvvm pattern and also using no extra mvvm framework - just xaml behaviours.
My End goal is to be able to double click a page and then create a new tab with the header bind to the page name . For test purposes I added an add page and add tab button because the double click isn't working correctly. Every time a new item is added to the collection for the tabs, it isn't reflected in the ui because the data template is creating a new instance of my viewmodel which is what I don't want to happen. The temporary add buttons calls the correct methods and does the functionality I want to achieve with the double click. Ill post the shortest example of my code below.
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="1">
<Button Width="200" VerticalAlignment="Stretch" Content="Add Page" Foreground="White">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Click">
<Core:CallMethodAction MethodName="AddPage" TargetObject="{Binding Mode=OneWay}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Button>
<Button Width="200" VerticalAlignment="Stretch" Content="Add Tab" Foreground="White">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Click">
<Core:CallMethodAction MethodName="AddSection" TargetObject="{Binding Mode=OneWay}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Button>
</StackPanel>
<Pivot Grid.Column="1" Grid.Row="2" Foreground="White" ItemsSource="{Binding PivotItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Foreground="White"/>
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate>
<GridView ItemsSource="{Binding Result, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="DoubleTapped">
<Core:CallMethodAction MethodName="AddSection"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<GridView.ItemTemplate>
<DataTemplate>
<Grid x:Name="CanvasControl" Background="#00000000" Width="200" Height="200" >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="8*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="11*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Canvas Grid.Column="1" Grid.Row="1" Margin="10" Background="White" DoubleTapped="Canvas_DoubleTapped" />
<TextBox Grid.Column="1" Grid.Row="2" Foreground="White" FontSize="14" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" Padding="0" Background="{x:Null}" BorderBrush="{x:Null}" Text="{Binding CanvasCollection[0].CanvasName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Column="1" Grid.Row="0" Foreground="White" FontSize="12" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="10" IsHitTestVisible="False" Text="{Binding CanvasCollection[0].CanvasMaster}" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
</Grid>
Viewmodel
Public Class ProjectDataViewModel
Implements INotifyPropertyChanged
Private WindowData As New CanvasData
Private randomdata As New DataGenerators
Private m_PivotItems As New ObservableCollection(Of PivotSection)
Private Canvas_Collection As New ObservableCollection(Of CanvasData)
Private mycollection As New CanvasData
Private pivotItem_Home As New PivotSection() With {.Name = "Home"}
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public Property PropertyCollectionItemName As String
Get
Return WindowData.CanvasName
End Get
Set(value As String)
WindowData.CanvasName = value
End Set
End Property
Public Property PropertyCollectionItemMaster As String
Get
Return WindowData.CanvasMaster
End Get
Set(value As String)
WindowData.CanvasMaster = value
End Set
End Property
Public Property CanvasCollection As ObservableCollection(Of CanvasData)
Get
Return Canvas_Collection
End Get
Private Set(value As ObservableCollection(Of CanvasData))
Canvas_Collection = value
NotifyPropertyChanged()
End Set
End Property
Public Property my_collection As CanvasData
Get
Return mycollection
End Get
Set(value As CanvasData)
mycollection = value
NotifyPropertyChanged()
End Set
End Property
Public Property PivotItems() As ObservableCollection(Of PivotSection)
Get
Return m_PivotItems
End Get
Set
m_PivotItems = Value
NotifyPropertyChanged()
End Set
End Property
Public Sub AddSection()
Dim pivotItem_New As New PivotSection() With {.Name = "Item Header " + PivotItems.Count.ToString}
m_PivotItems.Add(pivotItem_New)
End Sub
Public Sub AddPage()
Dim Newpage As New PivotItemContent
Newpage.CanvasCollection.Add(New CanvasData With {.CanvasName = "Page " + pivotItem_Home.Result.Count.ToString, .CanvasMaster = "Master "})
pivotItem_Home.Result.Add(newpage)
End Sub
Sub New()
Dim indexPage As New PivotItemContent
PivotItems = New ObservableCollection(Of PivotSection)
PivotItems.Add(pivotItem_Home)
indexPage.CanvasCollection.Add(New CanvasData With {.CanvasName = "Home", .CanvasMaster = "Master"})
pivotItem_Home.Result.Add(indexPage)
End Sub
PivotSection Class
End Class
Public Class PivotSection
Implements INotifyPropertyChanged
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public Property Name() As String
Get
Return m_Name
End Get
Set
m_Name = Value
End Set
End Property
Private m_Name As String
Public Property SystemLabel() As String
Get
Return m_SystemLabel
End Get
Set
m_SystemLabel = Value
End Set
End Property
Private m_SystemLabel As String
Public Property Result() As ObservableCollection(Of PivotItemContent)
Get
Return m_Result
End Get
Set
m_Result = Value
NotifyPropertyChanged()
End Set
End Property
Private m_Result As New ObservableCollection(Of PivotItemContent)
'Public Sub New()
' Result = New ObservableCollection(Of PivotGroup)
'End Sub
End Class
PivotContent Class
Public Class PivotItemContent
Implements INotifyPropertyChanged
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Canvas_Collection As New ObservableCollection(Of CanvasData)
Public Property CanvasCollection As ObservableCollection(Of CanvasData)
Get
Return Canvas_Collection
End Get
Private Set(value As ObservableCollection(Of CanvasData))
Canvas_Collection = value
NotifyPropertyChanged()
End Set
End Property
Private Page_Name As String
Public Property PageName As String
Get
Return Page_Name
End Get
Set(value As String)
Page_Name = value
NotifyPropertyChanged()
End Set
End Property
Private Page_Master As String
Public Property PageMaster As String
Get
Return Page_Master
End Get
Set(value As String)
Page_Master = value
NotifyPropertyChanged()
End Set
End Property
End Class
CavasDataclass
Imports Windows.UI
Public Class CanvasData
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Private _CanvasMaster_Name As String
Private _CanvasName As String
Public Property CanvasMaster() As String
Get
Return _CanvasMaster_Name
End Get
Set(ByVal value As String)
_CanvasMaster_Name = value
NotifyPropertyChanged()
End Set
End Property
Public Property CanvasName As String
Get
Return _CanvasName
End Get
Set(value As String)
_CanvasName = value
NotifyPropertyChanged()
End Set
End Property
End Class
In this case you can have a TabList page, that will contain the GridView with all the opened tabs. Each item will use a ItemTemplate in which you can add a close button and a preview.
To enable opening a tab, you can set the GridView's IsItemClickEnabled property to true and then handle the ItemClick event to know which tab was clicked by the user. You can then use this information to navigate to a TabDetail page, which you create.
Creating new tab will be also simple - just adding a new item into the GridView and navigating to it directly.

Binding with for grid Column

I have a grid with 3 columns. I want that when you click on a button, the first column changes width.
This is the code, but doesn't work. Why?
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width= "{Binding Path=PositionCol,Mode=TwoWay}" x:Name="column1"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch"/>
<Button Content="Button" Grid.Column="2" HorizontalAlignment="Left" Height="38" Margin="4,4,4,4" VerticalAlignment="Top" Width="55" Click="Button_Click"/>
</Grid>
Imports System.ComponentModel
Public Class Window1
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private _PositionCol As Double
Public Property PositionCol As Double
Get
Return _PositionCol
End Get
Set(value As Double)
_PositionCol = value
OnPropertyChanged("PositionCol")
End Set
End Property
Private Sub OnPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
PositionCol = 70
End Sub
End Class
The main issue is that ColumnDefinition.Width is typed as GridLength, not Double. Change your property:
Private _PositionCol As GridLength = New GridLength(200)
Public Property PositionCol As GridLength
Get
Return _PositionCol
End Get
Set(value As GridLength)
_PositionCol = value
OnMyPropertyChanged("PositionCol")
End Set
End Property
' ...
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
PositionCol = New GridLength(70)
End Sub
Also, make sure you are setting the DataContext in the constructor:
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.DataContext = Me
End Sub
You'll probably want to tweak the column definitions some, too:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=PositionCol,Mode=TwoWay}"/>
<ColumnDefinition Width="2"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>

Binding Image to ListView in VB.net (Windows Store)

I have a problem with binding images to ListView in VB.net. I'm building an app that will resize, convert and compress images, but I would like the selected images to be displayed in a ListView, alongside the image name.
This is the XAML code for the ListView:
<ListView x:Name="ListView" ItemsSource="{Binding Image}" HorizontalAlignment="Left" Height="481" Margin="10,275,0,0" VerticalAlignment="Top" Width="1069" BorderBrush="#FF003859" Foreground="White" Background="#42FFFFFF" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" BorderThickness="6,0,6,6" FontSize="16" SelectionMode="Multiple">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="vertical">
<Grid Height="160" Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Width="160" Height="160">
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding ImageID}" Stretch="Uniform" />
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="10,0,0,0">
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextStyle}" TextWrapping="NoWrap"/>
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is the code for Image class:
Imports System.Collections.ObjectModel
Public Class Image</code>
Private _Title As String
Private _ImageID As BitmapImage
Public ReadOnly Property Title() As String
Get
Return _Title
End Get
End Property
Public ReadOnly Property Image() As BitmapImage
Get
Return _ImageID
End Get
End Property
Public Sub New(ByVal Title As String, ByVal ImageID As BitmapImage)
_Title = Title
_ImageID = ImageID
End Sub
End Class
And here is the code for the button that adds the images in the ListView:
Private Async Sub AddImage_Click(sender As Object, e As RoutedEventArgs) Handles AddImage.Click
Dim picker As New FileOpenPicker()
picker.SuggestedStartLocation = PickerLocationId.Desktop
picker.ViewMode = PickerViewMode.Thumbnail
picker.FileTypeFilter.Add(".jpg")
picker.FileTypeFilter.Add(".jpeg")
picker.FileTypeFilter.Add(".bmp")
picker.FileTypeFilter.Add(".gif")
picker.FileTypeFilter.Add(".png")
picker.FileTypeFilter.Add(".tiff")
picker.FileTypeFilter.Add(".tga")
Dim files As IReadOnlyList(Of StorageFile) = Await picker.PickMultipleFilesAsync
Dim imagearray(10000000) As BitmapImage
Dim i = 0
If files.Count > 0 Then
For Each file In files
imagearray(i) = New BitmapImage(New Uri(file.Path))
i += 1
Next
Dim j = 0
For Each file In files
ListView.Items.Add(New Image(file.Name, imagearray(j)))
j += 1
Next
End If
End Sub
Please help me out with this.
Edit:
ListView XAML Code:
<ListView x:Name="ListView" HorizontalAlignment="Left" Height="481" Margin="10,275,0,0" VerticalAlignment="Top" Width="1069" BorderBrush="#FF003859" Foreground="White" Background="#42FFFFFF" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" BorderThickness="6,0,6,6" FontSize="16" SelectionMode="Multiple">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="vertical">
<Grid Height="160" Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Width="160" Height="160">
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding ImageID}" Stretch="Uniform" />
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="10,0,0,0">
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextStyle}" TextWrapping="NoWrap"/>
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Image Class:
Imports System.Collections.ObjectModel
Public Class Image
Private _Title As String
Private _Image As BitmapImage
Public ReadOnly Property Title() As String
Get
Return _Title
End Get
End Property
Public ReadOnly Property ImageID() As BitmapImage
Get
Return _Image
End Get
End Property
Public Sub New(ByVal Title As String, ByVal ImageID As BitmapImage)
_Title = Title
_Image = ImageID
End Sub
End Class
The button:
Dim ImageCollection As New Collection(Of Image)
Private Async Sub AddImage_Click(sender As Object, e As RoutedEventArgs) Handles AddImage.Click
Dim picker As New FileOpenPicker()
picker.SuggestedStartLocation = PickerLocationId.Desktop
picker.ViewMode = PickerViewMode.Thumbnail
picker.FileTypeFilter.Add(".jpg")
picker.FileTypeFilter.Add(".jpeg")
picker.FileTypeFilter.Add(".bmp")
picker.FileTypeFilter.Add(".gif")
picker.FileTypeFilter.Add(".png")
picker.FileTypeFilter.Add(".tiff")
picker.FileTypeFilter.Add(".tga")
Dim files As IReadOnlyList(Of StorageFile) = Await picker.PickMultipleFilesAsync
Dim imagearray(10000000) As BitmapImage
Dim i = 0
If files.Count > 0 Then
For Each file In files
imagearray(i) = New BitmapImage(New Uri(file.Path))
i += 1
Next
Dim j = 0
For Each file In files
ImageCollection.Add(New Image(file.Name, imagearray(j)))
j += 1
Next
For Each file In files
ListView.ItemsSource = ImageCollection
Next
End If
End Sub
This is the code I have now, but the images are still not shown. What is wrong?
Here is the new edit:
ListView XAML Code:
<ListView x:Name="ListView" DataContext="{Binding Image}" HorizontalAlignment="Left" Height="481" Margin="10,275,0,0" VerticalAlignment="Top" Width="1069" BorderBrush="#FF003859" Foreground="White" Background="#42FFFFFF" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" BorderThickness="6,0,6,6" FontSize="16" SelectionMode="Multiple">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="vertical">
<Grid Height="160" Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Width="160" Height="160">
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding ImageProperty}" Stretch="Uniform" />
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="10,0,0,0">
<TextBlock Text="{Binding TitleProperty}" Style="{StaticResource TitleTextStyle}" TextWrapping="NoWrap"/>
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Image Class:
Imports System.Collections.ObjectModel
Public Class Image
Implements INotifyPropertyChanged
Private ImageX As BitmapImage
Private TitleX As String
Public ReadOnly Property ImageProperty() As BitmapImage
Get
Return ImageX
End Get
End Property
Public ReadOnly Property TitleProperty() As String
Get
Return TitleX
End Get
End Property
Public Sub New(ByVal ImageTitle As String, ByVal ImageID As BitmapImage)
TitleX = ImageTitle
ImageX = ImageID
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public Sub NotifyPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
And the Button with ImageCollection Class:
Dim ImageCollection As New ImageCollectionClass
Private Async Sub AddImage_Click(sender As Object, e As RoutedEventArgs) Handles AddImage.Click
Dim picker As New FileOpenPicker()
picker.SuggestedStartLocation = PickerLocationId.Desktop
picker.ViewMode = PickerViewMode.Thumbnail
picker.FileTypeFilter.Add(".jpg")
picker.FileTypeFilter.Add(".jpeg")
picker.FileTypeFilter.Add(".bmp")
picker.FileTypeFilter.Add(".gif")
picker.FileTypeFilter.Add(".png")
picker.FileTypeFilter.Add(".tiff")
picker.FileTypeFilter.Add(".tga")
Dim files As IReadOnlyList(Of StorageFile) = Await picker.PickMultipleFilesAsync
Dim imagearray(10000000) As BitmapImage
Dim i = 0
If files.Count > 0 Then
For Each file In files
imagearray(i) = New BitmapImage(New Uri(file.Path))
i += 1
Next
Dim j = 0
For Each file In files
ImageCollection.AddImage(file.Name, imagearray(j))
j += 1
Next
For Each file In files
ListView.ItemsSource = ImageCollection
Next
End If
End Sub
Public Class ImageCollectionClass
Public ImageCollectionClass As New ObservableCollection(Of Image)
Public Sub AddImage(ByVal ImageTitleInClass As String, ByVal ImageIDInClass As BitmapImage)
ImageCollectionClass.Add(New Image(ImageTitleInClass, ImageIDInClass))
End Sub
End Class
But it doesn't work. Tell me please what's wrong now!
Your original loop is rather convoluted (thought that's not the immediate cause of the program). All of this code:
Dim imagearray(10000000) As BitmapImage
Dim i = 0
If files.Count > 0 Then
For Each file In files
imagearray(i) = New BitmapImage(New Uri(file.Path))
i += 1
Next
Dim j = 0
For Each file In files
ImageCollection.AddImage(file.Name, imagearray(j))
j += 1
Next
For Each file In files
ListView.ItemsSource = ImageCollection
Next
End If
could be collapsed to:
For Each file In files
ImageCollection.AddImage(file.Name, New BitmapImage(New Uri(file.Path)))
Next
ListView.ItemsSource = ImageCollection.ImageCollectionClass
Note you need ImageCollectionClass as your ItemsSource.
From there, you can incorporate code from Scenario 2 of the XAML Images Sample and modify to get the image via SetSourceAsync:
Dim fileStream As IRandomAccessStream
For Each file In files
fileStream = Await file.OpenAsync(Windows.Storage.FileAccessMode.Read)
Dim bitmapImage As New BitmapImage()
Await bitmapImage.SetSourceAsync(fileStream)
ImageCollection.AddImage(file.Name, bitmapImage)
Next
ListView.ItemsSource = ImageCollection.ImageCollectionClass