When does the binding on the ItemsSource property generate Items? - wpf

I have added a dialog to my WPF application. Here's the Xaml:
<cs:CarSystemDialog x:Class="CarSystem.CustomControls.EditHotListDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cs="clr-namespace:CarSystem.CustomControls"
DataContext="{Binding Path=HotList, RelativeSource={RelativeSource Self}}"
Height="265"
Loaded="EditHotListDialog_Loaded"
MaxHeight="665"
MaxWidth="1200"
SizeToContent="WidthAndHeight"
cs:ThemeSelector.CurrentThemeDictionary="{Binding Path=TimeOfDayTheme, RelativeSource={RelativeSource Self}}"
Width="850"
WindowStartupLocation="CenterOwner" >
<cs:CarSystemDialog.Resources>
<cs:BooleanToVisibilityConverter x:Key="BoolToVisibility" True="Visible" False="Collapsed" />
<cs:CaseToVisibilityConverter x:Key="CaseToVisibilityConverter" />
</cs:CarSystemDialog.Resources>
<Grid Background="{DynamicResource ContentBackground}" FocusManager.IsFocusScope="True" Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock FontSize="16"
FontWeight="Bold"
Foreground="{DynamicResource TextForeground}"
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Right"
Margin="5"
Text="Source:"
VerticalAlignment="Center" />
<TextBox AcceptsTab="False"
AcceptsReturn="False"
BorderBrush="{DynamicResource ControlBorder}"
BorderThickness="2"
FontSize="16"
FontWeight="Bold"
Foreground="{DynamicResource UnfocusedForeground}"
Grid.Column="1"
Grid.Row="0"
Margin="5"
MaxLength="80"
MaxLines="1"
Name="HotListNameBox"
TabIndex="0"
Text="{Binding Path=Name, Mode=TwoWay}"
VerticalAlignment="Center" />
<TextBlock FontSize="16"
FontWeight="Bold"
Foreground="{DynamicResource TextForeground}"
Grid.Column="2"
HorizontalAlignment="Right"
Margin="5"
Text="List Type:"
VerticalAlignment="Center" />
<ComboBox BorderBrush="{DynamicResource PlateInfoBorder}"
DisplayMemberPath="Value"
FontSize="16"
FontWeight="Bold"
Grid.Column="3"
ItemsSource="{Binding Path=ListTypes, RelativeSource={RelativeSource AncestorType={x:Type cs:EditHotListDialog}}}"
Margin="5"
Name="ListTypePicker"
SelectedValue="{Binding Path=ListTypeId, Mode=TwoWay}"
SelectedValuePath="Key"
TabIndex="1" />
<TextBlock FontSize="16"
FontWeight="Bold"
Foreground="{DynamicResource TextForeground}"
Grid.Column="0"
Grid.Row="1"
HorizontalAlignment="Right"
Margin="5"
Text="Domain:"
VerticalAlignment="Center" />
<ComboBox BorderBrush="{DynamicResource PlateInfoBorder}"
DisplayMemberPath="Value"
FontSize="16"
FontWeight="Bold"
Grid.Column="1"
Grid.Row="1"
ItemsSource="{Binding Path=Domains, RelativeSource={RelativeSource AncestorType={x:Type cs:EditHotListDialog}}}"
Margin="5"
Name="DomainPicker"
SelectedValue="{Binding Path=DomainId, Mode=TwoWay}"
SelectedValuePath="Key"
TabIndex="1" />
<StackPanel Grid.Column="0"
Grid.ColumnSpan="4"
Grid.Row="2"
HorizontalAlignment="Center"
Orientation="Horizontal">
<Button Background="{DynamicResource ButtonBackground}"
Click="OkButton_Click"
Content="OK"
FontSize="18"
FontWeight="Bold"
Foreground="{DynamicResource ButtonForeground}"
Height="50"
IsDefault="True"
IsEnabled="{Binding Path=CanSave, RelativeSource={RelativeSource AncestorType={x:Type cs:EditHotListDialog}}}"
Margin="5"
Name="OkButton"
Width="100"/>
<Button Background="{DynamicResource ButtonBackground}"
Content="Cancel"
FontSize="18"
FontWeight="Bold"
Foreground="{DynamicResource ButtonForeground}"
Height="50"
IsCancel="True"
Margin="5"
Name="CancelButton"
Width="100" />
</StackPanel>
</Grid>
</cs:CarSystemDialog>
And here's the code behind:
public partial class EditHotListDialog : CarSystemDialog, INotifyPropertyChanged {
public static readonly DependencyProperty CanSaveProperty =
DependencyProperty.Register( "CanSave", typeof( bool ), typeof( EditHotListDialog ), new PropertyMetadata( false ) );
public static readonly DependencyProperty HotListProperty =
DependencyProperty.Register( "HotList", typeof( HotListViewModel ), typeof( EditHotListDialog ),
new PropertyMetadata( null, new PropertyChangedCallback( OnHotListChanged ) ) );
public bool CanSave {
get { return (bool) GetValue( CanSaveProperty ); }
set { SetValue( CanSaveProperty, value ); }
}
public ObservableCollection<ItemChoice<int?>> Domains { get; set; }
public HotListViewModel HotList {
get { return (HotListViewModel) GetValue( HotListProperty ); }
set { SetValue( HotListProperty, value ); }
}
public ObservableCollection<ItemChoice<int?>> ListTypes { get; set; }
public EditHotListDialog() {
InitializeComponent();
Domains = new ObservableCollection<ItemChoice<int?>>();
ListTypes = new ObservableCollection<ItemChoice<int?>>();
Domains .Add( new ItemChoice<int?> { Key = null, Value = "-- Pick a Domain --"} );
ListTypes.Add( new ItemChoice<int?> { Key = null, Value = "-- Pick a List Type --" } );
KeywordCache.KeywordCacheUpdated += KeywordCacheUpdated;
}
private void EditHotListDialog_Loaded( object sender, RoutedEventArgs e ) {
UpdateChoices();
DomainPicker.SelectedIndex = 0;
ListTypePicker.SelectedIndex = 0;
}
void HotList_PropertyChanged( object sender, PropertyChangedEventArgs e ) {
HotListViewModel hotList = sender as HotListViewModel;
CanSave = !( string.IsNullOrEmpty( hotList.Name ) || string.IsNullOrWhiteSpace( hotList.Name ) ) && hotList.ListTypeId > 0 && hotList.DomainId > 0;
}
private void OkButton_Click( object sender, RoutedEventArgs e ) {
if ( ValidateHotList() ) {
DialogResult = true;
Close();
}
e.Handled = true;
}
private void OnHotListChanged( HotListViewModel oldHotList, HotListViewModel newHotList ) {
if ( oldHotList != null ) {
oldHotList.PropertyChanged -= HotList_PropertyChanged;
}
if ( newHotList != null ) {
newHotList.PropertyChanged += HotList_PropertyChanged;
}
}
private static void OnHotListChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) {
EditHotListDialog dialog = d as EditHotListDialog;
dialog.OnHotListChanged( e.OldValue as HotListViewModel, e.NewValue as HotListViewModel );
}
private void UpdateChoices() {
. . .
}
private bool ValidateHotList() {
if ( string.IsNullOrEmpty( HotListNameBox.Text.Trim() ) ) {
CarSystemMessageBox.Show( "Please enter a name for the Hot List.", "Please Name the Hot List", MessageBoxButton.OK, MessageBoxImage.None );
return false;
}
if ( ListTypePicker.SelectedIndex <= 0 ) {
CarSystemMessageBox.Show( "Please select the List Type from the drop down that specifies what type of Hot List this is.", "Please Specify a List Type", MessageBoxButton.OK, MessageBoxImage.None );
return false;
}
if ( DomainPicker.SelectedIndex <= 0 ) {
CarSystemMessageBox.Show( "Please select the Domain from the drop down that this Hot List Entry belongs to.", "Please Specify a Domain", MessageBoxButton.OK, MessageBoxImage.None );
return false;
}
return true;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent( string propertyName ) {
if ( PropertyChanged != null ) {
PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
}
}
#endregion
}
}
When I debug this code, I see the two ObservableCollections get populated with data. This occurs in the UpdateChoices method. I've put the call to UpdateChoices in the constructor as well as where it is in the code above.
The problem is that after the two ObservableCollections are populated, there are no Items in the ComboBoxes. When I set the SelectedIndex property to 0, nothing gets selected. When the Dialog finally opens, nothing is selected in either of the ComboBoxes.
I've used this pattern in a number of UserControls on the MainWindow of my application with success, but this is the first time I've used it in a dialog. Where is the right place to call the UpdateChoices method and to set the SelectedIndex properties of the ComboBoxes?
P.S. I didn't include the details of the UpdateChoices method because it's not pertinent to the question.

Your DataContext is set to HotList, which is at the same level as the properties you are trying to access. Either change the DataContext to be the whole dialog, or move the observable collections into the HotList object.

I don't know what the problem with the binding was, but I got rid of it and just set the ItemsSource properties of the ComboBox controls in the dialog's Loaded event handler. Everything works now.

Check out MVVM Pattern. Almost no Code behind is needed and you get testable code.

Related

Event Aggregator in Prism usage giving exception

I have to communicate between 2 view models so I am using Event aggregator but I observed the method is calling 2 times when a property is updated and for the first it is working as expected but second time all the elements are null and throwing null reference exception.
Why it is happening I am not triggering it second time.
MainViewModel
private XMLNode NodeSelected;
public XMLNode NodeSelected
{
get { return NodeSelected; }
set
{
nodeSelected = value;
iEventAggregator.GetEvent<AddNewObjectEvent>().Publish(this.NodeSelected);
}
}
UsercontrolViewModel
public UserControlViewModel(IEventAggregator iEventAggregator)
{
this.iEventAggregator = iEventAggregator;
this.iEventAggregator.GetEvent<AddNewGuiSyncObjectEvent>()
.Subscribe(AddXMLNode);
}
AddXMLNODE method related code
private void AddXMLNODE (XMLNode SelectedNode)
{
if (this.CriteriaItem == null) return;
SyncObject currentObj = new SyncObject(SelectedNode);
if (!IsSyncItemNameUnique(currentObj))
{
currentObj.Name = GetUniqueName(currentObj);
}
this.CriteriaItem.SyncObjects.Add(currentObj);
this.SelectedSyncObject = this.CriteriaItem .SyncObjects.LastOrDefault();
}
Here first time "CriteriaItem" is coming correct and newnode is added to collection but again same method is hitting and CriteriaItem is NULL If I remove that null check we are getting exception.
What is the mistake here I am not getting.
The complete code
UserControl ViewModel
namespace Hexagon.SmartUITest.GUISynchronization.ViewModel
{
public class IndividualSyncViewModel : ViewModelBase
{
#region properties
private GUISyncObject selectedSyncObject;
public GUISyncObject SelectedSyncObject
{
get { return selectedSyncObject; }
set
{
selectedSyncObject = value;
this.OnPropertyChanged(() => this.SelectedSyncObject);
iEventAggregator.GetEvent<SelectedSyncObjectEvent>().Publish(this.SelectedSyncObject);
}
}
private SyncCriteriaItem _CriteriaItem;
public SyncCriteriaItem CriteriaItem
{
get { return CriteriaItem; }
set
{
CriteriaItem = value;
OnPropertyChanged(() => this.CriteriaItem);
}
}
private IEventAggregator iEventAggregator;
#endregion
#region constructor
public IndividualSyncViewModel(IEventAggregator iEventAggregator)
{
this.iEventAggregator = iEventAggregator;
this.iEventAggregator.GetEvent<AddNewGuiSyncObjectEvent>()
.Subscribe(AddGUISyncItem);
}
#endregion
private ICommand deleteSyncObjectClick;
public ICommand DeleteSyncObjectClick
{
get
{
if (deleteSyncObjectClick == null) deleteSyncObjectClick = new RelayCommand(DeleteSync);
return deleteSyncObjectClick;
}
set
{
deleteSyncObjectClick = value;
}
}
private void DeleteSync()
{
this.CriteriaItem.SyncObjects.Remove(selectedSyncObject);
selectedSyncObject = this.CriteriaItem.SyncObjects.LastOrDefault();
}
private bool IsItemNameUnique(GUISyncObject SyncObject)
{
if (this.CriteriaItem != null && this.CriteriaItem.SyncObjects.Count == 0)
return true;
foreach (GUISyncObject item in this.CriteriaItem.SyncObjects.ToList())
{
if (item.Name.Equals(SyncObject.Name) && !item.CommandNodeName.Equals(SyncObject.CommandNodeName))
return false;
}
return true;
}
private string GetUniqueName(GUISyncObject syncItem)
{
List<string> itemsNames = this.CriteriaItem.SyncObjects.Select(item => item.Name).ToList();
return CommonNamingRules.GetUniqueName(itemsNames, syncItem.Name);
}
private void AddGUISyncItem(ControlNode SelectedNode)
{
if (this.CriteriaItem == null) return;
GUISyncObject currentObj = new GUISyncObject(SelectedNode);
if (!IsSyncItemNameUnique(currentObj))
{
currentObj.Name = GetUniqueName(currentObj);
}
this.CriteriaItem.SyncObjects.Add(currentObj);
this.SelectedSyncObject = this.CriteriaItem.SyncObjects.LastOrDefault();
}
}
}
UserControl xaml.cs
public partial class IndividualSync : UserControl
{
private IndividualSyncViewModel _vm;
public IndividualSync()
{
InitializeComponent();
_vm = new IndividualSyncViewModel(Event.EventInstance.EventAggregator);
rootGrid.DataContext = _vm;
}
#region properties
public SyncCriteriaItem SyncCriteriaItem
{
get { return (SyncCriteriaItem)GetValue(SyncCriteriaItemProperty); }
set { SetValue(SyncCriteriaItemProperty, value); }
}
public static readonly DependencyProperty SyncCriteriaItemProperty = DependencyProperty.Register("SyncCriteriaItem", typeof(SyncCriteriaItem), typeof(IndividualSync), new PropertyMetadata(null, OnCriteriaItemSet));
public GUISyncObject SelectedSYNC
{
get { return (GUISyncObject)GetValue(SelectedSYNCDependencyProperty); }
set { SetValue(SelectedSYNCDependencyProperty, value); }
}
public static readonly DependencyProperty SelectedSYNCDependencyProperty = DependencyProperty.Register("SelectedSYNC", typeof(GUISyncObject), typeof(IndividualSync), new PropertyMetadata(null, OnGUISyncItemSelect));
private static void OnCriteriaItemSet(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((IndividualSync)d)._vm.CriteriaItem = e.NewValue as SyncCriteriaItem;
}
private static void OnSyncItemSelect(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((IndividualSync)d)._vm.SelectedSyncObject = e.NewValue as GUISyncObject;
}
#endregion
}
Iam creating two dependency properties on the usercontrol which will be set from parent usercontrol.
Parent usercontrol Xaml
<UserControl.Resources>
<Converters:IndexToTabNameConverter x:Key="TabIndexConverter"/>
<DataTemplate x:Key="SyncTabItemTemplate" >
<StackPanel VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock Text="{Binding Converter={StaticResource TabIndexConverter},
RelativeSource={RelativeSource AncestorType={x:Type telerik:RadTabItem}}}"/>
<Button Margin="10,0,0,0"
Style="{StaticResource CloseButton}"
ToolTipService.ToolTip="Save and Close">
<Button.Content>
<Path Data="M0,0 L6,6 M6, 0 L0,6"
SnapsToDevicePixels="True"
Stroke="Black"
StrokeThickness="1" />
</Button.Content>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<uxt:EventToCommand CommandParameter="{Binding}" Command="{Binding Path=DataContext.RemoveSyncCriteriaCommand,ElementName=rootGrid}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="EmptyTemplate">
<TextBlock FontWeight="Bold" FontFamily="Comic Sans" FontStyle="Italic" Text="{Binding}" />
</DataTemplate>
<DataTemplate x:Key="HeaderTemplate">
<Label FontWeight="Bold" HorizontalContentAlignment="Center" Content="{Binding}" />
</DataTemplate>
<DataTemplate x:Key="SyncCriteriaTemplate">
<local:IndividualSync SyncCriteriaItem="{Binding}" SelectedGUISYNC="{Binding Path=DataContext.SelectedGUISYNCOBJECT}"/>
</DataTemplate>
<DataTemplate x:Key="newTabButtonHeaderTemplate">
<telerik:RadButton Style="{DynamicResource IconButtonStyle}" Width="20" Height="20" Command="{Binding Path=DataContext.NewCommand,ElementName=rootGrid}" ToolTip="Click to add new item">
<uxt:UxtXamlImage Template="{DynamicResource Com_Add}" />
</telerik:RadButton>
</DataTemplate>
<DataTemplate x:Key="itemContentTemplate">
<Grid/>
</DataTemplate>
<Selectors:TabItemTemplateSelector x:Key="headerTemplateSelector"
NewButtonTemplate="{StaticResource newTabButtonHeaderTemplate}"
ItemTemplate="{StaticResource SyncTabItemTemplate}"/>
<Selectors:TabItemTemplateSelector x:Key="contentTemplateSelector"
NewButtonTemplate="{StaticResource itemContentTemplate}"
ItemTemplate="{StaticResource SyncCriteriaTemplate}"/>
<Selectors:SyncTemplateSelector x:Key="syncTemplates">
<Selectors:SyncTemplateSelector.ProcessSyncTemplate>
<DataTemplate>
<telerik:Label Content="{Binding ProcessSync,StringFormat={}{0}}" BorderThickness="1" HorizontalContentAlignment="Left" FontStyle="Oblique" Width="{Binding Width,RelativeSource={RelativeSource AncestorType=telerik:RadListBox}}"/>
</DataTemplate>
</Selectors:SyncTemplateSelector.ProcessSyncTemplate>
<Selectors:SyncTemplateSelector.GUISyncTemplate>
<DataTemplate>
<Expander Header="GUISYNC" HeaderTemplate="{StaticResource HeaderTemplate}" Width="{Binding Width,RelativeSource={RelativeSource AncestorType=telerik:RadListBox}}" IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=telerik:RadListBoxItem, Mode=FindAncestor}}">
<telerik:RadTabControl ItemsSource="{Binding SyncCriteriaItem}" OverflowMode="Scroll" DropDownDisplayMode="Visible" SelectedItem="{Binding SelectedSyncCriteria, Mode=TwoWay}" SelectedIndex="0"
ItemTemplateSelector="{StaticResource headerTemplateSelector}"
ContentTemplateSelector="{StaticResource contentTemplateSelector}">
</telerik:RadTabControl>
</Expander>
</DataTemplate>
</Selectors:SyncTemplateSelector.GUISyncTemplate>
</Selectors:SyncTemplateSelector>
</UserControl.Resources>
<Grid Name="rootGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<telerik:RadListBox Margin="20,5,20,0" Grid.Row="0" Grid.Column="0" Name="synclist" ItemsSource="{Binding CurrentSyncObjectCollection.SyncObjects}" ItemTemplateSelector="{StaticResource syncTemplates}" SelectedItem="{Binding SelectedSyncObject,Mode=TwoWay}" >
</telerik:RadListBox>
<telerik:RadComboBox Grid.Row="1" Grid.Column="0" Name="SyncOption" EmptyText="Select a sync type to be added " Margin="0,8,0,5" EmptySelectionBoxTemplate="{StaticResource EmptyTemplate}" ItemsSource="{Binding SyncTypes}" Width="{Binding ActualWidth, ElementName=synclist}" HorizontalContentAlignment="Center" Height="25" SelectedIndex="{Binding SelectedSyncIndex,Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<uxt:EventToCommand Command="{Binding AddSelectedSyncClick}" CommandParameter="{Binding Path=SelectedValue,ElementName=SyncOption}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</telerik:RadComboBox>
<telerik:RadButton Style="{DynamicResource IconButtonStyle}" Grid.Column="1" Grid.Row="0" Width="20" Height="20" VerticalAlignment="Top" IsEnabled="{Binding Path=SelectedSyncObject,Converter={uxt:ObjectToBoolConverter}}" ToolTip="Click to delete selected Sync"
Command="{Binding DeleteSyncObjectClick}">
<uxt:UxtXamlImage Template="{DynamicResource Com_Delete}" />
</telerik:RadButton>
</Grid>
I hope this will help. I have debugged the code and I observed even two Items are binded for CriteriaItems Breakpoint hitting for dependency property criteria item 3 times and one time null is coming.
Even when I change Tab selection Dependency Property setting code is hitting 2 times instead of one time.first time null is setting for CriteriaItem and second time respective item is coming.

How to bind XamDataGrids available on different panels with different collections on a WPF page, using pure MVVM concepts & dependency injection.

I have a WPF XAML page, having 3 sections separated by DockPanels. One panel contains an INFRAGITICS XamDataGrid control to be bound with a collection.
I would like to bind XamDataGrid control using DataContext/DataSource property in pure MVVM way.
Also, would be delighted to understand if binding is done through dependency injection.
I have tried different approaches but didn't get success. I have pasted my code below for reference. Kindly help.
XAML Page:
<Window x:Class="UserInterface.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:UserInterface"
xmlns:igDP="clr-namespace:Infragistics.Windows.DataPresenter;assembly=InfragisticsWPF.DataPresenter"
xmlns:igEditors="clr-namespace:Infragistics.Windows.Editors;assembly=InfragisticsWPF.Editors"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:dc ="clr-namespace:UserInterface.ViewModel"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
mc:Ignorable="d"
Title="MainWindow">
<Window.Resources>
<dc:GraphicViewModel x:Key="dataContext"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=".5*"/>
<RowDefinition Height=".5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*"/>
<ColumnDefinition Width=".5*"/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0" Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
</Grid>
<!--<StackPanel Orientation="Vertical" DockPanel.Dock="Top">
<StackPanel Orientation="Horizontal" Margin="5" Grid.Row="0">
<DockPanel>
<TextBlock Text="*.cfg File" Grid.Column="0" DockPanel.Dock="Left"/>
<Button Content="Browse..." Grid.Column="2" DockPanel.Dock="Right"/>
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.cfg file..." Grid.Column="1" DockPanel.Dock="Right"/>
</DockPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5" Grid.Row="1">
<TextBlock Text="*.ps File " Grid.Column="0"/>
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.ps file..." Grid.Column="1"/>
<Button Content="Browse..." Grid.Column="2"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5" Grid.Row="2">
<TextBlock Text="*.pic File " Grid.Column="0"/>
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.pic file..." Grid.Column="1"/>
<Button Content="Browse..." Grid.Column="2"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5" Grid.Row="3">
<TextBlock Text="*.xlsx File" Grid.Column="0"/>
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.xlsx file..." Grid.Column="1"/>
<Button Content="Browse..." Grid.Column="2"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5" Grid.Row="4">
<TextBlock Text="*.xlsx File"/>
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.xlsx file..." Grid.Column="1"/>
<Button Content="Browse..." Grid.Column="2"/>
</StackPanel>
</StackPanel>-->
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical" Margin="5" Grid.Row="0">
<TextBlock MinHeight="20.5" Text="*.cfg File" Grid.Column="0"/>
<TextBlock MinHeight="20.5" Text="*.ps File " Grid.Column="0"/>
<TextBlock MinHeight="20.5" Text="*.pic File " Grid.Column="0"/>
<TextBlock MinHeight="20.5" Text="*.xlsx File" Grid.Column="0"/>
<TextBlock MinHeight="20.5" Text="*.xlsx File" Grid.Column="0"/>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="5" Grid.Row="1">
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.cfg file..." Grid.Column="1" MinHeight="20.5"/>
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.ps file..." Grid.Column="1" MinHeight="20.5"/>
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse *.pic file..." Grid.Column="1" MinHeight="20.5"/>
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse Model mapping file..." Grid.Column="1" MinHeight="20.5"/>
<TextBox FontStyle="Italic" FontWeight="Light" Text="Browse Parameter mapping file..." Grid.Column="1" MinHeight="20.5"/>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="5" Grid.Row="2">
<Button Content="Browse..." Grid.Column="2"/>
<Button Content="Browse..." Grid.Column="2"/>
<Button Content="Browse..." Grid.Column="2"/>
<Button Content="Browse..." Grid.Column="2"/>
<Button Content="Browse..." Grid.Column="2"/>
</StackPanel>
</StackPanel>
</DockPanel>
<DockPanel Grid.Column="1" Grid.Row="0">
<igDP:XamDataGrid x:Name="ItemsSource" DataContext="{Binding Source={StaticResource dataContext}, Path=ItemsSource, Mode=TwoWay}" Grid.Row="0" Margin="10" AutoFit="true">
<igDP:XamDataGrid.ViewSettings>
<igDP:GridViewSettings/>
</igDP:XamDataGrid.ViewSettings>
<igDP:XamDataGrid.FieldSettings>
<igDP:FieldSettings LabelTextAlignment="Left" AllowRecordFiltering="true" FilterOperandUIType="ExcelStyle" FilterStringComparisonType="CaseInsensitive" FilterOperatorDefaultValue="Contains"
LabelClickAction="SortByOneFieldOnlyTriState" SortComparisonType="Default"/>
</igDP:XamDataGrid.FieldSettings>
<igDP:XamDataGrid.FieldLayoutSettings>
<igDP:FieldLayoutSettings DataErrorDisplayMode="ErrorIconAndHighlight" SupportDataErrorInfo="RecordsAndCells" SelectionTypeRecord ="Single"
AutoGenerateFields="False" FilterUIType="FilterRecord"/>
</igDP:XamDataGrid.FieldLayoutSettings>
<igDP:XamDataGrid.FieldLayouts>
<igDP:FieldLayout>
<igDP:FieldLayout.Fields>
<igDP:Field Name="IsSelected" Label="Select" HorizontalContentAlignment="Left" Width="Auto" VerticalContentAlignment="Center">
<igDP:Field.Settings>
<igDP:FieldSettings DataItemUpdateTrigger="OnCellValueChange">
<igDP:FieldSettings.LabelPresenterStyle>
<Style TargetType="{x:Type igDP:LabelPresenter}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" Content="" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</igDP:FieldSettings.LabelPresenterStyle>
</igDP:FieldSettings>
</igDP:Field.Settings>
</igDP:Field>
<igDP:Field Label="Name" Name="Name" AllowEdit="False" HorizontalContentAlignment="Left" Width="Auto">
</igDP:Field>
<igDP:Field Label="Type" Name="Type" AllowEdit="False" HorizontalContentAlignment="Left" Width="*"/>
<igDP:Field Label="Background" Name="Background" AllowEdit="False" HorizontalContentAlignment="Left" Width="Auto"/>
<igDP:Field Label="Width" Name="Width" AllowEdit="False" HorizontalContentAlignment="Right" Width="Auto"/>
<igDP:Field Label="Height" Name="Height" AllowEdit="False" HorizontalContentAlignment="Right" Width="Auto"/>
</igDP:FieldLayout.Fields>
</igDP:FieldLayout>
</igDP:XamDataGrid.FieldLayouts>
</igDP:XamDataGrid>
</DockPanel>
<DockPanel Grid.Column="0" Grid.Row="1" Grid.RowSpan="2">
<StackPanel Orientation="Vertical" DockPanel.Dock="Bottom">
<TextBox Text="Sample Text1"/>
<TextBox Text="Sample Text2"/>
<TextBox Text="Sample Text3"/>
<TextBox Text="Sample Text4"/>
</StackPanel>
</DockPanel>
<!--</StackPanel>-->
</Grid>
</Window>
Xaml page code behind:
namespace UserInterface
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//GraphicViewModel obj = new GraphicViewModel();
//ItemsSource.DataSource = obj.ItemsSource;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion INotifyPropertyChanged Members
public GraphicViewModel GraphicViewModel
{
get { return this.DataContext as GraphicViewModel; }
set
{
this.DataContext = value;
if (this.DataContext != null)
NotifyPropertyChanged("GraphicViewModel");
}
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
}
}
}
Model Class:
namespace UserInterface.Model
{
public class GraphicsModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyOfPropertyChange(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected == value) return;
_isSelected = value;
NotifyOfPropertyChange("IsSelected");
}
}
private string _name = string.Empty;
public string Name
{
get { return _name; }
set
{
if (_name != value)
_name = value;
NotifyOfPropertyChange("Name");
}
}
private string _type = string.Empty;
public string Type
{
get { return _type; }
set
{
if (_type != value)
_type = value;
NotifyOfPropertyChange("Type");
}
}
private string _width = string.Empty;
public string Width
{
get { return _width; }
set
{
if (_width != value)
_width = value;
NotifyOfPropertyChange("Width");
}
}
private string _height = string.Empty;
public string Height
{
get { return _height; }
set
{
if (_height != value)
_height = value;
NotifyOfPropertyChange("Height");
}
}
}
}
ViewModel class:
namespace UserInterface.ViewModel
{
public class GraphicViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyOfPropertyChange(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
private ObservableCollection<GraphicsModel> _itemsSource = new ObservableCollection<GraphicsModel>();
// MainWindow _view = null;
public ObservableCollection<GraphicsModel> ItemsSource
{
get { return _itemsSource; }
set
{
if (_itemsSource == value) return;
_itemsSource = value;
NotifyOfPropertyChange("ItemsSource");
}
}
public GraphicViewModel()
{
//_view = view;
_itemsSource = new ObservableCollection<GraphicsModel>() { new GraphicsModel() { Name = "sdasdad", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,
new GraphicsModel() { Name = "sdsa", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,new GraphicsModel() { Name = "sdasdad", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,new GraphicsModel() { Name = "asas", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,new GraphicsModel() { Name = "rewwe", Type = "Model", IsSelected = false, Height = "1000", Width = "1370" } ,};
//view.GraphicViewModel = this;
}
}
}
When you write
<Window.Resources>
<dc:GraphicViewModel x:Key="dataContext"/>
</Window.Resources>
You are saying "create a property of type GraphicViewModel and name it dataContext". It's almost the exact same as doing something like this in the code-behind :
private GraphicViewModel dataContext = new GraphicViewModel();
When you write
<igDP:XamDataGrid DataContext="{Binding Source={StaticResource dataContext}, Path=ItemsSource, Mode=TwoWay}" .. />
You are saying "bind the igDP:XamDataGrid.DataContext property to dataContext.ItemsSource".
Now for why the Grid won't load, the .DataContext property doesn't actually do anything. It's just a holder for the data that sits behind the control. So if you were to write
<igDP:XamDataGrid ItemsSource="{Binding MyProperty}" />
It would be to tell WPF "set XamDataGrid.ItemsSource property equal to XamDataGrid.DataContext.MyProperty".
Since in the code above you set the DataContext equal to dataContext.ItemsSource, it would try to set the value to dataContext.ItemsSource.MyProperty (which of course does not exist).
What you actually need is something like
<igDP:XamDataGrid ItemsSource="{Binding Source={StaticResource dataContext}, Path=ItemsSource}" .. />
This binds the .ItemsSource property of the grid (which is the property it builds its data rows from) to the static resource created in <Window.Resources> named "dataContext", and the property on that object called ItemsSource.
Second issue here though is you seem to have multiple copies of your ViewModel in your code. Personally I recommend never creating objects in the XAML like you did for your GraphicViewModel. Instead, I would recommend something like this :
public MainWindow()
{
InitializeComponent();
this.DataContext = new GraphicViewModel();
}
Now it should be noted that this creates a new instance of the GraphicViewModel, but doesn't store it anywhere. If you want to access this object in other code-behind without casting this.DataContext to GraphicViewModel, then you should probably store the value somewhere.
Once the Window.DataContext is set, you can write the bindings without specifying a custom Source property for the binding.
<igDP:XamDataGrid ItemsSource="{Binding ItemsSource}" .. />
This will work because WPF controls will look up the DataContext from their parent by default if it is not specifically set. So in this case, the .DataContext property for XamDataGrid is null so it will travel up the visual tree looking for something with a DataContext until it runs into Window.DataContext which you've set in the constructor to a new instance of your GraphicViewModel.
For people looking to understand the DataContext property, I usually send them to this SO answer to avoid having to retype the same thing all the time. I'd recommend reading it if you're still working to understand what the DataContext is or how it's used.
Also that said, Dependency Injection is something different and wouldn't be used here at all.
Thanks a lot #Rachel, #Daniel Filipov & #quetzalcoatl, I got my code working now. The changes done in below files:
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
ItemsSource.DataContext= new GraphicViewModel();
}
MainWindow.xaml:
<igDP:XamDataGrid x:Name="ItemsSource" DataSource="{Binding ItemsSource, Mode=TwoWay}" .../>

Changes to Observable Collection not updating DataGrid

I have an observable collection in my viewmodel as follows..Not perfect but just code that looks as below populating an observable collection and bind it to the datagrid. I also have two buttons beside the datagrid one for upcommand and one for downcommand. When I click the upbutton everything works fine in which the selected row moves up and the sequence order is getting updated, Observable Collection is also getting updated. But the changes are not being bound to the DataGrid. Similarly for the downcommand. My view is below. The commands are working just fine only the view is not being updated. .Please help.
Issue is with observable collection, move up and move down.
ViewModel:
public class JobConfigurationViewModel : BindableBase
{
public JobConfigurationLogic JobConfigurationLogic =
new JobConfigurationLogic(new JobConfigurationResultsRepository());
public SrcDestConfigurationLogic SrcDestConfigurationLogic =
new SrcDestConfigurationLogic(new SrcDestCofigurationRepository());
private string _enterprise;
public string Enterprise
{
get { return _enterprise; }
set { SetProperty(ref _enterprise, value); }
}
private int currentJobID;
private int currentSequence;
private int previousJobID;
private int previousSequence;
private string _site;
public string Site
{
get { return _site; }
set { SetProperty(ref _site, value); }
}
private int _siteID;
public int SiteID
{
get { return _siteID; }
set { SetProperty(ref _siteID, value); }
}
private ObservableCollection<JobConfigurationResults> _jobEntities;
public ObservableCollection<JobConfigurationResults> JobEntities
{
get { return _jobEntities; }
set
{
SetProperty(ref _jobEntities, value);
//JobEntities.CollectionChanged += JobEntities_CollectionChanged;
OnPropertyChanged("JobEntities");
}
}
//void JobEntities_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
//{
// if (e.OldItems != null)
// {
// foreach (var item in e.OldItems)
// {
// this.GetJobConfigurationResults();
// }
// }
//}
//Source System List for Job
private List<SourceSiteSystem> _lstJobSrcSystems;
public List<SourceSiteSystem> LstJobSrcSystems
{
get { return _lstJobSrcSystems; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
SetProperty(ref _lstJobSrcSystems, value);
}
}
//Deestination System List for Job
private List<DestinationSiteSystem> _lstJobDestSystems;
public List<DestinationSiteSystem> LstJobDestSystems
{
get { return _lstJobDestSystems; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
SetProperty(ref _lstJobDestSystems, value);
}
}
//the Selected Source Site system ID
private int _selectedSrcSiteSystemId = 0;
public int SelectedSrcSiteSystemId
{
get { return _selectedSrcSiteSystemId; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
SetProperty(ref _selectedSrcSiteSystemId, value);
}
}
//the Selected Source Site system from the dropdown
private SourceSiteSystem _selectedSrcSiteSystem;
public SourceSiteSystem SelectedSrcSiteSystem
{
get { return _selectedSrcSiteSystem; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
if (value != null)
{
SetProperty(ref _selectedSrcSiteSystem, value);
SelectedSrcSiteSystemId = SelectedSrcSiteSystem.SiteSystemId;
}
}
}
//the Selected Destination Site system ID
private int _selectedDestSiteSystemId = 0;
public int SelectedDestSiteSystemId
{
get { return _selectedDestSiteSystemId; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
SetProperty(ref _selectedDestSiteSystemId, value);
}
}
//the Selected Destination Site system from the dropdown
private DestinationSiteSystem _selectedDestSiteSystem;
public DestinationSiteSystem SelectedDestSiteSystem
{
get { return _selectedDestSiteSystem; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
if (value != null)
{
SetProperty(ref _selectedDestSiteSystem, value);
SelectedDestSiteSystemId = SelectedDestSiteSystem.SiteSystemId;
}
}
}
private JobConfigurationResults _jeJobConfigurationResults;
public JobConfigurationResults JEJobConfigurationResults
{
get { return _jeJobConfigurationResults; }
set { _jeJobConfigurationResults = value; }
}
private List<JobTaskConfiguration> _taskSelectionList = new List<JobTaskConfiguration>();
private CancellationTokenSource _source;
private RelayCommand<object> _commandSaveInstance;
private RelayCommand<object> _hyperlinkInstance;
private RelayCommand<object> _commandRunJob;
private RelayCommand<object> _upCommand;
private RelayCommand<object> _downCommand;
private IEventAggregator _aggregator;
/// <summary>
/// This is a Subscriber to the Event published by EnterpriseViewModel
/// </summary>
/// <param name="agg"></param>
public JobConfigurationViewModel(IEventAggregator agg)
{
_aggregator = agg;
PubSubEvent<Message> evt = _aggregator.GetEvent<PubSubEvent<Message>>();
evt.Subscribe(message => Enterprise = message.Enterprise.ToString(), ThreadOption.BackgroundThread);
evt.Subscribe(message => Site = message.Site.ToString(), ThreadOption.BackgroundThread);
evt.Subscribe(message => SiteID = message.SiteID, ThreadOption.BackgroundThread);
//evt.Unsubscribe();
StartPopulate();
}
private async void StartPopulate()
{
await TaskPopulate();
}
//This is to ensure that the publisher has published the data that is needed for display in this workspace
private bool TaskProc()
{
Thread.Sleep(500);
PubSubEvent<Message> evt = _aggregator.GetEvent<PubSubEvent<Message>>();
evt.Subscribe(message => Enterprise = message.Enterprise.ToString(), ThreadOption.BackgroundThread);
evt.Subscribe(message => Site = message.Site.ToString(), ThreadOption.BackgroundThread);
evt.Subscribe(message => SiteID = message.SiteID, ThreadOption.BackgroundThread);
return DoPopulate();
}
private Task<bool> TaskPopulate()
{
_source = new CancellationTokenSource();
return Task.Factory.StartNew<bool>(TaskProc, _source.Token);
}
/// <summary>
/// This method handles the populating of the Source and Destination Dropdowns and the Job entity and Task Datagrid
/// This is mainly driven by the Site selected in the previous workspace
/// </summary>
/// <returns></returns>
private bool DoPopulate()
{
PopulateSourceDestinations(this.SiteID);
return true;
}
/// <summary>
/// this method displays all entities and tasks for the site.
/// This is done async so that the Publisher thread is not held up
/// </summary>
public void GetJobConfigurationResults()
{
if (SelectedSrcSiteSystem == null)
{
SelectedSrcSiteSystem = LstJobSrcSystems[0];
}
if (SelectedDestSiteSystem == null)
{
SelectedDestSiteSystem = LstJobDestSystems[0];
}
SelectedSrcSiteSystemId = SelectedSrcSiteSystem.SiteSystemId;
SelectedDestSiteSystemId = SelectedDestSiteSystem.SiteSystemId;
var jobConfigurationResults = new JobConfigurationResults
{
SourceId = SelectedSrcSiteSystemId,
DestinationId = SelectedDestSiteSystemId
};
JobEntities = new ObservableCollection<JobConfigurationResults>();
JobEntities = JobConfigurationLogic.GetResults(jobConfigurationResults.SourceId,
jobConfigurationResults.DestinationId);
_taskSelectionList = new List<JobTaskConfiguration>(JobEntities.Count * 3);
}
/// <summary>
/// //Adding a method to pupulate the Source and Destination dropdown lists.
/// This is done async so that the Publisher thread is not held up
/// </summary>
///
///
public async void PopulateSourceDestinations(int siteId)
{
this.LstJobSrcSystems = SrcDestConfigurationLogic.LoadSourceSiteSystems(siteId);
this.LstJobDestSystems = SrcDestConfigurationLogic.LoadDestinationSystems(siteId);
GetJobConfigurationResults();
}
public ICommand HyperlinkCommand
{
get
{
if (_hyperlinkInstance == null)
_hyperlinkInstance = new RelayCommand<object>(openDialog);
return _hyperlinkInstance;
}
}
private void openDialog(object obj)
{
JobConfigurationResults results = obj as JobConfigurationResults;
JEJobConfigurationResults = JobEntities.SingleOrDefault(x => x.JobEntityId == results.JobEntityId);
}
public ICommand CommandSave
{
get
{
if (_commandSaveInstance == null)
_commandSaveInstance = new RelayCommand<object>(saveJobConfigurationChanges);
return _commandSaveInstance;
}
}
public ICommand CommandRunJob
{
get { return _commandRunJob ?? (_commandRunJob = new RelayCommand<object>(RunJob)); }
}
/// <summary>
/// this saves all the changes in the selection made by the user
/// </summary>
/// <param name="ob"></param>
public void saveJobConfigurationChanges(object ob)
{
foreach (var job in JobEntities)
{
JobConfigurationLogic.UpdateSequence(job.SequenceOrder, job.JobEntityId); //Save Sequence Changes
int jobEntityId = job.JobEntityId;
foreach (var task in job.TaskDetails)
{
int id = task.JobTask_ID;
bool isSelected = task.IsSelected;
_taskSelectionList.Add(task);
}
}
JobConfigurationLogic.UpdateTaskSelection(_taskSelectionList);
}
public ICommand UpCommand
{
get
{
if (_upCommand == null)
_upCommand = new RelayCommand<object>(MoveUp);
return _upCommand;
}
}
private void MoveUp(object obj)
{
if (obj != null)
{
JobConfigurationResults results = obj as JobConfigurationResults;
currentJobID = results.JobEntityId;
currentSequence = results.SequenceOrder - 1;
JobConfigurationResults previousResult =
JobEntities.FirstOrDefault(n => n.SequenceOrder == currentSequence);
try
{
previousJobID = previousResult.JobId;
previousSequence = previousResult.SequenceOrder;
int newindex = JobEntities.IndexOf(results);
int oldindex = JobEntities.IndexOf(previousResult);
JobEntities[newindex].SequenceOrder = previousResult.SequenceOrder;
JobEntities[oldindex].SequenceOrder = results.SequenceOrder + 1;
//foreach (var i in JobEntities)
//{
// MessageBox.Show(i.EntityName + " " + i.SequenceOrder);
//}
}
catch (NullReferenceException)
{
MessageBox.Show("You have reached the top");
}
}
else
{
MessageBox.Show("Select a row first");
}
}
public ICommand DownCommand
{
get
{
if (_downCommand == null)
_downCommand = new RelayCommand<object>(MoveDown);
return _downCommand;
}
}
private void MoveDown(object obj)
{
if (obj != null)
{
JobConfigurationResults results = obj as JobConfigurationResults;
currentJobID = results.JobEntityId;
currentSequence = results.SequenceOrder + 1;
JobConfigurationResults previousResult =
JobEntities.FirstOrDefault(n => n.SequenceOrder == currentSequence);
try
{
previousJobID = previousResult.JobId;
previousSequence = previousResult.SequenceOrder;
int newindex = JobEntities.IndexOf(results);
int oldindex = JobEntities.IndexOf(previousResult);
JobEntities[newindex].SequenceOrder = previousResult.SequenceOrder;
JobEntities[oldindex].SequenceOrder = results.SequenceOrder - 1;
foreach (var i in JobEntities)
{
MessageBox.Show(i.EntityName + " " + i.SequenceOrder);
}
}
catch (NullReferenceException)
{
MessageBox.Show("You cannot move further down");
}
}
else
{
MessageBox.Show("Select a row first");
}
}
/// <summary>
/// Execute an etl job using the current job id
/// </summary>
private void RunJob(object obj)
{
JobEngine jobEngine = new JobEngine();
var jobId = JobEntities[0].JobId;
jobEngine.ProcessJob(jobId);
}
}
View.XAML:
<UserControl.Resources>
<DataTemplate x:Key="ItemTemplate1">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ItemTemplate2">
<StackPanel>
<TextBlock Text="{Binding Status}"/>
</StackPanel>
</DataTemplate>
<Style TargetType="{x:Type Border}">
<Setter Property="Background" Value="Bisque" />
<Setter Property="TextBlock.FontSize" Value="14" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="3*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="0.14*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.ColumnSpan="2">
<TextBlock>
<Label FontSize="16">Enterprise:</Label>
<Label Name="lblEnterprise" FontSize="16" Content="{Binding Enterprise}" />
<Label FontSize="16">Site:</Label>
<Label Name="lblSite" FontSize="16" Content="{Binding Site}" HorizontalAlignment="Right" />
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0">
<TextBlock>
<Label FontSize="16">Source System:</Label>
<ComboBox Name="CmbSource" Margin="3" SelectedIndex="0" Width="220" ItemsSource="{Binding LstJobSrcSystems}" SelectedItem="{Binding SelectedSrcSiteSystem, Mode=TwoWay}" DisplayMemberPath ="SourceSystemType"></ComboBox>
</TextBlock>
</StackPanel>
<StackPanel Grid.Column="0" Grid.Row="1">
<TextBlock HorizontalAlignment="Right" Margin="2,2,14,2">
<Label FontSize="16">Destination System:</Label>
<ComboBox Name="CmbDestination" SelectedIndex="0" Margin="2" Width="220" ItemsSource="{Binding LstJobDestSystems}" SelectedItem="{Binding SelectedDestSiteSystem, Mode=TwoWay}" DisplayMemberPath ="DestinationSystemType"></ComboBox>
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="2" Grid.ColumnSpan="2" Margin="0,2,0,46" Grid.RowSpan="3">
<Border BorderThickness="1" Width="{Binding ElementName=dgEntities,Path=Width}" Margin="35,48,60,48" Height="{Binding ElementName=grd,Path=Height}">
<Grid Name="grd" Height="30" Width="{Binding ElementName=JobConfigCol,Path=Width}" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="c1" Width="82*"/>
<ColumnDefinition x:Name="c2" Width="83*"/>
<ColumnDefinition x:Name="c3" Width="83*"/>
<ColumnDefinition x:Name="c4" Width="96*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" HorizontalAlignment="Center" FontWeight="Bold" FontSize="16" Margin="24,0,78,0" Width="62" Content="Extract"/>
<Label Grid.Column="1" HorizontalAlignment="Center" FontWeight="Bold" FontSize="16" Margin="40,0,38,0" Width="88" Content="Transform"/>
<Label Grid.Column="2" HorizontalAlignment="Center" FontWeight="Bold" FontSize="16" Margin="66,0,54,0" Width="46" Content="Load"/>
</Grid>
</Border>
<DataGrid x:Name="dgEntities" Width="690" Height="370" Margin="40,-48,65,-8" CanUserAddRows="false" SelectionMode="Single" ItemsSource="{Binding}" AutoGenerateColumns="False" CanUserSortColumns="False">
<DataGrid.DataContext>
<CollectionViewSource x:Name="CollectionViewSource" Source="{Binding Path=JobEntities,Mode=TwoWay,NotifyOnTargetUpdated=True}">
</CollectionViewSource>
</DataGrid.DataContext>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Status" Width="138" MaxWidth="138">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Margin="5" Content="{Binding TaskDetails[0].Status,Mode=TwoWay,NotifyOnTargetUpdated=True}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.HyperlinkCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Foreground="Blue" Cursor="Hand" MouseDoubleClick="Control_OnMouseDoubleClick" >
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn MinWidth="{Binding ElementName=c1,Path=ActualWidth}">
<DataGridTemplateColumn.Header>
<CheckBox Name="chkHeaderExtract" Checked="ChkHeaderExtract_OnChecked" Unchecked="ChkHeaderExtract_OnUnchecked"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" Name="chkExtract" IsChecked="{Binding TaskDetails[0].IsSelected,Mode=TwoWay,NotifyOnTargetUpdated=True,UpdateSourceTrigger=PropertyChanged}"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Status" Width="138" MaxWidth="138">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Margin="5" Content="{Binding TaskDetails[1].Status,Mode=TwoWay,NotifyOnTargetUpdated=True,UpdateSourceTrigger=PropertyChanged}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.HyperlinkCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Cursor="Hand" Foreground="Blue" MouseDoubleClick="Control_OnMouseDoubleClick_2" >
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn MinWidth="{Binding ElementName=c2,Path=ActualWidth}">
<DataGridTemplateColumn.Header>
<CheckBox Name="chkHeaderTransform" Checked="ChkHeaderTransform_OnChecked" Unchecked="ChkHeaderTransform_OnUnchecked"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" Name="chkTransform" IsChecked="{Binding TaskDetails[1].IsSelected,Mode=TwoWay,NotifyOnTargetUpdated=True,UpdateSourceTrigger=PropertyChanged}"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Status" Width="138" MaxWidth="138">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Margin="5" Content="{Binding TaskDetails[2].Status,Mode=TwoWay,NotifyOnTargetUpdated=True}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.HyperlinkCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Cursor="Hand" Foreground="Blue" MouseDoubleClick="Control_OnMouseDoubleClick" >
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn MinWidth="{Binding ElementName=c3,Path=ActualWidth}">
<DataGridTemplateColumn.Header>
<CheckBox Name="chkHeaderLoad" Checked="ChkHeaderLoad_OnChecked" Unchecked="ChkHeaderLoad_OnUnchecked"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" Name="chkLoad" IsChecked="{Binding TaskDetails[2].IsSelected,Mode=TwoWay,NotifyOnTargetUpdated=True,UpdateSourceTrigger=PropertyChanged}"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding EntityName}" Header="Entity" Width="{Binding ElementName=c4,Path=ActualWidth}"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel HorizontalAlignment="Right" Margin="0,-388,43,0" Height="108">
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Top"><InlineUIContainer>
<Button Height="40" Width="40" x:Name="btnup" Command="{Binding UpCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Click="Btnup_OnClick">
<Image x:Name="Up" Source="../Images/up.jpg" Height="40" />
</Button>
</InlineUIContainer></TextBlock>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,2"><InlineUIContainer>
<Button Height="40" Width="40" x:Name="btndown" Command="{Binding DownCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Click="btndown_Click">
<Image x:Name="Down" Source="../Images/Down.jpg" Height="40" />
</Button>
</InlineUIContainer></TextBlock>
</StackPanel>
</StackPanel>
<StackPanel Grid.Row="4" Grid.Column="0">
<TextBlock Name="tbldemo" HorizontalAlignment="Right">
<Button Name="btnRun" Height="30" Width="90" FontSize="18" Margin="9" Command="{Binding CommandRunJob}" >Run</Button>
<Button Name="btnSave" Height="30" Width="90" FontSize="18" Margin="9" Command="{Binding CommandSave, Mode=OneWay}">Save</Button>
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="4" Grid.Column="0">
<TextBlock HorizontalAlignment="Left">
<Button Name="btnclose" Height="30" Width="90" FontSize="18" Margin="19,9">Close</Button>
</TextBlock>
</StackPanel>
</Grid>
</UserControl>
CS: Im saying CollectionViewSource.View.Refresh();
I believe you are on the right track. the reason your view is not updating when you are changing properties in the collection from the view model, is because while you are making use of ObservableCollection for it to work correctly in the way you are describing, you will need to make sure that the type that you are binding to in the collection implements INotifyProperyChanged. Once you do this, the ObservableCollection will receive this message and in turn notify your view of the changes and ultimately causing a view update.
so in your case you would need to make sure that the type JobConfigurationResults implements the INotifyPropertyChanged interface.
For a reference, you can view this link and towards the bottom of the page you will find the note describing what I am suggesting. http://msdn.microsoft.com/en-us/library/ms748365(v=vs.110).aspx

ListBox binding with ViewModel in WPF

I am new to the WPF and trying to build a sample application using the MVVM framework. My application has a xaml file which has some textboxes for inputing customer info, combo box for display of states and a save button. All the databinding is done through ViewModel(CustomerViewMode) which has a reference to the Model(Customer), containing the required fields and their
Getter, setters. The viewModel has a CustomerList property.
On clicking the save button, I want to display the FirstName and LastName properties of Customer in a ListBox. This is where the problem is. I debugged the code,
(Click event of button in the code behind), I can see that the CustomerList has the first Customer object with all its details, but its not getting displayed in the listbox.
My code is:
Customer(Model);
enter code here
namespace SampleMVVM.Models
{
class Customer : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private String _firstName;
private String _lastName;
private Address _customerAddress;
public String FirstName
{
get { return _firstName; }
set
{
if (value != _firstName)
{
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
}
public String LastName
{
get { return _lastName; }
set
{
if (value != _lastName)
{
_lastName = value;
RaisePropertyChanged("LastName");
}
}
}
public Address CustomerAddress
{
get { return _customerAddress; }
set
{
if (value != _customerAddress)
{
_customerAddress = value;
RaisePropertyChanged("CustomerAddress");
}
}
}
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Address(Model)
namespace SampleMVVM.Models
{
class Address : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _addressLine1;
private string _addressLine2;
private string _city;
//private string _selectedState;
private string _postalCode;
private string _country;
public String AddressLine1
{
get { return _addressLine1; }
set
{
if (value != _addressLine1)
{
_addressLine1 = value;
RaisePropertyChanged(AddressLine1);
}
}
}
public String AddressLine2
{
get { return _addressLine2; }
set
{
if (value != _addressLine2)
{
_addressLine2 = value;
RaisePropertyChanged(AddressLine2);
}
}
}
public String City
{
get { return _city; }
set
{
if (value != _city)
{
_city = value;
RaisePropertyChanged(City);
}
}
}
public String PostalCode
{
get { return _postalCode; }
set
{
if (value != _postalCode)
{
_postalCode = value;
RaisePropertyChanged(PostalCode);
}
}
}
public String Country
{
get { return _country; }
set
{
if (value != _country)
{
_country = value;
RaisePropertyChanged(Country);
}
}
}
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
CustomerViewModel:
namespace SampleMVVM.ViewModels
{
class CustomerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Customer _customer;
RelayCommand _saveCommand;
private List<String> _stateList = new List<string>();
private string _selectedState;
private ObservableCollection<Customer> _customerList = new ObservableCollection<Customer>();
//public CustomerViewModel(ObservableCollection<Customer> customers)
//{
// _customers = new ListCollectionView(customers);
//}
public Customer CustomerModel
{
get { return _customer; }
set
{
if (value != _customer)
{
_customer = value;
RaisePropertyChanged("CustomerModel");
}
}
}
public List<String> StateList
{
get
{
return _stateList;
}
set { _stateList = value; }
}
public ObservableCollection<Customer> CustomerList
{
get
{
return _customerList;
}
set
{
if (value != _customerList)
{
_customerList = value;
RaisePropertyChanged("CustomerList");
}
}
}
public CustomerViewModel()
{
CustomerModel = new Customer
{
FirstName = "Fred",
LastName = "Anders",
CustomerAddress = new Address
{
AddressLine1 = "Northeastern University",
AddressLine2 = "360, Huntington Avenue",
City = "Boston",
PostalCode = "02115",
Country = "US",
}
};
StateList = new List<String>
{
"Alaska", "Arizona", "California", "Connecticut", "Massachusetts", "New Jersey", "Pennsylvania", "Texas"
};
SelectedState = StateList.FirstOrDefault();
}
public String SelectedState
{
get { return _selectedState; }
set
{
if (value != _selectedState)
{
_selectedState = value;
RaisePropertyChanged(SelectedState);
}
}
}
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
CustomerInfo.xaml(view)
<UserControl x:Class="SampleMVVM.Views.CustomerInfo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ViewModels="clr-namespace:SampleMVVM.ViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<ViewModels:CustomerViewModel />
</UserControl.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<!--Starting label-->
<TextBlock FontSize="18" FontFamily="Comic Sans MS" FontWeight="ExtraBlack"
Foreground="Navy"
Grid.Row="0" HorizontalAlignment="Center">
<TextBlock.Text>
Customer Information:
</TextBlock.Text>
</TextBlock>
<TextBlock Text="First name: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="1" Width="80px" Height="50px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.FirstName}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="1" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0" Name="fname"/>
<TextBlock Text="Last Name: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="2" Width="80px" Height="50px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.LastName}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="2" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0" Name="lname"/>
<TextBlock Text="Address: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="3" Width="80px" Height="50px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.AddressLine1}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="3" Grid.Column="1" Width="160px" Height="20px" Margin="20,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.AddressLine2}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="4" Grid.Column="1" Width="160px" Height="30px" Margin="20,5,0,0"/>
<TextBlock Text="City: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="5" Width="80px" Height="20px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.City}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="5" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0"/>
<TextBlock Text="State: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="6" Width="80px" Height="20px" Margin="40,5,0,0"/>
<ComboBox Grid.RowSpan="2" HorizontalAlignment="Left" Name="listOfSates"
VerticalAlignment="Top"
Grid.Row="6" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0"
ItemsSource="{Binding Path=StateList}"
SelectedItem="{Binding Path=SelectedState}"
SelectionChanged="ComboBox_SelectionChanged"
>
</ComboBox>
<TextBlock Text="PostalCode: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="7" Width="80px" Height="20px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.PostalCode}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="7" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0"/>
<TextBlock Text="Country: " Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="8" Width="80px" Height="20px" Margin="40,5,0,0"/>
<TextBox Text="{Binding CustomerModel.CustomerAddress.Country}" Grid.RowSpan="2" HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="8" Grid.Column="1" Width="80px" Height="20px" Margin="20,5,0,0"/>
<Button Content="Save" Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Grid.Row="9" Width="50px" Height="20px" Name="savebtn" Margin="40,5,0,0"
Click="savebtn_Click"/>
<ListBox Name="cList" ItemsSource="{Binding Path=CustomerList}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Row="1" Grid.Column="2" Grid.RowSpan="2" Width="200px" Height="300px" Margin="200,5,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding CustomerModel.FirstName}"
FontWeight="Bold" Foreground="Navy"/>
<TextBlock Text=", " />
<TextBlock Text="{Binding CustomerModel.LastName}"
FontWeight="Bold" Foreground="Navy"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
CustomerInfo(Code behind class)
namespace SampleMVVM.Views
{
/// <summary>
/// Interaction logic for CustomerInfo.xaml
/// </summary>
public partial class CustomerInfo : UserControl
{
public CustomerInfo()
{
InitializeComponent();
//checkvalue();
}
private void savebtn_Click(object sender, RoutedEventArgs e)
{
////Customer c = new Customer();
////c.FirstName = fname.Text;
////c.LastName = lname.Text;
//CustomerViewModel cvm = new CustomerViewModel();
//cvm.CustomerModel.FirstName = fname.Text;
//cvm.CustomerModel.LastName = lname.Text;
//List<CustomerViewModel> customerList = new List<CustomerViewModel>();
//customerList.Add(cvm);
var viewModel = DataContext as CustomerViewModel;
if (viewModel != null)
{
//viewModel.ShowCustomerInfo();
String strfname = viewModel.CustomerModel.FirstName;
String strname = viewModel.CustomerModel.LastName;
viewModel.CustomerList.Add(viewModel.CustomerModel);
String str1 = viewModel.CustomerList.FirstOrDefault().FirstName;
int i = viewModel.CustomerList.Count();
//cList.ItemsSource = viewModel.CustomerList;
}
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CustomerViewModel cvm = new CustomerViewModel();
cvm.SelectedState = listOfSates.SelectedItem.ToString();
}
}
}
I just cant understand where am I going wrong...Someone please help
And for the correct binding in ListBox.ItemTemplate:
<TextBlock Text="{Binding FirstName}"
FontWeight="Bold" Foreground="Navy"/>
<TextBlock Text="{Binding LastName}"
FontWeight="Bold" Foreground="Navy"/>
The DataContext of ListBoxItem is a Customer already.
You only create a new instance of a CustomerModel object once in your code (in the Customer View Model constructor). So you are constantly updating the same customer object rather than creating a new one.
At the end of your click handler you should do a
viewModel.CustomerModel = new Customer();
HOWEVER
Rather than having a click handler you should have an ICommand in your view model for adding a new customer. Then you should bind to command of your button to the ICommand in your view model.
you were binding the CustomerLIst.FirstName which is not walid because innterconent will check for property name customerlist in side the listbox itemssource. and as its not their then it will raise a silent error but wo't show into GUI, what you need to do is just provide the propertyname like firstname and lastname that will work.
well besides your binding in listbox every thing else is ok. just replace you listbox binding as like below.
<TextBlock Grid.Row="0"
Grid.Column="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="List of Customers" />
<ListBox Name="cList"
Grid.Row="1"
Grid.RowSpan="8"
Grid.Column="2"
ItemsSource="{Binding CustomerList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock FontWeight="Bold"
Foreground="Black"
Text="{Binding FirstName}" />
<TextBlock Text=", " />
<TextBlock FontWeight="Bold"
Foreground="Black"
Text="{Binding LastName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Grid.Row="10"
Grid.Column="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding CustomerList.Count,
StringFormat='Total Customers, ={0}'}" />
better to take command insteed of events.
Your problem is in this line of code:
RaisePropertyChanged("CustomerList");
It doesn't work for collection add/remove events. Take a look at ObservableCollection and Item PropertyChanged.
Keep in mind that in MVVM, you should not have much code (if any) in code behind. Consider using commands.

refresh datagrid on view from viewmodel

I have a datagrid on a view that is bound to a viewmodel. When I initialze the view, the datagrid is populated with data from the viewmodel (ObservableCollection) as it should. However, with I try to do a search against the data, the datagrid does not get refreshed from the viewmodel. When I breakpoint the code in my viewmodel, I can see the results in the ObservableCollection has changed per my search, but somehow that is not getting communicated back to the view. Here is my view and viewmodel (BTW, I am using VS2010 RTM):
namespace Attendance.ViewModels
{
public class EmployeeSelectViewModel : ViewModel, INotifyPropertyChanged
{
#region Entity list and constructor
public EmployeeSelectViewModel()
{
{
Initialize();
}
}
private void Initialize()
{
if (employeeRpository == null)
employeeRpository = new EmployeeRepository();
ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployees(true));
}
private EmployeeRepository employeeRpository;
private ObservableCollection<EmployeeDto> listOfEmployees;
public ObservableCollection<EmployeeDto> ListOfEmployees
{
get { return listOfEmployees; }
set
{
if (listOfEmployees != value)
{
listOfEmployees = value;
NotifyPropertyChanged("ListOfEmployee");
}
}
}
private EmployeeDto selectedEmployee;
public EmployeeDto SelectedEmployee
{
get { return selectedEmployee; }
set
{
if (selectedEmployee != value)
{
selectedEmployee = value;
NotifyPropertyChanged("SelectedEmployee");
}
}
}
#endregion
#region UI control references
/// <summary>
/// search text property
/// </summary>
private string searchText;
public string SearchText
{
get { return searchText; }
set
{
if (searchText != value)
{
searchText = value;
NotifyPropertyChanged("SearchText");
}
}
}
public string Location { get; set; }
#endregion
#region Relay Commands
/// <summary>
/// new command
/// </summary>
private ViewCommand newCommand;
public ViewCommand NewCommand
{
get
{
if (newCommand == null)
newCommand = new ViewCommand(param => this.NewEmployee());
return newCommand;
}
}
private void NewEmployee()
{
NavigationActions.NewEmployeeView();
}
/// <summary>
/// edit command
/// </summary>
private ViewCommand editCommand;
public ViewCommand EditCommand
{
get
{
if (editCommand == null)
{
editCommand = new ViewCommand(param => this.EditEmployee());
}
return editCommand;
}
}
private void EditEmployee()
{
NavigationActions.OpenEmployeeView(SelectedEmployee);
}
/// <summary>
/// save command
/// </summary>
private ViewCommand saveCommand;
public ViewCommand SaveCommand
{
get
{
if (saveCommand == null)
{
saveCommand = new ViewCommand(
param => this.SaveEmployee(),
param => this.CanSaveEmployee
);
}
return saveCommand;
}
}
public void SaveEmployee()
{
employeeRpository.SaveChanges();
}
private bool CanSaveEmployee
{
get { return true; }
}
/// <summary>
/// clear search command
/// </summary>
private ViewCommand clearSearchCommand;
public ViewCommand ClearSearchCommand
{
get
{
if (clearSearchCommand == null)
clearSearchCommand = new ViewCommand(param => this.ClearSearch());
return clearSearchCommand;
}
}
private void ClearSearch()
{
this.SearchText = string.Empty;
ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployees(true));
}
/// <summary>
/// search command
/// </summary>
private ViewCommand searchCommand;
public ViewCommand SearchCommand
{
get
{
if (searchCommand == null)
searchCommand = new ViewCommand(param => this.SearchEmployee());
return searchCommand;
}
}
private void SearchEmployee()
{
if (this.SearchText == string.Empty || this.SearchText == null)
{
NavigationActions.ShowError("Search Employees.", "Please enter your search text ...");
return;
}
ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployeesByQuery(SearchText, Location));
}
/// <summary>
/// exit command
/// </summary>
private ViewCommand exitCommand;
public ViewCommand ExitCommand
{
get
{
if (exitCommand == null)
{
exitCommand = new ViewCommand(param => this.ExitWindow());
}
return exitCommand;
}
}
private void ExitWindow()
{
NavigationActions.CloseCurrentView();
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
<Window x:Class="Attendance.Views.EmployeeSelectView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Attendance.ViewModels"
Title="Employee Maintenance" FocusManager.FocusedElement="{Binding ElementName=txtSearchCriteria}"
Height="525" Width="800" WindowStartupLocation="CenterScreen" WindowState="Normal"
WindowStyle="SingleBorderWindow" Icon="Images/gb_icon.png">
<Window.DataContext>
<vm:EmployeeSelectViewModel />
</Window.DataContext>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/DataGrid.Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<!--xml data start-->
<XmlDataProvider x:Key="LocationData" XPath="LocationList/LocationItem" Source="XMLData/Location.xml"/>
<!--xml data end-->
</ResourceDictionary>
</Window.Resources>
<Grid Width="775">
<DockPanel HorizontalAlignment="Left" Width="770">
<!-- TOOLBAR -->
<DockPanel DockPanel.Dock="Top" MinHeight="30" Margin="5">
<ToolBar FontWeight="Bold">
<!-- NEW -->
<Button Name="btnNew" Command="{Binding Path=NewCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Create a new Customer
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Create a new customer in a new Window tab.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/new.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/new.png" Width="22" Height="22" Margin="2"/>
<Label VerticalAlignment="Center">_New</Label>
</StackPanel>
</Button>
<!-- EDIT -->
<Button Name="btnEdit" Command="{Binding Path=EditCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Edit the current record
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Edit the current selected Customer.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/dialog-information.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/edit.png" Width="22" Height="22" Margin="2" />
<Label VerticalAlignment="Center">_Edit</Label>
</StackPanel>
</Button>
<!-- SEARCH -->
<Separator />
<TextBox Name="txtSearchCriteria"
MinWidth="300" Margin="5"
BorderThickness="1" BorderBrush="LightGray"
FontWeight="Normal" Foreground="Gray" Text="{Binding Path=SearchText}">
</TextBox>
<Button Name="btnSearch" Command="{Binding Path=SearchCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Search
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Search a specific Customer.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/find.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/find.png" Width="22" Height="22" Margin="2" />
<Label VerticalAlignment="Center">_Find</Label>
</StackPanel>
</Button>
<Button Name="btnClearSearch" Command="{Binding Path=ClearSearchCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Search
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Clear search results.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/find.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Label VerticalAlignment="Center">_Clear Search</Label>
</StackPanel>
</Button>
<!-- EXIT -->
<Separator />
<Button Name="btnExit" Command="{Binding Path=ExitCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Start the application
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Start the main application with the M-V-MV pattern.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/dialog-information.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/exit.png" Width="22" Height="22" Margin="2" />
<Label VerticalAlignment="Center">_Exit</Label>
</StackPanel>
</Button>
</ToolBar>
</DockPanel>
<!-- LIST -->
<DockPanel DockPanel.Dock="Top" MinHeight="30" Margin="0,0,0,5">
<Label>Location:</Label>
<ComboBox Name="cboLocation" Grid.Column="1" Grid.Row="4"
ItemsSource="{Binding Source={StaticResource LocationData}}"
DisplayMemberPath="location_text" SelectedValuePath="location_value"
SelectedValue="{Binding Path=Location}"
HorizontalAlignment="Left" Width="175" Margin="4" />
</DockPanel>
<DockPanel Margin="5">
<DataGrid ItemsSource="{Binding Path=ListOfEmployees}" AutoGenerateColumns="False" IsReadOnly="True"
Name="dgEmployee" SelectionMode="Single" SelectionUnit="FullRow" CanUserResizeColumns="True"
SelectedItem="{Binding Path=SelectedEmployee}" GridLinesVisibility="Horizontal">
<DataGrid.Columns>
<DataGridTextColumn Header="Employee ID" Width="SizeToCells" MinWidth="125" Binding="{Binding EmployeeID}" />
<DataGridTextColumn Header="First Name" Width="SizeToCells" MinWidth="200" Binding="{Binding FirstName}" />
<DataGridTextColumn Header="Last Name" Width="SizeToCells" MinWidth="200" Binding="{Binding LastName}" />
<DataGridTextColumn Header="Location" Width="SizeToCells" MinWidth="125" Binding="{Binding Location}" />
<DataGridCheckBoxColumn x:Name="Active" Header="Active" Binding="{Binding active}" MinWidth="75" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</DockPanel>
</Grid>
This was my solution:
<DataGrid Name="dgrid" ItemsSource="{Binding UserSettings, IsAsync=True}" AutoGenerateColumns="False">
The key being the setting of IsAsync=True, allows the screen paint to occur
I found 2 ways to refresh DataGrid:
One was posted by VariableLost, it works with INotifyPropertyChanged but have one drawback. Whole DataGrid is refreshed with blink effect (disappears for a split second). Doesn't look natural.
Other solution is to refresh ObservableCollection in ViewModel or Code Behind (if you're not using MVVM):
CollectionViewSource.GetDefaultView(collectionName).Refresh();
Looks more natural because only changes cells affected by edition.
Your previous code should have also worked, but 'magic strings' got in the way.
Property name is ListOfEmployees and in its setter you raise PropertyChanged event with property name ListOfEmployee. 's' is missing.
Beware of your new code. It will raise CollectionChanged event on ListOfEmployees for every insertion, and that might make your app slower if you are doing many insertions.
For many insertions, it would be better to derive from ObservableCollection and implement Reset method that clears underlying Items, adds new items and raises CollectionChanged event of type Reset.
My question was answered in a post on another site. Instead of creating a new instance of the ListOfEmployees in my view model, I just cleared the existing one and added the results from my repository:
private void SearchEmployee()
{
if (String.IsNullOrEmpty(this.SearchText) || String.IsNullOrEmpty(this.Location))
{
NavigationActions.ShowError("Search Employees.", "Please enter your search text and select a location...");
return;
}
// clear the list and repopulate based on the search criteria
if (ListOfEmployees != null)
{
ListOfEmployees.Clear();
IList<EmployeeDto> iList = employeeRpository.GetEmployeesByQuery(SearchText, Location, IsActive);
foreach (EmployeeDto value in iList)
ListOfEmployees.Add(value);
}
}
That did the trick.

Resources