пожалуйста, попробуйте следующее решение:
Xaml (основано на селекторе шаблонов данных)
<Window x:Class="MvvmNavigationIssue.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mvvmNavigationIssue="clr-namespace:MvvmNavigationIssue"
Title="MainWindow" Height="350" Width="525" x:Name="This">
<Window.DataContext>
<mvvmNavigationIssue:MainNavigationViewModel/>
</Window.DataContext>
<Window.Resources>
<mvvmNavigationIssue:FreezableProxyClass x:Key="ProxyElement"
ProxiedDataContext="{Binding Source={x:Reference This}, Path=DataContext}"/>
<DataTemplate x:Key="DefaultDataTemplate">
<Grid>
<Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Tomato" />
<TextBlock Text="Default Template" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</DataTemplate>
<DataTemplate x:Key="JobsDataTemplate">
<ListView ItemsSource="{Binding JobModels, UpdateSourceTrigger=PropertyChanged}">
<ListView.View>
<GridView>
<GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="mvvmNavigationIssue:JobModel">
<TextBlock Text="{Binding Id}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
<GridViewColumn Header="Salary" DisplayMemberBinding="{Binding Salary, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
<GridViewColumn Header="" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="mvvmNavigationIssue:JobModel">
<Button Command="{Binding Source={StaticResource ProxyElement},
Path=ProxiedDataContext.ShowLogsCommand, Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding }">Logs</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
<DataTemplate x:Key="LogsDataTemplate">
<ListView ItemsSource="{Binding LogModels, UpdateSourceTrigger=PropertyChanged}">
<ListView.View>
<GridView>
<GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="mvvmNavigationIssue:JobModel">
<TextBlock Text="{Binding Id}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
<GridViewColumn Header="Time" DisplayMemberBinding="{Binding LogTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
<GridViewColumn Header="Event" DisplayMemberBinding="{Binding LogEvent, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
<GridViewColumn Header="" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="mvvmNavigationIssue:JobModel">
<Button Command="{Binding Source={StaticResource ProxyElement},
Path=ProxiedDataContext.ShowAllJobsCommand, Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}">All Jobs</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
<mvvmNavigationIssue:MainContentTemplateSelector x:Key="MainContentTemplateSelectorKey"
DefaultDataTemplate="{StaticResource DefaultDataTemplate}"
JobsViewDataTemplate="{StaticResource JobsDataTemplate}"
LogsViewDataTemplate="{StaticResource LogsDataTemplate}"/>
</Window.Resources>
<Grid>
<ContentControl Content="{Binding CurrentViewModel, UpdateSourceTrigger=PropertyChanged}"
ContentTemplateSelector="{StaticResource MainContentTemplateSelectorKey}"></ContentControl>
</Grid>
MVVM код
public class FreezableProxyClass : Freezable
{
protected override Freezable CreateInstanceCore()
{
return new FreezableProxyClass();
}
public static readonly DependencyProperty ProxiedDataContextProperty = DependencyProperty.Register(
"ProxiedDataContext", typeof(object), typeof(FreezableProxyClass), new PropertyMetadata(default(object)));
public object ProxiedDataContext
{
get { return (object)GetValue(ProxiedDataContextProperty); }
set { SetValue(ProxiedDataContextProperty, value); }
}
}
public class MainNavigationViewModel : BaseObservableObject
{
private object _currentViewModel;
private JobsViewModel _jobsViewModel;
private List<LogModel> _logModels;
private ICommand _showLogs;
private ICommand _showJobs;
public MainNavigationViewModel()
{
_jobsViewModel = new JobsViewModel();
Init();
}
private void Init()
{
_jobsViewModel.JobModels = new ObservableCollection<JobModel>
{
new JobModel{Id = 1, Salary = "12k", Title = "Hw Engineer"},
new JobModel{Id=2, Salary = "18k", Title = "Sw Engineer"},
new JobModel{Id = 3, Salary = "12k", Title = "IT Engineer"},
new JobModel{Id=4, Salary = "18k", Title = "QA Engineer"},
};
_logModels = new List<LogModel>
{
new LogModel{Id = 1, Salary = "12k", Title = "Hw Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Pending"},
new LogModel{Id = 1, Salary = "12k", Title = "Hw Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Active"},
new LogModel{Id = 1, Salary = "12k", Title = "Hw Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Closed"},
new LogModel{Id=2, Salary = "12k", Title = "Sw Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Pending"},
new LogModel{Id=2, Salary = "12k", Title = "Sw Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Active"},
new LogModel{Id=2, Salary = "12k", Title = "Sw Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Closed"},
new LogModel{Id = 3, Salary = "12k", Title = "IT Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Pending"},
new LogModel{Id = 3, Salary = "12k", Title = "IT Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Active"},
new LogModel{Id = 3, Salary = "12k", Title = "IT Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Closed"},
new LogModel{Id=4, Salary = "12k", Title = "QA Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Pending"},
new LogModel{Id=4, Salary = "12k", Title = "QA Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Active"},
new LogModel{Id=4, Salary = "12k", Title = "QA Engineer", LogTime = DateTime.Now.ToLocalTime(), LogEvent = "Closed"},
};
CurrentViewModel = _jobsViewModel;
}
public object CurrentViewModel
{
get { return _currentViewModel; }
set
{
_currentViewModel = value;
OnPropertyChanged(()=>CurrentViewModel);
}
}
public ICommand ShowLogsCommand
{
get { return _showLogs ?? (_showLogs = new RelayCommand<JobModel>(ShowLogs)); }
}
private void ShowLogs(JobModel obj)
{
CurrentViewModel = new LogsViewModel
{
LogModels = new ObservableCollection<LogModel>(_logModels.Where(model => model.Id == obj.Id)),
};
}
public ICommand ShowAllJobsCommand
{
get { return _showJobs ?? (_showJobs = new RelayCommand(ShowAllJobs)); }
}
private void ShowAllJobs()
{
CurrentViewModel = _jobsViewModel;
}
}
public class LogsViewModel:BaseObservableObject
{
private ObservableCollection<LogModel> _logModels;
public ObservableCollection<LogModel> LogModels
{
get { return _logModels; }
set
{
_logModels = value;
OnPropertyChanged();
}
}
}
public class LogModel : JobModel
{
private DateTime _logTime;
private string _logEvent;
public DateTime LogTime
{
get { return _logTime; }
set
{
_logTime = value;
OnPropertyChanged();
}
}
public string LogEvent
{
get { return _logEvent; }
set
{
_logEvent = value;
OnPropertyChanged();
}
}
}
public class JobsViewModel:BaseObservableObject
{
private ObservableCollection<JobModel> _jobModels;
public ObservableCollection<JobModel> JobModels
{
get { return _jobModels; }
set
{
_jobModels = value;
OnPropertyChanged();
}
}
}
public class JobModel:BaseObservableObject
{
private int _id;
private string _title;
private string _salary;
public int Id
{
get { return _id; }
set
{
_id = value;
OnPropertyChanged();
}
}
public string Title
{
get { return _title; }
set
{
_title = value;
OnPropertyChanged();
}
}
public string Salary
{
get { return _salary; }
set
{
_salary = value;
OnPropertyChanged();
}
}
}
реализация INPC и код команды реле
/// <summary>
/// implements the INotifyPropertyChanged (.net 4.5)
/// </summary>
public class BaseObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
}
public class RelayCommand : ICommand
{
private readonly Func<bool> _canExecute;
private readonly Action _execute;
public RelayCommand(Action execute)
: this(() => true, execute)
{
}
public RelayCommand(Func<bool> canExecute, Action execute)
{
_canExecute = canExecute;
_execute = execute;
}
public bool CanExecute(object parameter = null)
{
return _canExecute();
}
public void Execute(object parameter = null)
{
_execute();
}
public event EventHandler CanExecuteChanged;
}
public class RelayCommand<T> : ICommand
where T:class
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public RelayCommand(Action<T> execute):this(obj => true, execute)
{
}
public RelayCommand(Predicate<T> canExecute, Action<T> execute)
{
_canExecute = canExecute;
_execute = execute;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter as T);
}
public void Execute(object parameter)
{
_execute(parameter as T);
}
public event EventHandler CanExecuteChanged;
}
Малый объяснение
- У нас есть три задания DataTemplate, журналы, по умолчанию.
- DataTemplateSelector будет управлять выбором шаблона данных на основе свойства Content ContentControl, к которому привязан DataTemplateSelector.
- Кнопка находится внутри сетки и привязана к команде из виртуальной машины родителя. Родительская виртуальная машина предоставляется в DataTemplate через объект Freezable proxie.
Дайте мне знать, если у вас есть проблемы с кодом.
С уважением.
есть ли ответ :( – Marzouk
попытаться спросить здесь https://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=wpf – StepUp
Вы ищете 'RowDetailTemplate' HTTP: //www.wpf-tutorial.com/datagrid-control/details-row/ – Eldho