I am using Silverlight Application in that I am using Datagrid and binding Data based on Observable Collection, but when I am trying to Bind the Observable Collection to Dropdown it's not binding, do we need to write code to Bind in the xaml Code behind.
My Code :
<sdk:DataGridTemplateColumn Header="lab Validated?" CanUserSort="True">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<ComboBox Height="Auto" HorizontalAlignment="Left"
Name="cboLabValidated" VerticalAlignment="Center" Width="80"
ItemsSource="{Binding Path=LabValidatedList}">
</ComboBox>
</Grid>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
ViewModel :
Public LabValidatedList As New List(Of String)() From { _
"Yes", _
"No"
}
In order to be usable as the source of a binding, LabValidatedList has to be a public property, not a field:
Private labValidatedListValue As New List(Of String)() From { _
"Yes", _
"No"
}
Public Property LabValidatedList() As List(Of String)
Get
Return Me.labValidatedListValue
End Get
Set(ByVal value As List(Of String))
Me.labValidatedListValue = value
End Set
End Property
Sorry if the above does not compile immediately, but VB is not my language. Note also that a List(Ofd String) is not an ObservableCollection.
Related
I am trying to data-bind a List to a DataGrid.
So far it seems to work only one way - when I manually change something entered in the displayed DataGrid, the List gets updated, but not vice-versa (DataGrid does not change when I change something in the List).
This is my DataGrid:
<DataGrid x:Name="MyDataGrid" AutoGenerateColumns="false" ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn x:Name="ColName" Binding="{Binding Name}" Header="Name" />
<DataGridTextColumn x:Name="ColProperty" Binding="{Binding MyProperty}" Header="My Property" />
</DataGrid.Columns>
</DataGrid>
I enter my data as follows:
Public Class Res
Public Shared TableData As New List(Of DataItem)
End Class
Public Class DataItem
Public Property Name() As String
Public Property MyProperty() As String
End Class
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
Dim entry As New DataItem
entry.Name = "Test Name"
entry.MyProperty = "Test Property"
Res.TableData.Add(entry)
Me.MyDataGrid.ItemsSource = Res.TableData
End Sub
But then, when I try to change my data, by doing something like:
Res.TableData.Item(0).Name = "Changed"
it does not work, the value displayed in the DataGrid does not change.
Why is this? How can I update my DataGrid?
If there is a better way to bind data to DataGrid, I am open for suggestions.
After some more searching, found a solution, that worked.
What I did, I added:
Me.MyDataGrid.Items.Refresh()
after I changed the value in the List.
Thanks.
I want to use SelectedItem to set selection to a combobox from code.
I can only get it to work by using SelectedValue. SelectedItem will throw a null reference exception with this at the top of the stacktrace:
at AttachedCommandBehavior.CommandBehaviorBinding.Execute()
The XAML:
<Window x:Class="MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:acb="clr-namespace:AttachedCommandBehavior;assembly=AttachedCommandBehavior"
Title="Window1" Height="300" Width="300">
<StackPanel>
<ComboBox Name="ComboItems1"
DisplayMemberPath="Value"
SelectedValuePath="Key"
ItemsSource="{Binding Items}"
SelectedValue="{Binding SelectedValue}"
acb:CommandBehavior.Event="SelectionChanged"
acb:CommandBehavior.Command="{Binding Path=SelectionChangedCommand}"
acb:CommandBehavior.CommandParameter="{Binding ElementName=ComboItems1, Path=SelectedItem}" />
<ComboBox Name="ComboItems2"
DisplayMemberPath="Value"
SelectedValuePath="Key"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"
acb:CommandBehavior.Event="SelectionChanged"
acb:CommandBehavior.Command="{Binding Path=SelectionChangedCommand}"
acb:CommandBehavior.CommandParameter="{Binding ElementName=ComboItems2, Path=SelectedItem}"/>
</StackPanel>
The code:
Imports AttachedCommandBehavior
Public Class MainWindowViewModel
Private _mainWindowView As MainWindowView
Public Property Items As New List(Of KeyValuePair(Of Integer, String))
Public Property SelectedItem As Nullable(Of KeyValuePair(Of Integer, String))
Public Property SelectedValue As Nullable(Of Integer)
Public Property SelectionChangedCommand As ICommand
Public Sub New()
Items.Add(New KeyValuePair(Of Integer, String)(1, "first item"))
Items.Add(New KeyValuePair(Of Integer, String)(2, "second item"))
Items.Add(New KeyValuePair(Of Integer, String)(3, "third item"))
Dim simpleCommand As SimpleCommand = New SimpleCommand()
simpleCommand.ExecuteDelegate = Sub(selectedItem As Object)
HandleSelectionChanged(selectedItem)
End Sub
SelectionChangedCommand = simpleCommand
SelectedValue = 1
'SelectedItem = Items(1) 'uncomment this to raise the null ref exception
End Sub
Private Sub HandleSelectionChanged(ByRef selectedItem As Object)
If selectedItem IsNot Nothing Then
'Do something
End If
End Sub
End Class
Why does selecteditem not work?
UPDATE:
Nikolay: you have a keen eye. That was due to last minute copy paste work!
Blindmeis: this, ofcourse, is an abstract from a much larger program in which I need the selectionchanged event to execute some actions. Those commandbindings have to stay (though maybe they need some fixing).
Regards,
Michel
why you have these commandbindings?
<ComboBox
DisplayMemberPath="Value"
SelectedValuePath="Key"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}" />
viewmodel
//this select the "third item" in your combobox
SelectedItem = Items[2];/dont know the vb indexer stuff ;)
this works.
Edit:
viewmodel
public KeyValuePair<int, string> SelectedItem
{
get{return this._selectedItem;}
set{
if(this._selectedItem==value)
return;//no selection change
//if you got here then there was a selection change
this._selectedItem=value;
this.OnPropertyChanged("SelectedItem");
//do all action you want here
//and you do not need selection changed event commmandbinding stuff
}
}
acb:CommandBehavior.CommandParameter="{Binding ElementName=ComboItems, Path=SelectedItem}"
You don't have element with name ComboItems, you have ComboItems1 and ComboItems2. I think this is the problem.
<ItemsControl ItemsSource="{Binding ExportFormat, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}" Margin="5" Height="50" Width="70" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.setExportFormat, UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding}"></Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
So i have that code in my xaml and the button gets filed with a list of string. Depending on what the users chooses on previous Usercontrol that item will be filed with differents items. The problem is if the user select one option at the first run the button will be filled correctly but if the user go back and select the other option the control doenst update and shows the same as before..
My english is not the best but i think i could made me understand! Any idea?!
PS: the bindind on Button is to a readOnly property so i cant define it to Mode="TwoWay".. i took a look on the debug and the property ExportFormat gets updates with the new items but the usercontrol still displays the first option!!
Sincerely Rui Nunes
You didn't provide code-behind so I'm gonna take a few shots in the dark here:
The ExportFormatcollection is not an ObservableCollection (or more generally, doesn't implement INotifyCollectionChanged).
If it actually is an ObservableCollection, you assign it directly, instead of clearing its items and adding the new ones. example:
ExportFormat = MyNewObsCollection; //Bad
ExportFormat.Clear();
foreach(var newItem in myNewObsCollection)
{
ExportFormat.Add(newItem); //Good
}
Side note: ExportFormat should be readonly
Thanks to #Baboon for giving me some lights on this problem. So the Solution to my problem is:
So my ExportFormat Property was defined as:
Private _ExportFormat As New List(Of String)
Public Property ExportFormat As List(Of String)
Get
Return _ExportFormat
End Get
Set(value As List(Of String))
_ExportFormat = value
NotifyPropertyChanged("ExportFormat")
End Set
End Property
and i just had to change the List(of String) to ObjectModel.ObservableCollection(Of String)..
Private _ExportFormat As New ObjectModel.ObservableCollection(Of String)
Public Property ExportFormat As ObjectModel.ObservableCollection(Of String)
Get
Return _ExportFormat
End Get
Set(value As ObjectModel.ObservableCollection(Of String))
_ExportFormat = value
NotifyPropertyChanged("ExportFormat")
End Set
End Property
And my problems got solved.. Thanks once again!
i have
<Grid Name="thisPage">
<TextBlock Name="tbtb" />
<ScrollViewer Name="sv4" Visibility="Hidden">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TextChanged="TextBox_TextChanged"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
in the MainWindow.vb, i have
movieArray as ObservableCollection(of Movie)
For i As Integer = 0 To 5
Me.movieArray.Add(New Movie(i))
Next
Me.sv4.DataContext = Me.movieArray
Me.listBox5.DataContext = Me.movieArray
Private Sub TextBox_TextChanged(sender As System.Object, e As System.Windows.Controls.TextChangedEventArgs)
Me.tbtb.Text = ""
For Each m As Movie In movieArray
Me.tbtb.Text += p.Title.ToString + " ^ "
Next
End Sub
Class Movie
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Property Title As Integer
Get
Return Me._title
End Get
Set(value As Integer)
Me._title = value
If Not (value = _title) Then
Me._title= value
NotifyPropertyChanged("Title")
End If
End Set
End Property
for the next page i have,
<Grid Name="nextPage" Visibility="Hidden" >
<ListBox Name="listBox5" >
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ListBox>
</Grid >
To change pages i just toggle the visibility of thisPage and nextPage using back, next buttons.
IM not sure what im doing wrong as:-
listbox5 shows only the original values, not anything changed by
textboxes.
tbtb, however is able to update its values
I think the problem might be your 'Title' property setter.
I'm a C# guy, not a VB expert... but it would appear that NotifyPropertyChanged will never get called.
value = _title will always be true because you just set Me._title = value in the previous line of code. Thus you will never execute any of the code in your if statement.
Why are you using Textchanged evetn in two way binding you dont need kind of stuff. two way binding is directly bind values from your view to property and from property to view
so don't use textchanged event and try again. this will work.
I've encountered a problem when converting a WPF project from vs2008 to vs2010.
I have a DataGrid that contains a ListBox. Each ListBoxItem has a Label and a Button. After converting to vs2010 the button no longer renders but crashes the app as soon as it comes into view. (Ie. the app loads but when the ListBox is created I get a NullReferenceException. What does work though is to remove the click event from the button and then it renders fine :) Same type of setup with Button within ListBoxItem also works when not inside a DataGrid. The content of ListBox obviously is meant to be dynamic but when working with a static collection I get the same error. Also removing the CommandParam does not help at all. Any pointers most welcome.
Code:
<DataGrid x:Name="DgTest" AutoGenerateColumns="false">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ListBox ItemsSource="{Binding ItemList}">
<ListBox.ItemTemplate>
<DataTemplate >
<StackPanel Style="{StaticResource hzp}">
<Label />
<Button Click="Button_Click" Content="TestButton"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Code-behind:
Imports System.Collections.ObjectModel
Class MainWindow
Public TestList As New ObservableCollection(Of TestClass)
Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
DgTest.ItemsSource = TestList
TestList.Add(New TestClass(0))
TestList.Add(New TestClass(1))
End Sub
Public Class TestClass
Private _ItemList As New List(Of String)
Private _id As Integer
Public Property ItemList() As List(Of String)
Get
Return _ItemList
End Get
Set(ByVal value As List(Of String))
_ItemList = value
End Set
End Property
Public Property Id() As Integer
Get
Return _id
End Get
Set(ByVal value As Integer)
_id = value
End Set
End Property
Public Sub New(ByVal id As Integer)
_ItemList.Add("String1")
_id = id
End Sub
End Class
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
End Sub
End Class
And in App Resources:
<Style TargetType="StackPanel" x:Key="hzp">
<Setter Property="Orientation" Value="Horizontal"/>
<Setter Property="Background" Value="Orange"/>
</Style>
Now here's the strange thing. If the Stackpanel Style is removed, the button will work. If the Click event for the button is removed, it will load normally.
Seems like your event handler is gone from the code-behind file, check that first. Comment if that is not the case.
I believe I have found the answer to my own question. In the ListBox bound to an ObservableCollection all Styles must be DynamicResource. Using StaticResource worked well in 3.5 but not 4! Took a few hours of randomly testing everything to find this. Case closed