refresh datagrid on view from viewmodel - wpf

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.

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

how to get textbox value from View to ViewModel in Silverlight MVVM?

Currently now i'm using silverlight5 with MVVM. in SL5 i need to do the following.
I have 3 textbox and 1 button control and i datagrid in the xaml(Design page).
here is the Design View(Xaml):
<UserControl.DataContext>
<VC:EmployeeListViewModel />
</UserControl.DataContext>
<Grid x:Name="LayoutRoot">
<my:DataGrid x:Name="McDataGrid" ItemsSource="{Binding Employees,UpdateSourceTrigger=PropertyChanged}" Margin="130,151,0,0" Height="137" VerticalAlignment="Top" RowBackground="#AA5D9324" AutoGenerateColumns="True" HorizontalAlignment="Left" Width="193">
</my:DataGrid>
<Button Content="Show Message" Width="100" Height="25" Margin="256,75,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<si:CallDataMethod Method="AddEmployeeCommand"/>
<si:ShowMessageBox Caption="Thank you"
Message="Thanks for trying the Example"
MessageBoxButton="OK"/>
<si:SetProperty TargetName="LayoutRoot"
PropertyName="Background" Value="PaleGoldenrod"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<TextBlock FontWeight="Bold" Height="26" HorizontalAlignment="Left" Margin="47,12,0,0" Name="textBlock1" Text="First Name:" VerticalAlignment="Top" Width="77" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Employee.Fname}" />
<TextBlock FontWeight="Bold" Height="25" HorizontalAlignment="Left" Margin="35,44,0,0" Name="textBlock2" Text="Second Name:" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,44,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" />
<TextBlock FontWeight="Bold" Height="23" HorizontalAlignment="Left" Margin="45,75,0,0" Name="textBlock3" Text="Department:" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,75,0,0" Name="textBox3" VerticalAlignment="Top" Width="120" />
<!-- Add reference to Microsoft.Expression.Interactions.dll, System.Windows.Interactivity.dll -->
<!-- Use mvvmxmlns snippet to add i and ei namespace prefixes -->
</ComboBox>
<TextBlock Height="23" HorizontalAlignment="Left" Margin="64,122,0,0" Name="textBlock4" Text="Choose:" VerticalAlignment="Top" FontWeight="Bold" />
</Grid>
</UserControl>
in the same project i create one folder named 'ViewModel':
in the same folder i add one class file named: EmployeeListViewModel.cs
my question is this. how to pass the textbox value to the viewmodel[EmployeeListViewModel] and insert the it to the Datagrid.
EmployeeListViewModel.cs:
public class EmployeeListViewModel:INotifyPropertyChanged
{
public ObservableCollection<Employee> Employees { get; private set; }
public EmployeeListViewModel()
{
Employees = Silverlight_MVVM.DataHelper.EmployeeDataHelper.EmployeeData ();
}
private Employee _SelectedEmployee;
public Employee SelectedEmployee
{
get
{
return _SelectedEmployee;
}
set
{
_SelectedEmployee = value;
RaisePropertyChanged("SelectedEmployee");
}
}
private Employee _Names;
public Employee Names
{
get
{
return _Names;
}
set
{
_Names = value;
RaisePropertyChanged("Names");
}
}
public void HandleShowMessage()
{
// MessageBox.Show("Hello " + Names + ",Welcome to EventTrigger for MVVM.");
}
public RelayCommand _AddEmployeeCommand;
/// <summary>
/// Returns a command that show the customer.
/// </summary>
public ICommand AddEmployeeCommand
{
get
{
if (_AddEmployeeCommand == null)
{
_AddEmployeeCommand = new RelayCommand(
param => this.AddEmployee(),
param => this.CanAddEmployee
);
}
return _AddEmployeeCommand;
}
}
public bool CanAddEmployee
{
get
{
return true;
}
}
public void AddEmployee()
{
//Employee newEmployee = new Employee("New1);
Employee newEmployee = new Employee() **{};**
--> **Here i have to pass the value.. How is it possible..?**
Employees.Add(newEmployee);
SelectedEmployee = newEmployee;
}
#region INotifyPropertyChanged
// [field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Not 100% sure how you are going about this?
Usually I would have the grid bound to the selected employee as you have, then have the values of the text boxes bound to the properties on the selectedemployee. As you change row, these would then update to reflect the values of the currently selected row in the grid.
So then you add a new blank employee and it would have blank values until they were entered in the text box. Of course, you'd need to build in some validation to ensure you don't get loads of blabnk rows added.
If I'm correct in my understanding of how you are wanting to do it, then as it stands the values in the text boxes are not related to the selected row, but are used just to add a new employee with those values? to achieve this I would suggest having the Textbox bind to a string value on the Viewmodel. Currently you have them bound to something that doesn't appear to actually exist. Instead, I'd bind them to their own properties on the view model thus:
private string _employeeFirstName;
public string EmployeeFirstName
{
get
{
return _employeeFirstName;
}
set
{
_employeeFirstName= value;
RaisePropertyChanged("EmployeeFirstName");
}
}
and then in the xaml bind to that property - with Mode=TwoWay so that the viewmodel also recieves any updates
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=EmployeeFirstName, Mode=TwoWay}" />
then when creating your new employee:
public void AddEmployee()
{
Employee newEmployee = new Employee() {FName = this.EmployeeFirstName};
Employees.Add(newEmployee);
SelectedEmployee = newEmployee;
}
You have to use TwoWay binding mode. For example, Text="{Binding Path=Employee.Fname,Mode=TwoWay}". You can read more about Binding.Mode on MSDN.
i create three property named Fname,Sname,Dept respectly in View Model..
private string _fname;
public string Fname
{
get
{
return _fname;
}
set
{
_fname = value;
RaisePropertyChanged("Fname");
}
}
And the function is as follows..
public void AddEmployee()
{
Employee newEmployee = new Employee() {Fname=this.Fname;Sname=this.Sname;Dept=this.Dept};
Employees.Add(newEmployee);
SelectedEmployee = newEmployee;
}
It Works Well..
Design Code is :
<TextBlock FontWeight="Bold" Height="26" HorizontalAlignment="Left" Margin="47,12,0,0" Name="textBlock1" Text="First Name:" VerticalAlignment="Top" Width="77" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Fname,Mode=TwoWay}" />
<TextBlock FontWeight="Bold" Height="25" HorizontalAlignment="Left" Margin="35,44,0,0" Name="textBlock2" Text="Second Name:" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,44,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Text="{Binding Path=Sname,Mode=TwoWay}"/>
<TextBlock FontWeight="Bold" Height="23" HorizontalAlignment="Left" Margin="45,75,0,0" Name="textBlock3" Text="Department:" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,75,0,0" Name="textBox3" VerticalAlignment="Top" Width="120" Text="{Binding Path=Dept,Mode=TwoWay}"/>
<Button Content="Show Message" Width="100" Height="25" Margin="256,75,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<si:CallDataMethod Method="AddEmployee"/>
<si:ShowMessageBox Caption="Thank you"
Message="Thanks for trying the Example"
MessageBoxButton="OK"/>
<si:SetProperty TargetName="LayoutRoot"
PropertyName="Background" Value="PaleGoldenrod"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
Hope it will useful to us..

When does the binding on the ItemsSource property generate Items?

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.

Resources