简体   繁体   中英

Changing View Wpf MVVM

I'm beginner in WPF and MVVM, but want to learn it by building some small project.
I've got a WPF app using the Model-View-ViewModel pattern, based on Rachel Lim example. In my app I have 2 views - EmployeesList and EmployeeDetails. List of employees is storage in GidView.

The main problem I have is

  • How to change view when I double-click on a row,
  • How to get the value from the first column (employee_id) and pass it into EmployeeDetails view.

Base navigation is in xaml with DataTmplate and ItmCntrol:

<Window.Resources>
    <DataTemplate DataType="{x:Type local:HomeViewModel}">
        <local:HomeView />
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:EmployeesListViewModel}">
        <local:EmployeesListView />
    </DataTemplate>
</Window.Resources>



<ItemsControl ItemsSource="{Binding PageViewModels}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Content="{Binding Name}"
                    Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                    CommandParameter="{Binding }"
                    Margin="2,5"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

also I've got ApplicationViewModel where is list of views

public class ApplicationViewModel : ObservableObject
{
    #region Fields

    private ICommand _changePageCommand;

    private IPageViewModel _currentPageViewModel;
    private List<IPageViewModel> _pageViewModels;

    #endregion

    public ApplicationViewModel()
    {
        // Add available pages
        PageViewModels.Add(new HomeViewModel());
        PageViewModels.Add(new EmployeesListViewModel());
        PageViewModels.Add(new EmployeeDetailsViewModel());

        // Set starting page
        CurrentPageViewModel = PageViewModels[0];
    }

    #region Properties / Commands

    public ICommand ChangePageCommand
    {
        get
        {
            if (_changePageCommand == null)
            {
                _changePageCommand = new RelayCommand(
                    p => ChangeViewModel((IPageViewModel)p),
                    p => p is IPageViewModel);
            }

            return _changePageCommand;
        }
    }

    public List<IPageViewModel> PageViewModels
    {
        get
        {
            if (_pageViewModels == null)
                _pageViewModels = new List<IPageViewModel>();

            return _pageViewModels;
        }
    }

    public IPageViewModel CurrentPageViewModel
    {
        get
        {
            return _currentPageViewModel;
        }
        set
        {
            if (_currentPageViewModel != value)
            {
                _currentPageViewModel = value;
                OnPropertyChanged("CurrentPageViewModel");
            }
        }
    }

    #endregion

    #region Methods

    private void ChangeViewModel(IPageViewModel viewModel)
    {
        if (!PageViewModels.Contains(viewModel))
            PageViewModels.Add(viewModel);

        CurrentPageViewModel = PageViewModels
        .FirstOrDefault(vm => vm == viewModel);
    }

    #endregion
}

How to change view when I double-click on a row

First, you need to add EventTrigger for MouseDoubleClick event:

    <DataGrid Name="gridEmployees" ItemsSource="{Binding Employees}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseDoubleClick">
                <local:CustomCommandAction Command="{Binding DoubleClickCommand}" CommandParameter="{Binding ElementName=gridEmployees, Path=SelectedItems[0]}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </DataGrid>

CustomCommandAction is a class, that inherits from TriggerAction and is used as a link between event and command in your View Model. Here is the code:

public sealed class CustomCommandAction : TriggerAction<DependencyObject>
{
    public static readonly DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), typeof(CustomCommandAction), null);

    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
        "Command", typeof(ICommand), typeof(CustomCommandAction), null);

    public ICommand Command
    {
        get
        {
            return (ICommand)this.GetValue(CommandProperty);
        }
        set
        {
            this.SetValue(CommandProperty, value);
        }
    }

    public object CommandParameter
    {
        get
        {
            return this.GetValue(CommandParameterProperty);
        }

        set
        {
            this.SetValue(CommandParameterProperty, value);
        }
    }

    protected override void Invoke(object parameter)
    {
        if (this.AssociatedObject != null)
        {
            ICommand command = this.Command;
            if (command != null)
            {
                if (this.CommandParameter != null)
                {
                    if (command.CanExecute(this.CommandParameter))
                    {
                        command.Execute(this.CommandParameter);
                    }
                }
                else
                {
                    if (command.CanExecute(parameter))
                    {
                        command.Execute(parameter);
                    }
                }
            }
        }
    }
}

After that the easiest solution is to use ChangeViewModel method in yours command Execute method, eg:

...

_doubleClickCommand = new RelayCommand(OnDoubleClick);
...

    private RelayCommand _doubleClickCommand = null;
    private ApplicationViewModel _applicationViewModel;

    private void OnDoubleClick(object obj)
    {
        EmployeeDetailsViewModel selectedModel = obj as  EmployeeDetailsViewModel;

        _applicationViewModel.ChangeViewModel(selectedModel);
    }

    public ICommand DoubleClickCommand
    {
        get
        {
            return _doubleClickCommand;
        }
    }

How to get the value from the first column (employee_id) and pass it into EmployeeDetails view

For your DataGrid you may use collection of EmployeeDetailsViewModel as ItemsSource. If you do so, selected item will be passed to your command Execute method as an instance of EmployeeDetailsViewModel, and you'll be able to get Id from there.

It looks like you're missing a needed element to show the selected view. If you look at the linked sample note the ItemsControl is contained within a Border which is in turn inside a DockPanel .

Below the DockPanel there is a ContentControl which is a key element needed to show the selected view.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM