Closed Grunzfort closed 8 years ago
@Grunzfort Hi, is DataContext
your MainViewModel
? How is your is your ActionCommand
implemented? I think it's necessary to give us more code. Thx
Oh sorry bruh, I'm calling from a different View and ViewModel.
Here's the MainWindow:
<controls:MetroWindow x:Class="SerialEncoder.Views.MainWindow"
dialog:DialogParticipation.Register="{Binding}"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance viewModels:MainViewModel}">
here's the code from the DataContext of the MainViewModel:
public MainViewModel(IDialogCoordinator dialogCoordinator)
{
DialogCoordinator = dialogCoordinator;
ShowMainMenu();
}
private async void OpenUserAccountDialog()
{
CustomDialog = new CustomDialog() { Content = new CreateUserDialog() };
await DialogCoordinator.ShowMetroDialogAsync(this, CustomDialog);
}
public async void CloseDialog()
{
await DialogCoordinator.HideMetroDialogAsync(this, CustomDialog);
}
//I can call this from the other usercontrols using the command in the XAML below
public ActionCommand ViewUserAccountCommand
{
get
{
return new ActionCommand(p => ShowUserAccountMenu());
}
}
//can't call this for some reason once the Dialog has been shown or any other commands from the MainViewModel
public ActionCommand CloseDialogCommand
{
get
{
return new ActionCommand(p => CloseDialog());
}
}
Here is where I call it (The UserControl View):
<UserControl x:Class="SerialEncoder.Views.UserAccountView">
<UserControl.Resources>
<viewModels:UserAccountViewModel x:Key="UserAccountViewModel"/>
</UserControl.Resources>
<Button Style="{StaticResource RedStyle}" Command="{Binding DataContext.ViewUserAccountDialogCommand, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type views:MainWindow}}}" Content="Add NEW USER" Grid.Row="1" FontSize="14" Height="Auto" Width="170" HorizontalAlignment="Left" Margin="30,0,0,0"/>
I don't really have a code for this View Model to close the Dialog as I was expecting to close it via the command inside the MainViewModel.
Here's my Action Command (It works though)
public class ActionCommand : BaseViewModel, ICommand
{
private readonly Action<object> _action;
private readonly Predicate<Object> _predicate;
public ActionCommand(Action<Object> action) : this(action, null)
{
}
public ActionCommand()
{
}
public ActionCommand(Action<object> action, Predicate<object> predicate)
{
if (action == null)
{
throw new ArgumentNullException("action", "You must specify an Action<T>.");
}
_action = action;
_predicate = predicate;
}
public bool CanExecute(object parameter)
{
if (_predicate == null)
{
return true;
}
return _predicate(parameter);
}
public void Execute(object parameter)
{
_action(parameter);
}
public void Execute()
{
Execute(null);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
Are there any other ways like closing the dialog via other ViewModel?
I'm going to add a picture in order to show what's going on.
If the dialog box is displayed in the AdornerLayer, then you might be running into the same issue that you can get with context menus in DataGrids. Basically, your visual tree in an adorner layer stops at the adorner layer and never gets to the ancestor type {x:Type views:MainWindow}.
To work around this issue, you'll have to have a proxy element defined in a higher context as described here: http://stackoverflow.com/questions/29361921/get-row-in-context-menu-command-parameter-mvvm
The issue is the fact that context menus, popups, adorners, etc. live in a completely different visual tree than the main window. You'll need to have a named reference that you can use and change your binding to:
{Binding DataContext.CloseDialogCommand, Mode=OneWay, ElementName=Proxy}
As an aside, you might want to do a Debug.WriteLine("CanExecuteCalled") in the ActionCommand to show just how often it will be queried when you tie in to the CommandManager.RequeryRequested callback. It's quite enlightening, and it was a source of performance problems for a very complex application we are developing. Having an explicit RaiseCanExecuteChanged() that can be called every time there is actually a change worthy of rechecking seemed to make things better for us. Although you actually have to have the same CommandObject in your getter for that to work.
In our code the equivalent would work like this:
public MainViewModel()
{
CloseDialogCommand = new ActionCommand(p => CloseDialog());
}
public ActionCommand CloseDialogCommand { get; private set; }
public void HandleSomeStateChangingEvent()
{
CloseDialogCommand.RaiseCanExecuteChanged();
}
There are far fewer events that actually change the state of when a command can execute than queries just because the mouse hovered over a focusable control.
@bloritsch dude, I've tried but sadly it ain't working, maybe because I have a different way on how to do it. Now, I accidentally saw a tutorial on how to do these stuff using a DialogService class instead of using a DialogCoordinator. It's working the only problem is to how can I display a CustomDialog. I'll research a bit more.
So I've got everything working now sorry to bother you guys. I saw @Amrykid's post on changing the UserControl to BaseMetroDialog and got everything working flawlessly.
Well, I've been following the mahapps metro demo application and I saw the Custom Dialog via MVVM and yeah, its working fine.
The above code works perfectly. Accessing the MainViewModel is no problem, I can do something like:
Then call it from my XAML:
Now the problem here is that for some unknown reason, the Command to close the dialog won't fire (which is the MainViewModel). Accessing the MainViewModel is working from UserControl to UserControl but now that it's been opened from the Dialog, I can't seem to fire the ActionCommand inside the MainViewModel that closes the Dialog using the same code from the above XAML. Are there other ways to call the fuction in the MainViewModel from the Other ViewModel? (I tried this but I failed, like trying to make this static or something)
I've been stuck here and searching the internet for days. I hope someone could help me out here, please.