Update
I edited the code below to match the suggestions and it works correctly now.
I've seen several stack overflow questions similar to this one, but I haven't quite been able to put it all together. I have the following xaml code.
<UserControl x:Class="AuditEfficiencyMVVM.View.AuditTestsMain"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AuditEfficiencyMVVM.View"
xmlns:viewmodel="clr-namespace:AuditEfficiencyMVVM.ViewModel"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="1000">
<UserControl.DataContext>
<viewmodel:AuditTests/>
</UserControl.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<ListView Grid.Row="1" Grid.Column="0" Margin="10" ItemsSource="{Binding Path=Tests}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="TestSelected" IsChecked="{Binding Path=Selected, Mode=TwoWay}" Command="{Binding Path=TestSelected, RelativeSource={RelativeSource AncestorType=ListView}}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Test Type" DisplayMemberBinding="{Binding Type, Mode=OneWay}"/>
<GridViewColumn Header="Progress">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ProgressBar Name="TestProgress" Width="50" Height="20" Value="{Binding Progress, Mode=OneWay}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Status" DisplayMemberBinding="{Binding Status, Mode=OneWay}"/>
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="True">
<Expander.Header>
<TextBlock FontWeight="Bold" FontSize="14" Text="{Binding Name}"/>
</Expander.Header>
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
<ListView Grid.Row="1" Grid.Column="1" Margin="10" ItemsSource="{Binding Path=Files}">
<ListView.View>
<GridView>
<GridViewColumn Header="File Type" DisplayMemberBinding="{Binding Type, Mode=OneWay}"/>
<GridViewColumn Header="File Location" Width="250">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Location, Mode=TwoWay}" Width="225"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Width="30" Height="20">...</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<Button Grid.Row="2" Grid.Column="1" HorizontalAlignment="Right" Margin="10" Width="50" Height="30">Run</Button>
</Grid>
</UserControl>
Here is my code behind
public class AuditTests : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private RelayCommand _testSelected;
private void AddTest()
{
MessageBox.Show("Success");
}
public RelayCommand TestSelected
{
get
{
return _testSelected;
}
private set
{
if (_testSelected != value)
{
_testSelected = value;
RaisePropertyChanged("TestSelected");
}
}
}
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public AuditTests()
{
TestSelected = new RelayCommand(AddTest);
}
public ObservableCollection<Model.File> Files
{
get;
set;
}
public ObservableCollection<Model.Test> Tests
{
get;
set;
}
public void LoadFiles()
{
ObservableCollection<Model.File> files = new ObservableCollection<Model.File>();
foreach (Model.Test test in Tests)
{
foreach (Enums.FileType type in test.ExpectedSources)
{
Boolean containsType = false;
foreach (Model.File file in files)
{
if (file.Type == type)
{
containsType = true;
break;
}
}
if (!containsType)
{
files.Add(new Model.File { Type = type, Location = "", Tests = new List<Enums.TestType> { test.Type } });
}
else
{
files.Where(t => t.Type == type).First().Tests.Add(test.Type);
}
}
}
Files = files;
}
public void LoadTests()
{
ObservableCollection<Model.Test> tests = new ObservableCollection<Model.Test>();
foreach (var prop in Enum.GetValues(typeof(Enums.TestType)).Cast<Enums.TestType>().ToList())
{
tests.Add(new Model.Test { Category = prop.GetCategory(), Type = prop, Progress = 0, Selected = true, Status = Enums.TestStatus.NotStarted, ExpectedSources = prop.GetExpectedFiles() });
}
Tests = tests;
}
}
}
From what I've read this seems like it should work, but when I check/uncheck the check box the message box is not activated. What am I missing here to get the check/uncheck command to work?
AuditTestsclass with theAuditTestsMainUserControl?AuditTests. Would that be a DataContext thing?AuditTestswants to be a viewmodel. It should implementINotifyPropertyChanged, and when you use your UserControl, it should have an instance ofAuditTestsfor its DataContext. This is in addition to what ASh points out below.DataContext = "{}"in the<UserControl>, but I'm not sure how to specify the file.AuditTestsMain.xamlis in View/ whileAuditTests.csis in ViewModel/AuditTests. It doesn't matter what folders the classes are defined in. How are you usingAuditTestsMain? Do you just want to toss an instance of it in anywhere and have it do its thing? Or does some other viewmodel own a copy ofAuditTests, and it wants to display that in its own view?