如何在MVVM模式下为AdaptiveGridView绑定命令至UserPhotosViewModel
Got it, let's tackle this problem. You've got your Master/DetailsView working with folders and images, but trying to bind commands or SelectedItem for the AdaptiveGridView directly from your UserPhotosViewModel feels blocked because VS is suggesting you add code to AppFolder—which makes no sense, since those actions belong to the parent view model, not the folder model.
Here are two straightforward ways to fix this, both letting you bind directly to your UserPhotosViewModel without polluting your model classes:
1. Use RelativeSource to Target the Parent ViewModel
The AdaptiveGridView is inside the DetailsTemplate of the MasterDetailsView, so its immediate DataContext is an AppFolder instance. But we can walk up the visual tree to get the MasterDetailsView's DataContext (which is your UserPhotosViewModel).
Update your XAML for the AdaptiveGridView like this:
<controls:AdaptiveGridView ItemsSource="{Binding AppImages}" OneRowModeEnabled="False" ItemHeight="205" DesiredWidth="205" SelectionMode="Multiple" Margin="0 6 0 0" <!-- Bind SelectedItem to the parent VM's property --> SelectedItem="{Binding DataContext.SelectedImage, RelativeSource={RelativeSource AncestorType={x:Type controls:MasterDetailsView}}}" <!-- Bind a command for selection changes --> SelectionChangedCommand="{Binding DataContext.ImageSelectionChangedCommand, RelativeSource={RelativeSource AncestorType={x:Type controls:MasterDetailsView}}}" >
Then add the corresponding property and command to your UserPhotosViewModel:
// Add a property for the selected image private AppImage _selectedImage; public AppImage SelectedImage { get => _selectedImage; set { _selectedImage = value; RaisePropertyChanged(nameof(SelectedImage)); } } // Add a command for selection changes public ICommand ImageSelectionChangedCommand { get; } // Initialize the command in your constructor public UserPhotosViewModel(IDataService dataService, INavigationService navigationService) { this.dataService = dataService; this.navigationService = navigationService; // Use a RelayCommand (from MVVM Light, or your own implementation) ImageSelectionChangedCommand = new RelayCommand(HandleImageSelectionChanged); Initialize(); } // The method that runs when selection changes private void HandleImageSelectionChanged(object parameter) { // Get the selection event args to access all selected items if needed var args = parameter as SelectionChangedEventArgs; if (args != null) { var selectedItems = args.AddedItems.Cast<AppImage>(); // Do your logic here—e.g., track selected images, trigger an action, etc. } }
If you don't have a RelayCommand implementation, here's a simple one you can add to your project:
public class RelayCommand : ICommand { private readonly Action<object> _execute; private readonly Func<object, bool> _canExecute; public event EventHandler CanExecuteChanged; public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } public void RaiseCanExecuteChanged() { CanExecuteChanged?.Invoke(this, EventArgs.Empty); } }
2. Use ElementName Binding (Alternative)
If you give your MasterDetailsView a name, you can reference it directly in the binding instead of using RelativeSource:
First, add a name to your MasterDetailsView:
<controls:MasterDetailsView x:Name="PhotoMasterDetails" ItemsSource="{Binding FolderList}"> <!-- Rest of your template code --> </controls:MasterDetailsView>
Then update the AdaptiveGridView bindings:
<controls:AdaptiveGridView ItemsSource="{Binding AppImages}" <!-- ... other properties ... --> SelectedItem="{Binding DataContext.SelectedImage, ElementName=PhotoMasterDetails}" SelectionChangedCommand="{Binding DataContext.ImageSelectionChangedCommand, ElementName=PhotoMasterDetails}" >
This works the same way as the RelativeSource method—you just reference the named control to get its DataContext (your UserPhotosViewModel).
Key Notes
- For multiple selection, since
SelectedItemsis a read-only collection, you can't bind directly to it. Instead, use theSelectionChangedCommand's parameter (theSelectionChangedEventArgs) to accessAddedItemsandRemovedItemslike we did in theHandleImageSelectionChangedmethod. - Double-check that your
MasterDetailsView'sDataContextis indeed set to yourUserPhotosViewModel(this should already be the case since your folders are displaying correctly). - Avoid adding view-related logic (commands, selection properties) to your
AppFoldermodel—those belong in the view model, which is exactly what these methods let you do.
内容的提问来源于stack exchange,提问作者Stanislav Zinoviev

