Following code is okey in vb.net and Windows Form Application.
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim comboSource As New Dictionary(Of String, String)()
comboSource.Add("1", "Sunday")
comboSource.Add("2", "Monday")
comboSource.Add("3", "Tuesday")
comboSource.Add("4", "Wednesday")
comboSource.Add("5", "Thursday")
comboSource.Add("6", "Friday")
comboSource.Add("7", "Saturday")
ComboBox1.DataSource = New BindingSource(comboSource, Nothing)
ComboBox1.DisplayMember = "Value"
ComboBox1.ValueMember = "Key"
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim key As String = DirectCast(ComboBox1.SelectedItem, KeyValuePair(Of String, String)).Key
Dim value As String = DirectCast(ComboBox1.SelectedItem, KeyValuePair(Of String, String)).Value
MessageBox.Show(key & " " & value)
End Sub
End Class
I want to convert above codes to WPF Application.
xaml
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox x:Name="ComboBox1" Height="20" Width="150"/>
<Button x:Name="Button1" Height="20" Width="80" VerticalAlignment="Top" Content="Click Me"/>
</Grid>
</Window>
vb.net
Class MainWindow
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Dim comboSource As New Dictionary(Of String, String)()
comboSource.Add("1", "Sunday")
comboSource.Add("2", "Monday")
comboSource.Add("3", "Tuesday")
comboSource.Add("4", "Wednesday")
comboSource.Add("5", "Thursday")
comboSource.Add("6", "Friday")
comboSource.Add("7", "Saturday")
ComboBox1.DataSource = New BindingSource(comboSource, Nothing)
ComboBox1.DisplayMember = "Value"
ComboBox1.ValueMember = "Key"
End Sub
Private Sub Button1_Click(sender As Object, e As RoutedEventArgs) Handles Button1.Click
Dim key As String = DirectCast(ComboBox1.SelectedItem, KeyValuePair(Of String, String)).Key
Dim value As String = DirectCast(ComboBox1.SelectedItem, KeyValuePair(Of String, String)).Value
MessageBox.Show(key & " " & value)
End Sub
End Class
Linked picture shows the errors: https://prnt.sc/kcig7j
So, how can I solve that errors?
The WPF equivalents for the WinForms properties are as follows:
DataSource -> ItemsSource
DisplayMember -> DisplayMemberPath
ValueMember -> SelectedValuePath
Also, bear in mind that you can set properties in either code-behind or in XAML, so your ComboBox definition could look like this:
<ComboBox x:Name="ComboBox1" Height="20" Width="150" DisplayMemberPath="Value" SelectedValuePath="Key" />
I personally would find it easier to set the ItemsSource property in code-behind:
Dim comboSource As New Dictionary(Of String, String)()
comboSource.Add("1", "Sunday")
comboSource.Add("2", "Monday")
comboSource.Add("3", "Tuesday")
comboSource.Add("4", "Wednesday")
comboSource.Add("5", "Thursday")
comboSource.Add("6", "Friday")
comboSource.Add("7", "Saturday")
ComboBox1.ItemsSource = comboSource
W.R.T. your event handler, you have a double cast to KeyValuePair(Of String, String); you should probably cast only once and store the casted value in a variable. But in this particular case, you don't have to even cast the SelectedItem. Instead, you can cast the sender to a ComboBox and read the Text and Value properties:
Dim cmb As ComboBox = sender
MessageBox.Show($"Key: {cmb.SelectedValue}, Value: {cmb.Text}')
Also note that you can just as easily use an Integer for your dictionary key as a String:
Dim days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
Dim comboSource = days
.Select(Function(x, index) (item:=x, index:=index+1))
.ToDictionary(Function(x) x.index, Function(x) x.item)
Related
xaml codes are here;
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock x:Name="TextBlock1" Width="100" Height="20" Background="Blue"/>
</Grid>
</Window>
vb.net codes are here;
Class MainWindow
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Dim myBrush1 As New SolidColorBrush(CType(ColorConverter.ConvertFromString("#FF0000"), Color))
TextBlock1.Background = myBrush1
End Sub
End Class
The codes above are okey.
My question is here;
I want to use
TextBlock1.Background = "myBrush" & 1
instead of
TextBlock1.Background = myBrush1
TextBlock1.Background = "myBrush" & 1 is not working.
So, how can I make TextBlock1.Background = "myBrush" & 1 is working?
You can't use a string as a variable name in that way.
What you can do instead is have some kind of collection which associates an object (in this case a Brush) with a string. A Dictionary will serve this purpose well here.
You could have something like:
Class MainWindow
Private myBrushes As New Dictionary(Of String, Brush)
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
Dim myBrush1 As New SolidColorBrush(DirectCast(ColorConverter.ConvertFromString("#FF0000"), Color))
myBrushes.Add("myBrush1", myBrush1)
TextBlock1.Background = myBrushes("myBrush" & "1")
End Sub
End Class
The value of myBrushes("myBrush1") is the SolidColorBrush myBrush1. You can add as many brushes as you want to the dictionary.
I am trying to build a progressbar using MVVM. Basically, I have a main xaml and 2 UserControls, 1 for progressbar 1 for datagrid.
I am bit new and I followed this question and answer but I havent got any success. Below is my ViewModel code and Xaml code. Basically I have 2 problems,
1-How to bind CustomerModels or if even possible CustomerViewModel? I tried to use Itemsource binding direcly with ObservableCollection which I am filling with my delegateCommand that runs with a backgroundworker but no success. I tried without delegate and backgroundworker,simply using as below.
Me.myLoadCommand = New Commands.LoadCustomerModels()
What am I doing wrong?
<UserControl.Resources>
<vm:CustomerModelsVM x:Key="Customerobj"></vm:CustomerModelsVM>
</UserControl.Resources>
<Grid >
<DataGrid x:Name="grdData" ItemsSource="{Binding Path=CustomerModels}"/>
</Grid>
2-How to bind CurrentProgressBar? I tried to bind the progress bar status same way but I believe my ViewModel and Xaml somehow has no connection.
<UserControl x:Class="ucProgressBar"
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"
mc:Ignorable="d"
>
<Grid>
<ProgressBar Value="{Binding CurrentProgress, Mode=OneWay}" Visibility="{Binding ProgressVisibility}"></ProgressBar>
<TextBlock Text="{Binding ElementName=myProgressBar, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
Namespace ViewModels
Public Class CustomerModelsVM
Implements ICustomerModelsVM
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Private ReadOnly worker As BackgroundWorker
Private m_currentProgress As Integer
Private _CustomerModels As New ObservableCollection(Of Models.CustomerModel)
Private mySaveCommand As ICommand
Private myLoadCommand As ICommand
Public Sub New()
Me.worker = New BackgroundWorker()
Me.myLoadCommand = New DelegateCommand(Sub() Me.worker.RunWorkerAsync(), AddressOf Progressisbusy)
' _CustomerModels = getCustomerModels()
Me.worker = New BackgroundWorker()
AddHandler Me.worker.DoWork, AddressOf Me.DoWork
AddHandler Me.worker.ProgressChanged, AddressOf Me.ProgressChanged
End Sub
Private Sub ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
Me.CurrentProgress = e.ProgressPercentage
End Sub
Private Function Progressisbusy() As Boolean
Return Not Me.worker.IsBusy
End Function
Private Sub OnPropertyChanged(Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public ReadOnly Property CustomerModels() As ObservableCollection(Of Models.CustomerModel)
Get
Return _CustomerModels
End Get
End Property
Public ReadOnly Property btnClick() As ICommand
Get
Return myLoadCommand
End Get
End Property
Public Property CurrentProgress() As Integer
Get
Return Me.m_currentProgress
End Get
Private Set(value As Integer)
If Me.m_currentProgress <> value Then
Me.m_currentProgress = value
OnPropertyChanged(Me.CurrentProgress)
End If
End Set
End Property
Private Sub DoWork(sender As Object, e As DoWorkEventArgs)
_CustomerModels = getCustomerModels()
End Sub
Function getCustomerModels() As ObservableCollection(Of Models.CustomerModel) Implements ICustomerModelsVM.GetCustomerModels
If _CustomerModels Is Nothing OrElse _CustomerModels.Count = 0 Then myLoadCommand.Execute(_CustomerModels)
Return _CustomerModels
End Function
You can add the viewmodel as DataContext of the main window which is holding the two user controls. Please refer the below code.
<UserControl x:Class="UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<DataGrid x:Name="grdData" Height="200" ItemsSource="{Binding Path=CustomerModels}"/>
</Grid>
</UserControl>
<UserControl x:Class="UserControl2"
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" >
<StackPanel>
<Button Command="{Binding LoadCommand}">Test</Button>
<ProgressBar Value="{Binding CurrentProgress, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="20" Width="200"
Visibility="{Binding ProgressVisibility}"></ProgressBar>
</StackPanel>
</UserControl>
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StakOveflw"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<local:UserControl1/>
<local:UserControl2/>
</StackPanel>
</Grid>
</Window>
Class MainWindow
Public Sub New()
InitializeComponent()
Me.DataContext = New CustomerModelsVM()
End Sub
End Class
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Imports Microsoft.Practices.Prism.Commands
Imports System.Threading
Public Class CustomerModelsVM
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Private ReadOnly worker As BackgroundWorker
Private m_currentProgress As Integer
Private mySaveCommand As ICommand
Private myLoadCommand As ICommand
Public Property LoadCommand() As ICommand
Get
Return myLoadCommand
End Get
Set(ByVal value As ICommand)
myLoadCommand = value
End Set
End Property
Public Sub New()
Me.worker = New BackgroundWorker()
_CustomerModels = New ObservableCollection(Of CustomerModel)()
AddHandler Me.worker.DoWork, AddressOf Me.DoWork
AddHandler Me.worker.ProgressChanged, AddressOf Me.ProgressChanged
Me.worker.WorkerReportsProgress = True
myLoadCommand = New DelegateCommand(AddressOf LoadClick)
' _CustomerModels = getCustomerModels()
End Sub
Private Sub LoadClick()
Me.worker.RunWorkerAsync()
End Sub
Private Sub ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
CurrentProgress = e.ProgressPercentage
End Sub
Private Function Progressisbusy() As Boolean
Return Not Me.worker.IsBusy
End Function
Private Function CalculateProgress(total As Integer, complete As Integer) As Integer
' avoid divide by zero error
If total = 0 Then
Return 0
End If
' calculate percentage complete
Dim result = CDbl(complete) / CDbl(total)
Dim percentage = result * 100.0
' make sure result is within bounds and return as integer;
Return Math.Max(0, Math.Min(100, CInt(Math.Truncate(percentage))))
End Function
Private Sub OnPropertyChanged(Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Private _CustomerModels As ObservableCollection(Of CustomerModel)
Public Property CustomerModels() As ObservableCollection(Of CustomerModel)
Get
Return _CustomerModels
End Get
Set(ByVal value As ObservableCollection(Of CustomerModel))
_CustomerModels = value
End Set
End Property
Public Sub GetCustomers()
Dim total As Integer
total = 10000
For index = 1 To total
Dim a As CustomerModel = New CustomerModel()
a.NewProperty = "test" + index.ToString()
Application.Current.Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Background, Function()
_CustomerModels.Add(a)
End Function)
worker.ReportProgress(CalculateProgress(total, index))
Next
End Sub
Public ReadOnly Property btnClick() As ICommand
Get
Return myLoadCommand
End Get
End Property
Public Property CurrentProgress() As Integer
Get
Return Me.m_currentProgress
End Get
Private Set(value As Integer)
Me.m_currentProgress = value
OnPropertyChanged("CurrentProgress")
End Set
End Property
Private Sub DoWork(sender As Object, e As DoWorkEventArgs)
_CustomerModels = getCustomerModels()
End Sub
Function getCustomerModels() As ObservableCollection(Of CustomerModel)
GetCustomers()
'Application.Current.Dispatcher.BeginInvoke(Windows.Threading.DispatcherPriority.Normal, New Action(Of Integer)(AddressOf GetCustomers), 3)
Return _CustomerModels
End Function
End Class
Public Class CustomerModel
Private newPropertyValue As String
Public Property NewProperty() As String
Get
Return newPropertyValue
End Get
Set(ByVal value As String)
newPropertyValue = value
End Set
End Property
End Class
I would like answer my question with a working solution. In my case problem was simply, I had to use dispatcher to clear my oberservable collection. So my Do_work function looks like as following. I didnt clear the observable collection before I start binding. Adding this simple line makes my code working.
Private Sub DoWork(sender As Object, e As DoWorkEventArgs)
Application.Current.Dispatcher.BeginInvoke(Sub() Me.CustomerModels.Clear())
' Me.CustomerModels.Clear()
For index = 1 To 100
Dim CustomerModel As New CustomerModel With { _
.age = 30 + index, _
.name = "testName" & index, _
.surname = "testSurname" & index, _
.Id = index}
Application.Current.Dispatcher.BeginInvoke(Sub() CustomerModels.Add(CustomerModel))
' CustomerModels.Add(CustomerModel)
Thread.Sleep(100)
worker.ReportProgress(CalculateProgress(100, index))
Next
End Sub
I have a UI element which is a listview that contains in it another listview (one vertical and one horizontal).
The Itemsource of the the First listview is an ObservableCollection of Objects, which in turn contains ObservableCollection of a child object. Both have INotifyPropertyChanged interface implemented and call the PropetyChanged Event when usefull.
If I added new child object, I see my second listview update, but when I change a value, I do not see anything change. Is there anything I must do to refresh my UI element in this case ?
Here is my listview
<ListView x:Name="LstInfoEtape" Margin="0,0,0,0" Style="{StaticResource BaseListView}" Grid.Row="2" Grid.Column="1" >
<ListView.ItemTemplate>
<DataTemplate>
<ListView x:Name="LstEtape" ItemsSource="{Binding LstEtapes}" Background="#00000000" SelectionChanged="ListView_SelectionChanged" ScrollViewer.ScrollChanged="ListView_ScrollChanged">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Border Width="82" CornerRadius="4" BorderBrush="{Binding ColorSelected}" BorderThickness="3,3,3,3" Visibility="{Binding EtapeVisible}" Background="{Binding ColorBackground}" MouseDown="Border_MouseDown">
<Grid Width="80" >
<Grid.RowDefinitions>
<RowDefinition Height="19"/>
</Grid.RowDefinitions>
<TextBlock Margin="2,0,2,0" x:Name="TxtDateRappel" TextWrapping="Wrap" Grid.Row="0" Text="{Binding DateRappelTerminaison,StringFormat=yyyy-MM-dd,NotifyOnSourceUpdated=True}" Visibility="{Binding EtapeVisible}" FontSize="12" Foreground="{Binding ColorForeground}" />
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The classes I use are those
Public Class SuiviOperationLite
Implements INotifyPropertyChanged
Private _strNom As String
Private _oLstProcessusLite As ObservableCollection(Of ContratProcessusLite) ' Not implemented yet
Private _oLstEtapeLite As ObservableCollection(Of ContratProcessusEtapeLite)
Public Sub New(ByVal strNom As String,
ByVal oLstProcessusLite As ObservableCollection(Of ContratProcessusLite),
ByVal oLstEtapeLite As ObservableCollection(Of ContratProcessusEtapeLite))
Constructor(strNom, oLstProcessusLite, oLstEtapeLite)
End Sub
Private Sub Constructor(ByVal strNom As String,
ByVal oLstProcessusLite As ObservableCollection(Of ContratProcessusLite),
ByVal oLstEtapeLite As ObservableCollection(Of ContratProcessusEtapeLite))
_strNom = strNom
_oLstProcessusLite = oLstProcessusLite
_oLstEtapeLite = oLstEtapeLite
End Sub
Public Property Nom() As String
Get
Return _strNom
End Get
Set(ByVal value As String)
_strNom = value
End Set
End Property
Public Property LstContratProcessus() As ObservableCollection(Of ContratProcessusLite)
Get
Return _oLstProcessusLite
End Get
Set(ByVal value As ObservableCollection(Of ContratProcessusLite))
_oLstProcessusLite = value
End Set
End Property
Public Property LstEtapes() As ObservableCollection(Of ContratProcessusEtapeLite)
Get
Return _oLstEtapeLite
End Get
Set(ByVal value As ObservableCollection(Of ContratProcessusEtapeLite))
_oLstEtapeLite = value
End Set
End Property
Protected Friend Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
Public Class ContratProcessusEtapeLite
Implements INotifyPropertyChanged
Private _lngId As Long
Private _lngIdSequenceTravail As Long
Private _boolSelected As Boolean
Private _strETapeVisible As String
Private _strColorBackGround As String
Private _strColorForeGround As String
Private _dateRappelTerminaison As Date
Private _oParent As DAL.SuiviOperationLite
Public Sub New(ByVal oParent As DAL.SuiviOperationLite,
ByVal lngId As Long,
ByVal lngIdSequenceTravail As Long,
ByVal boolSelected As Boolean,
ByVal strEtapeVisible As String,
ByVal strColorBackGround As String,
ByVal strColorForeGround As String,
ByVal dateRappelTerminaison As Date)
Constructor(oParent,
lngId, _
lngIdSequenceTravail, _
boolSelected, _
strEtapeVisible, _
strColorBackGround, _
strColorForeGround, _
dateRappelTerminaison)
End Sub
Private Sub Constructor(ByVal oParent As DAL.SuiviOperationLite,
ByVal lngId As Long,
ByVal lngIdSequenceTravail As Long,
ByVal boolSelected As Boolean,
ByVal strEtapeVisible As String,
ByVal strColorBackGround As String,
ByVal strColorForeGround As String,
ByVal dateRappelTerminaison As Date)
_oParent = oParent
_lngId = lngId
_lngIdSequenceTravail = lngIdSequenceTravail
_boolSelected = boolSelected
_strETapeVisible = strEtapeVisible
_strColorBackGround = strColorBackGround
_strColorForeGround = strColorForeGround
_dateRappelTerminaison = dateRappelTerminaison
End Sub
Public Property Parent() As DAL.SuiviOperationLite
Get
Return _oParent
End Get
Set(ByVal value As DAL.SuiviOperationLite)
_oParent = value
End Set
End Property
Public Property ID() As Long
Get
Return _lngId
End Get
Set(ByVal value As Long)
_lngId = value
NotifyPropertyChanged("ID")
End Set
End Property
Public Property IdClientContratSequenceTravail() As Long
Get
Return _lngIdSequenceTravail
End Get
Set(ByVal value As Long)
_lngIdSequenceTravail = value
NotifyPropertyChanged("IdSequence")
End Set
End Property
Public Property Selected() As Boolean
Get
Return _boolSelected
End Get
Set(ByVal value As Boolean)
_boolSelected = value
NotifyPropertyChanged("Selected")
End Set
End Property
Public ReadOnly Property ColorSelected As String
Get
If _boolSelected Then
Return "#FF4394DF"
Else
Return "#FF000000"
End If
End Get
End Property
Public Property EtapeVisible() As String
Get
Return _strETapeVisible
End Get
Set(ByVal value As String)
_strETapeVisible = value
NotifyPropertyChanged("Visible")
End Set
End Property
Public Property ColorBackground() As String
Get
Return _strColorBackGround
End Get
Set(ByVal value As String)
_strColorBackGround = value
NotifyPropertyChanged("Background")
End Set
End Property
Public Property ColorForeground() As String
Get
Return _strColorForeGround
End Get
Set(ByVal value As String)
_strColorForeGround = value
NotifyPropertyChanged("Foreground")
End Set
End Property
Public Property DateRappelTerminaison() As Date
Get
Return _dateRappelTerminaison
End Get
Set(ByVal value As Date)
_dateRappelTerminaison = value
NotifyPropertyChanged("DateRappel")
End Set
End Property
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
_oParent.NotifyPropertyChanged("Child")
End Sub
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
End Class
And here are the functions (There are more processing to get the collection of items, but I doubt it's really relevant :
Private Sub LoadList(colSuivi as ObservableCollection(Of SuiviProductionLite)
LstInfoEtape.ItemsSource = colSuivi
End Sub
Private Sub Border_MouseDown(sender As System.Object, e As System.Windows.Input.MouseButtonEventArgs)
Dim oBorder As Border
Dim oEtapeLite As DAL.ContratProcessusEtapeLite
Select Case e.Source.GetType.ToString
Case "System.Windows.Controls.TextBlock"
Dim oTxt As TextBlock = e.Source
Dim oGrid As Grid = oTxt.Parent
_oCurBorderDet = oGrid.Parent
Case "System.Windows.Controls.Border"
Dim oBrd As Border = e.Source
_oCurBorderDet = e.Source
End Select
If Not _oCurBorderDet.DataContext.GetType().FullName.Equals("MS.Internal.NamedObject") Then
oEtapeLite = _oCurBorderDet.DataContext
oEtapeLite.Selected = True
End If
End Sub
When I do some tracing, I know that both PropertyChanged Events are call wheter I click on my UI. If I do a manual "Items.Refresh", I can also see the UI being changed, but I want to remove that manual refresh as it refresh everything, not only the item just modified, which, when facing a lot of data, takes much more time.
I see one problem
Public Property IdClientContratSequenceTravail() As Long
Get
Return _lngIdSequenceTravail
End Get
Set(ByVal value As Long)
_lngIdSequenceTravail = value
NotifyPropertyChanged("IdSequence")
End Set
End Property
Wrong name in Notify
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 :)
I have a WPF window with a TreeView that contains a checkbox at each node. I want to be able to capture the state of the checkboxes but I don't know how. (I am trying to do this without writing much of the code in XML)
Here is what I have in the XML:
<TreeView Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="1" Height="200" HorizontalAlignment="Left" Margin="126,299,0,0" Name="TreeView1" VerticalAlignment="Top" Width="220" ItemsSource="{Binding}" DataContext="{Binding}">
</TreeView>
And in the VB Code:
Dim site As ELSite
Dim sites() As ELSite
Dim parentCheckbox = New CheckBox
Dim parentNode = New TreeViewItem
parentCheckbox.Content = "All Sites"
parentNode.Header = parentCheckbox
For Each osite In sites
Dim childNode = New TreeViewItem
Dim childCheckbox = New CheckBox
childCheckbox.Content = osite.SiteName.ToString
childNode.Header = childCheckbox
parentNode.Items.Add(childNode)
Next
TreeView1.Items.Add(parentNode)
Private Sub TreeView1_SelectedItemChanged(ByVal sender As System.Object, ByVal e As System.Windows.RoutedPropertyChangedEventArgs(Of System.Object)) Handles TreeView1.SelectedItemChanged
'This event doesn't seem to occur when I check or uncheck a checkbox
End Sub
Thanks for the help!
...
For Each osite In sites
Dim childNode = New TreeViewItem
Dim childCheckbox = New CheckBox
' add this to your code '
AddHandler childCheckBox.Checked, AddressOf chkbox_Checked
AddHandler childCheckBox.Unchecked, AddressOf chkbox_Unchecked
'-----------------------'
childCheckbox.Content = osite.SiteName.ToString
childNode.Header = childCheckbox
parentNode.Items.Add(childNode)
Next
...
Private Sub chkbox_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim chk = DirectCast(sender, CheckBox)
' Do whatever needs to be done when chk has been checked '
End Sub
Private Sub chkbox_Unchecked(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim chk = DirectCast(sender, CheckBox)
' Do whatever needs to be done when chk has been unchecked '
End Sub