Properties are null when calling a command method - c#

When RefreshServices() is called, both SelectedComputerand SelectedCustomerare null, even though they are not when I actually select them.
Why?
/edit: Forgot to post the buttons' declarations in the XAML. It's updated now.
MainWindow.xaml.cs
public partial class MainWindow : Window
{
MainViewModel _main = new MainViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _main;
}
}
XAML:
<Window.Resources>
<vm:MainViewModel x:Key="viewModel" />
</Window.Resources>
<Border Margin="10">
<Grid>
<!-- Comboboxes -->
<GroupBox Header="Computer" Grid.Column="0" Grid.ColumnSpan="4" Margin="0 0 4 4">
<ComboBox ItemsSource="{Binding ComputerNames}"
SelectedItem="{Binding SelectedComputer}"
IsSynchronizedWithCurrentItem="True"
SelectedIndex="0"/>
</GroupBox>
<GroupBox Header="Customer" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" Margin="0 0 4 4" >
<ComboBox ItemsSource="{Binding CustomerNames}"
SelectedItem="{Binding SelectedCustomer}"
IsSynchronizedWithCurrentItem="True"
SelectedIndex="0"/>
</GroupBox>
<!-- Main list -->
<DataGrid x:Name="dataGrid" Grid.Row="2" Grid.ColumnSpan="8"
ItemsSource="{Binding Path=Services, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
AutoGenerateColumns="False"
IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="*" Binding="{Binding DisplayName}"/>
<DataGridTextColumn Header="Status" Width="*" Binding="{Binding Status}" />
<DataGridTextColumn Header="Machine Name" Width="*" Binding="{Binding MachineName}" />
</DataGrid.Columns>
</DataGrid>
<!-- Buttons-->
<Button Grid.Row="5" Grid.Column="0" Margin="0 4 4 4" Content="Start"
Command="{Binding Path=StartServiceCommand, Source={StaticResource viewModel}}"
CommandParameter="{Binding SelectedItems, ElementName=dataGrid}"/>
<Button Grid.Row="5" Grid.Column="1" Margin="4 4 0 4" Content="Stop"
Command="{Binding Path=StopServiceCommand, Source={StaticResource viewModel}}"
CommandParameter="{Binding SelectedItems, ElementName=dataGrid}"/>
<Button Grid.Row="5" Grid.Column="3" Margin="4 4 0 4" Content="Refresh"
Command="{Binding Path=RefreshServicesCommand, Source={StaticResource viewModel}}" />
</Grid>
</Border>
MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
#region INotify methods
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
#endregion
/*---------------------------- C U S T O M E R S -----------------------------*/
#region Customer Properties
private string _selectedCustomer;
private ObservableCollection<string> _customerNames;
public string SelectedCustomer
{
get => _selectedCustomer;
set
{
SetField(ref _selectedCustomer, value);
Services = Utils.UpdatedServices(SelectedComputer, SelectedCustomer);
}
}
public ObservableCollection<string> CustomerNames
{
get => _customerNames;
set
{
SetField(ref _customerNames, value);
Services = Utils.UpdatedServices(SelectedComputer, SelectedCustomer);
}
}
#endregion
/*---------------------------- S E R V I C E S -----------------------------*/
#region Services Properties
private ObservableCollection<ServiceController> _services;
private ObservableCollection<ServiceController> _selectedServices;
public ObservableCollection<ServiceController> SelectedServices
{
get => _selectedServices;
set => SetField(ref _selectedServices, value);
}
public ObservableCollection<ServiceController> Services
{
get => _services;
set => SetField(ref _services, value);
}
#endregion
/*---------------------------- C O M P U T E R S -----------------------------*/
#region Computer Properties
private string _selectedComputer;
private ObservableCollection<string> _computerNames;
public string SelectedComputer
{
get => _selectedComputer;
set
{
SetField(ref _selectedComputer, value);
CustomerNames = Utils.UpdatedCustomerNames(SelectedComputer);
}
}
public ObservableCollection<string> ComputerNames
{
get => _computerNames;
set => SetField(ref _computerNames, value);
}
#endregion
/*---------------------------- C O M M A N D S -----------------------------*/
#region Commands
public StartServiceCommand StartServiceCommand { get; set; }
public void StartService(ObservableCollection<ServiceController> serviceControllers)
{
try
{
foreach(var service in serviceControllers)
if (service.Status != ServiceControllerStatus.Running)
service.Start();
RefreshServices();
}
catch (Exception ex) { }
}
public StopServiceCommand StopServiceCommand { get; set; }
public void StopService(ObservableCollection<ServiceController> serviceControllers)
{
try
{
foreach (var service in serviceControllers)
if (service.Status != ServiceControllerStatus.Stopped &&
service.Status != ServiceControllerStatus.StopPending)
service.Stop();
RefreshServices();
}
catch (Exception ex) { }
}
public RefreshServicesCommand RefreshServicesCommand { get; set; }
public void RefreshServices()
{
Services = Utils.UpdatedServices(SelectedComputer, SelectedCustomer);
}
#endregion
public MainViewModel()
{
#region Initialize
_services = new ObservableCollection<ServiceController>();
_computerNames = new ObservableCollection<string>();
_customerNames = new ObservableCollection<string>();
_selectedComputer = _customerNames.FirstOrDefault();
_selectedServices = new ObservableCollection<ServiceController>();
ComputerNames = new ObservableCollection<string> { Environment.MachineName, Environment.MachineName };
StartServiceCommand = new StartServiceCommand(this);
StopServiceCommand = new StopServiceCommand(this);
RefreshServicesCommand = new RefreshServicesCommand(this);
#endregion
}
}

You created two instances of MainViewModel. Whenever you see "everything in my viewmodel is null even though, at the same time, it isn't" on Stack Overflow, look for duplicate viewmodel instantiations in the XAML and the constructor.
You're getting the Commands, inexplicably, from a throwaway copy in Window.Resources that's used for nothing else. Don't do that. Delete Source={StaticResource viewModel} from those bindings, and I think they should work as they are.
Grid is a direct child of the Window and doesn't have its own DataContext, so this should be fine. Let me know if not. We can make it work without too much trouble.
<Button Grid.Row="5" Grid.Column="0" Margin="0 4 4 4" Content="Start"
Command="{Binding StartServiceCommand}"
CommandParameter="{Binding SelectedItems, ElementName=dataGrid}"/>
<Button Grid.Row="5" Grid.Column="1" Margin="4 4 0 4" Content="Stop"
Command="{Binding StopServiceCommand}"
CommandParameter="{Binding SelectedItems, ElementName=dataGrid}"/>
<Button Grid.Row="5" Grid.Column="3" Margin="4 4 0 4" Content="Refresh"
Command="{Binding RefreshServicesCommand}" />

Related

TextBlock does not update after assigning the value

I am making a datagrid inside a window, where two columns are DockPanels with a TextBlock and a Button. When a user selects a file/folder, the TextBlock receives the value and displays it. However, it does not reflect it right away in my case. When I double click on the TextBlock, it suddenly shows. What am I missing here?
XAML
<DataGrid Name="copierDataGrid" Margin="30,50,30,100"
ItemsSource="{Binding SelectedAsm}" SelectedItem="{Binding Selected}" AutoGenerateColumns="False" CanUserResizeColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="Prefix" Width="70" Binding="{Binding prefCol, TargetNullValue=''}"/>
<DataGridTemplateColumn Width="235" CanUserResize="False" Header="Select File">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DockPanel DockPanel.Dock="Top">
<TextBlock Name="fileLocColtxtBox" Width="185" Margin="0,0,0,0" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="{Binding fileLocCol, TargetNullValue=''}"/>
<Button x:Name="brwsFileBtn" Content="..." Width="30" Margin="0,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Click="brwsFileBtn_Click"/>
</DockPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Suffix" Width="70" Binding="{Binding suffCol, TargetNullValue=''}"/>
<DataGridTemplateColumn Header="Target location" Width="*" CanUserResize="False" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DockPanel DockPanel.Dock="Top">
<TextBlock Name="destLocColtxtBox" Width="180" Margin="0,0,0,0" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="{Binding destLocCol, TargetNullValue=''}"/>
<Button x:Name="brwsFileBtn" Content="Browse" Width="50" Margin="0,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Click="brwsFolderBtn_Click"/>
</DockPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
XAML.CS
public itemAsm Selected { get; set; }
public ObservableCollection<itemAsm> SelectedAsm { get; set; }
public unitCopierFrm()
{
InitializeComponent();
SelectedAsm = new ObservableCollection<itemAsm>();
DataContext= this;}
public class itemAsm
{
public string prefCol { get; set; }
public string fileLocCol { get; set; }
public string suffCol { get; set; }
public string destLocCol { get; set; }
}
}private void brwsFolderBtn_Click(object sender, RoutedEventArgs e)
{
if (Selected !=null)
{
System.Windows.Forms.FolderBrowserDialog dlgFolderBrowser = new System.Windows.Forms.FolderBrowserDialog();
dlgFolderBrowser.Description = "Select the destination folder";
dlgFolderBrowser.RootFolder = System.Environment.SpecialFolder.MyComputer;
dlgFolderBrowser.ShowDialog();
string dirPath = dlgFolderBrowser.SelectedPath;
//if (dlgFolderBrowser.ShowDialog == Windows)
if (dirPath != null)
{
Selected.destLocCol = dirPath;
}
}
}
itemAsm should implement INotifyPropertyChanged and raise the PropertyChanged event to notify the view whenever the data-bound property has been set to a new value:
public class itemAsm : INotifyPropertyChanged
{
private string _prefCol;
public string prefCol
{
get { return _prefCol; }
set { _prefCol = value; NotifyPropertyChanged(); }
}
private string _fileLocCol;
public string fileLocCol
{
get { return _fileLocCol; }
set { _fileLocCol = value; NotifyPropertyChanged(); }
}
private string _suffCol;
public string suffCol
{
get { return _suffCol; }
set { _suffCol = value; NotifyPropertyChanged(); }
}
private string _destLocCol;
public string destLocCol
{
get { return _destLocCol; }
set { _destLocCol = value; NotifyPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
You may also want to consider renaming the properties according to the C# naming conventions.

ListView Not updating after RaisePropertyChangedEvent

I have the following XAML
<Label Content="Player Name" Grid.Row="0" Grid.Column="0" Margin="2,0,2,0" HorizontalAlignment="Right" Foreground="White"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="2,2,2,2" Text="{Binding PlayerFirstName}"/>
<Label Content="Player Last Name" Grid.Row="1" Grid.Column="0" Margin="2,0,2,0" HorizontalAlignment="Right" Foreground="White"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="2,2,2,2" Text="{Binding PlayerLastName}"/>
<Label Content="Player College" Grid.Row="2" Grid.Column="0" Margin="2,0,2,0" HorizontalAlignment="Right" Foreground="White"/>
<ComboBox Grid.Row="2" Grid.Column="1" Margin="2,2,2,2"
ItemsSource="{Binding Colleges}" DisplayMemberPath="CollegeName"
SelectedItem="{Binding SelectedCollege}"/>
<Button Content="Add Player" Grid.Row="3" Grid.Column="1" Width="75" Margin="2,2,2,2"
Background="Blue" Foreground="White" HorizontalAlignment="Right"
Command="{Binding NewPlayer}"/>
<ListView Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="1" Margin="2,2,2,2"
ItemsSource="{Binding Players, UpdateSourceTrigger=PropertyChanged}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" Width="100" DisplayMemberBinding="{Binding First}"/>
<GridViewColumn Header="Last Name" Width="100" DisplayMemberBinding="{Binding Last}"/>
<GridViewColumn Header="College" Width="100" DisplayMemberBinding="{Binding College}"/>
</GridView>
</ListView.View>
</ListView>
Which is bound to my PlayersViewModel Class
public class PlayersViewModel : ObservableObject
{
#region Variables
private DataView _Players = Controller.PlayerView.GetData().DefaultView;
private DataView _Colleges = Controller.CollegeTableAdapter.GetData().DefaultView;
private string _PlayerFirstName;
private string _PlayerLastName;
private DataRowView _SelectedCollege;
private long _PlayerCollegeID;
#endregion
#region Bindings
public DataView Players
{
get
{
return _Players;
}
set
{
_Players = value;
RaisePropertyChangedEvent("Players");
}
}
public DataView Colleges
{
get { return _Colleges; }
set
{
_Colleges = value;
RaisePropertyChangedEvent("Colleges");
}
}
public string PlayerFirstName
{
get { return _PlayerFirstName; }
set
{
_PlayerFirstName = value;
RaisePropertyChangedEvent("PlayerFirstName");
}
}
public string PlayerLastName
{
get { return _PlayerLastName; }
set
{
_PlayerLastName = value;
RaisePropertyChangedEvent("PlayerLastName");
}
}
public DataRowView SelectedCollege
{
get { return _SelectedCollege; }
set
{
_SelectedCollege = value;
_PlayerCollegeID = _SelectedCollege.Row.Field<long>("CollegeID");
RaisePropertyChangedEvent("SelectedCollege");
}
}
public ICommand NewPlayer
{
get { return new DelegateCommand(AddPlayer); }
}
#endregion
#region Methods
private void AddPlayer()
{
Controller.PersonTableAdapter.InsertPerson(_PlayerFirstName, _PlayerLastName, _PlayerCollegeID);
Players = Controller.PlayerView.GetData().DefaultView;
}
#endregion
}
This all works great, except when I run the InsertPerson Query in my PersonTableAdapter (which works manually and I've proven to work from the program), The Players ListView doesn't update after adding a new entry.
I found out what I did wrong.
Always make sure you are Implementing the INotifyPropertyChanged Interface in your ObservableObject Class
Mine looks like this now:
public abstract class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}

Loop through listview to get Checkbox status

<ListView Name="listViewLoadDisableSchems" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.View>
<GridView>
<GridViewColumn >
<GridViewColumn.CellTemplate >
<DataTemplate >
<DataTemplate >
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center" >
<Label Name="lblSchemeID" VerticalAlignment="Center" Margin="0" Content="{Binding Id}" Visibility="Hidden" />
<CheckBox Name="chkScheme" VerticalAlignment="Center" Margin="0,0,0,0" Content="{Binding Name}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I want to get lblSchemeID if checkbox is selected. so i can update database.
How i can do it on butten click?
You need to look at some basic MVVM patterns to get this going. Try this in the XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate >
<DataTemplate >
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center" >
<CheckBox VerticalAlignment="Center" Margin="0,0,0,0" Content="{Binding Name}" IsChecked="{Binding IsSelected}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<Button Grid.Row="1" Content="What is checked?" Command="{Binding GoCommand}"></Button>
and your equivalent of this in the view model & code behind:
public class MainViewModel
{
public ObservableCollection<TestItem> Items { get; set; } = new ObservableCollection<TestItem> { new TestItem() { Id = 1, Name = "Foo" }, new TestItem() { Id = 2, Name = "Bar" } };
public ICommand GoCommand => new DelegateCommand(Go);
void Go()
{
MessageBox.Show(string.Join(Environment.NewLine, Items.Where(x => x.IsSelected).Select(x => x.Name)));
}
}
public class TestItem : INotifyPropertyChanged
{
private bool _isSelected;
public int Id { get; set; }
public string Name { get; set; }
public bool IsSelected
{
get { return _isSelected; }
set
{
if (value == _isSelected) return;
_isSelected = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
You can get an implementation of delegate command from Google. Ditto implementations of INotifyPropertyChanged if you struggle with that.

checkbox in datagrid checked event not trigger wpf mvvm

my checkbox checked event is totally not trigger at all. here is my datagrid code. How should i trigger Checked event in wpf mvvm.
<Window x:Class="EmployeeManager.View.DataGridDownload"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Title="DataGridDownload" Height="600" Width="790">
<Grid>
<DataGrid HorizontalAlignment="Left" ItemsSource="{Binding TransView}" AutoGenerateColumns="False" Margin="10,62,0,0" VerticalAlignment="Top" Height="497" Width="762">
<DataGrid.Columns>
<DataGridTextColumn Header="caseRefNo" Binding="{Binding caseRefNo}" />
<DataGridTextColumn Header="subjMatr" Binding="{Binding subjMatr}" />
<DataGridTextColumn Header="Download %" Binding="{Binding incValue}" />
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
Content="Please Select" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding CheckCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding incValue,UpdateSourceTrigger=PropertyChanged}" Background="Red" Foreground="White" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Label Content="{Binding UpdatePercentage}" HorizontalAlignment="Left" Background="Blue" Foreground="White" Margin="10,10,0,0" VerticalAlignment="Top" Width="338" Height="30">
</Label>
<Button Content="Button" HorizontalAlignment="Left" Margin="672,20,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
Here is my view model
public class DataGridDownloadViewModel:BindableBase{
public ObservableCollection<tblTransaction> TransList
{ get; private set; }
public DispatcherTimer dispatchTimer = new DispatcherTimer();
public CollectionView TransView
{ get; private set; }
public DelegateCommand<object> CheckCommand { get; set; }
private String _UpdatePer;
public String UpdatePercentage
{
get { return _UpdatePer; }
set { SetProperty(ref _UpdatePer, value); }
}
private string _caseId;
public string CaseID
{
get { return _caseId; }
set { SetProperty(ref _caseId, value); }
}
private string _isChecked;
public string isChecked
{
get { return _isChecked; }
set { SetProperty(ref _isChecked, value); }
}
private bool CanExecute(object args)
{
return true;
}
private void CheckBoxChecker(object args)
{
//Should Work Here
// Totally not coming to this function
}
public DataGridDownloadViewModel(List<tblTransaction> model)
{
CheckCommand = new DelegateCommand<object>(CheckBoxChecker, CanExecute);
dispatchTimer.Interval = TimeSpan.FromMilliseconds(3000);
dispatchTimer.Tick += dispatchTimer_Tick;
BackGroundThread bgT = Application.Current.Resources["BackGroundThread"] as BackGroundThread;
bgT.GetPercentChanged += (ss, ee) =>
{
UpdatePercentage = bgT.local_percentage.ToString();
};
bgT.GetCaseID += (ss, ee) =>
{
CaseID = bgT.local_caseRef;
};
TransList =new ObservableCollection<tblTransaction>(model);
TransView = GetTransCollectionView(TransList);
TransView.Filter = OnFilterTrans;
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var cancellationTokenSource = new CancellationTokenSource();
dispatchTimer.Start();
}
private void dispatchTimer_Tick(object sender, EventArgs e)
{
UpdateDataGrid();
}
public void UpdateDataGrid()
{
foreach (tblTransaction tran in TransList)
{
if (tran.caseRefNo == CaseID)
{
tran.incValue = int.Parse(UpdatePercentage);
}
else
{
tran.incValue = tran.incValue;
}
}
TransView.Refresh();
}
bool OnFilterTrans(object item)
{
var trans = (tblTransaction)item;
return true;
}
public CollectionView GetTransCollectionView(ObservableCollection<tblTransaction> tranList)
{
return (CollectionView)CollectionViewSource.GetDefaultView(tranList);
}
}
Is it the correct way of doing it? why checkcommand is not trigger?
Edited
here is my model :
public class tblTransaction
{
public string caseRefNo { get;set;}
public string subjMatr { get; set; }
public int incValue { get; set; }
public DateTime? longTime { get; set; }
public bool IsSelected { get; set; }
}
Thanks
The code below worked for me without using the interactivity library like the answer above, just change the AncestorType property on the Command binding declaration according to your case, for me, I was using a UserControl, on the example above they used Window.
Good Luck!
<DataGridTemplateColumn Width="auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="select" HorizontalAlignment="Center"
Command="{Binding DataContext.CheckCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
IsChecked="{Binding Path=Selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Try the following:
<i:InvokeCommandAction Command="{Binding DataContext.CheckCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" />

Binding isn't working for ListBox while using MVVM

I have a simple UserControl with a DropDown showing versions like V14, V15 etc.
I have another ListBox whose ItemSource is binded to a property in the ViewModel which depend upon the SelectedValue of the Version DropDown.
ViewModel Looks like this:
class MultiSelectEnvironmentContextControlViewModel: ViewModelBase
{
private string selectedVersion;
private DomainFacade domainFacade;
private ObservableCollection<string> environments= new ObservableCollection<string>();
public MultiSelectEnvironmentContextControlViewModel()
{
domainFacade = ((App) Application.Current).DomainFacade;
}
public IEnumerable<string> EnvironmentVersions
{
get
{
return (domainFacade.GetEnvironmentVersions().Select(v => "Version " + v));
}
}
public string SelectedVersion
{
get { return selectedVersion; }
set
{
selectedVersion = value;
RaisePropertyChanged("Environments");
}
}
public ObservableCollection<string> Environments
{
get
{
environments = (ObservableCollection<string>)(domainFacade.GetEnvironments(SelectedVersion));
return environments;
}
}
}
I am keeping track of the SelectedVersion in a property which raises PropertyChanged on Environments so that whenever SeelectedVersion changes, the Environments should update the UI.
Issue I am facing is, ehn I run the application, I see the versions being populated, but there is nothing in the ListBox.
I am setting the DataContext of the UserControl to the ViewModel in the constructor of the UserControl.
Here is how my Control.cs file looks like:
public partial class MultiSelectEnvironmentContextControl : UserControl
{
private static MultiSelectEnvironmentContextControlViewModel dataContext = new MultiSelectEnvironmentContextControlViewModel();
public MultiSelectEnvironmentContextControl()
{
InitializeComponent();
this.DataContext = dataContext;
dataContext.SelectedVersion = (string)this.ComboBoxVersions.SelectedItem;
}
private void ComboBoxVersions_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
dataContext.SelectedVersion = ((ComboBox) sender).SelectedValue.ToString();
}
}
Here is the XAML:
<ComboBox Grid.Column="0" Grid.Row="0" x:Name="ComboBoxVersions" SelectedIndex="0" Margin="10" SelectionChanged="ComboBoxVersions_OnSelectionChanged" ItemsSource="{Binding EnvironmentVersions}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="0" Margin="10">
<TextBlock VerticalAlignment="Center" Margin="0,0,10,0">Tests to be run for:</TextBlock>
<ComboBox Name="ComboBoxFileTypeSelector" ItemsSource="{Binding AvailableValidationTypes}" DisplayMemberPath="Key" SelectedValuePath="Value" SelectedIndex="0">
</ComboBox>
</StackPanel>
<ListBox x:Name="ListBoxEnvironments" Grid.Column="0" Grid.Row="1" Height="300" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Margin="10" SelectionMode="Multiple" ItemsSource="{Binding Environments}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="800" >
</WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox x:Name="CheckBoxEnvironment" Content="{Binding}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Margin="5">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I believe this is because SelectedVersion has values like "Version 1", "Version 2", etc, but your method DomainFacade.GetEnvironments(string version) expects values like "1", "2" etc.
I would write your viewmodel like this:
public class MultiSelectEnvironmentContextControlViewModel : ViewModelBase
{
private string selectedVersion;
private DomainFacade domainFacade;
private IEnumerable<string> environments;
public MultiSelectEnvironmentContextControlViewModel()
{
domainFacade = ((App)Application.Current).DomainFacade;
EnvironmentVersions = domainFacade.GetEnvironmentVersions();
}
public IEnumerable<string> EnvironmentVersions { get; private set; }
public string SelectedVersion
{
get { return selectedVersion; }
set
{
selectedVersion = value;
RaisePropertyChanged("SelectedVersion");
Environments = domainFacade.GetEnvironments(SelectedVersion);
}
}
public IEnumerable<string> Environments
{
get { return environments; }
set
{
environments = value;
RaisePropertyChanged("Environments");
}
}
}
}
and applied to formatting of environment versions in view:
<ComboBox SelectedItem="{Binding SelectedVersion}"
ItemsSource="{Binding EnvironmentVersions}"
ItemStringFormat="Version: {0}" />

Categories

Resources