in my CustomerListViewModel i definded a 'delegate' event that needs to call a method in my mainViewModel and pass the GUID of my Customer to the method defined in this vm. only the delegate is not working correctly and the event is never passed to my mainViewModel :(
public partial class CustomerListViewModel : ObservableObject
{
public CustomerListViewModel()
{
customerCollection = new ObservableCollection<Customer>();
Customer jacob = new Customer("Jacob", "Woord", "NederLand");
Customer Maria = new Customer("Maria", "Woord", "Nederland");
customerCollection.Add(jacob);
customerCollection.Add(Maria);
}
public event Action<Guid> PlaceOrderRequested = delegate { };
[RelayCommand]
void PlaceOrder(Customer obj)
{
PlaceOrderRequested(obj.CustomerId);
}
[ObservableProperty]
ObservableCollection<Customer> customerCollection;
// Can Execute Example (if there no item selected in the list the button get disbled
public bool canDelete => selectedCustomer != null;
[RelayCommand(CanExecute =nameof(canDelete))]
void Delete()
{
customerCollection.Remove(selectedCustomer);
}
//Notifys the change for the selected Customer
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(DeleteCommand))]
Customer selectedCustomer;
[RelayCommand]
void DeleteAll()
{
customerCollection.Clear();
}
namespace viewModelBinding
{
public partial class MainWIndowViewModel : ObservableObject
{
//intialize every vieModel
private CustomerListViewModel customerListViewModel = new CustomerListViewModel();
private MaterialListViewModel materialListViewModel = new MaterialListViewModel();
private OrderListViewModel orderListViewModel = new OrderListViewModel();
private OrderPrepViewModel orderPrepViewModel = new OrderPrepViewModel();
private Timer timer = new Timer(5000);
public MainWIndowViewModel()
{
customerListViewModel.PlaceOrderRequested = CustomerListViewModel_PlaceOrderRequested;
currentViewModel = new OrderListViewModel();
timer.Elapsed = (s, e) => NotificationMessage = "Na 5 seconden word de huidige tijd neergzet: " DateTime.Now.ToLocalTime() " Kukulukuu";
timer.Start();
}
private void CustomerListViewModel_PlaceOrderRequested(Guid obj)
{
orderListViewModel.CustomerId = obj;
currentViewModel = orderListViewModel;
}
[ObservableProperty]
object currentViewModel;
[ObservableProperty]
string notificationMessage;
//switch statement with a parameter that gets a command parameter from the button as a string
[RelayCommand]
void OnNav(string destination)
{
switch (destination)
{
case "orders":
CurrentViewModel = orderListViewModel;
break;
case "customers":
CurrentViewModel = customerListViewModel;
break;
default:
CurrentViewModel = materialListViewModel;
break;
}
}
}
}
And below my vie where i defined the binding
<UserControl x:Class="viewModelBinding.Customers.CustomerListView"
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:viewModelBinding.Customers"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.InputBindings>
<KeyBinding Key="D" Modifiers="Control" Command="{Binding DeleteCommand}"/>
</UserControl.InputBindings>
<UserControl.Resources>
<DataTemplate x:Key="CustomerListTemplate">
<Border BorderThickness="2"
BorderBrush="red">
<StackPanel>
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text="{Binding LastName}"/>
<TextBlock Text="{Binding CityCustomer}"/>
</StackPanel>
</Border>
</DataTemplate>
</UserControl.Resources>
<UserControl.DataContext>
<local:CustomerListViewModel/>
</UserControl.DataContext>
<!--<b:Interaction.Triggers>
<b:EventTrigger EventName="">
<b:CallMethodAction TargetObject="{Binding}" MethodName="{Binding DeleteAllCommand}"/>
</b:EventTrigger>
</b:Interaction.Triggers>-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0"
Content="Delete"
HorizontalAlignment="Left"
Width="75"
Command="{Binding DeleteCommand}"/>
<Button Grid.Row="0"
Content="empty"
HorizontalAlignment="Right"
Width="75"
/>
<DataGrid ItemsSource="{Binding CustomerCollection}"
Grid.Row="1"
x:Name="CustomerList"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn x:Name="nameColumn"
Binding="{Binding FirstName}"
Width="*"/>
<DataGridTemplateColumn Width="auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!--with this command we grap the dataContext of the right customer to look at the anchestor (DataGrid)-->
<Button Content="Place Order"
Command="{Binding DataContext.PlaceOrderCommand,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}"
Margin="5"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding CustomerId}" Width="auto">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<ListBox SelectedItem="{Binding SelectedCustomer}"
ItemsSource="{Binding CustomerCollection}"
Grid.Row="2" ItemTemplate="{StaticResource CustomerListTemplate}"/>
</Grid>
</UserControl>
CodePudding user response:
Your problem is because you have two instances of CustomerListViewModel
This is one instance. ( Remove it.)
<UserControl.DataContext>
<local:CustomerListViewModel/>
</UserControl.DataContext>
This is another.
private CustomerListViewModel customerListViewModel = new CustomerListViewModel();
But the delegate approach is a bad idea.
I recommend messenger instead of a delegate.
Rather than pass a hard reference you could keep the two viewmodels decoupled.
https://learn.microsoft.com/en-us/windows/communitytoolkit/mvvm/messenger
// Create a message
public class LoggedInUserChangedMessage : ValueChangedMessage
{
public LoggedInUserChangedMessage(User user) : base(user)
{
}
}
// Register a message in some module
WeakReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this,
(r, m) =>
{
// Handle the message here, with r being the recipient and m being the
// input message. Using the recipient passed as input makes it so that
// the lambda expression doesn't capture "this", improving performance.
});
// Send a message from some other module
WeakReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));
Obviously, here you want to pass a guid in the object you send. You could elsewhere pass a type or even an entire viewmodel for navigation purposes.
It seems odd that you're passing a guid back to mainwindowviewmodel.
I would have thought there'd be views for orders and new order. New order would let you pick a customer so would have some sub view where you look a customer up. The command to pick a customer would be in new order viewmodel and bound from customer view so the command passed customer id.
Maybe this is just purely experimental code though.