Home > Net >  How to define implementation of event to viewmodel?
How to define implementation of event to viewmodel?

Time:09-22

I want to centralized all bussiness logic into viewmodel. but i have problem with implemetation event. so i think i create delegate in code behind for reference. and the implementation in view model by pass view object to view model. how to do this?

<UserControl x:Class="Project.Views.IndexView">
    <PasswordBox PasswordChanged="PasswordChangedHandler"/>
</UserControl>

C#

public partial class IndexView
{
    public IndexView()
    {
        InitializeComponent();
        DataContext = new IndexViewModel(this);
    }
    
    private delegate void PasswordChangedHandler(object sender, RoutedEventArgs args);
}

public class IndexViewModel
{
    public IndexViewModel(UserControl view)
    {
        view.PasswordChangedHandler = this.PasswordChangedHandler;
    }
    
    public string Password { get; set; }

    private void PasswordChangedHandler(object sender, RoutedEventArgs args)
    {
        var passwordBox = (PasswordBox)sender;
        Password = passwordBox.Password;
    }
}

CodePudding user response:

If you want to stay out of code behind you are going to have to look into implementing EventToCommand: Support in Framework, and Core as long as you reference Windows.Interactivity.WPF Nuget

Bind command to Loaded event of view

MVVM Light: Adding EventToCommand in XAML without Blend, easier way or snippet?

https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/may/mvvm-commands-relaycommands-and-eventtocommand

CodePudding user response:

You are making IndexViewModel aware of IndexView, this is wrong, you have to make the viewmodel unaware of the view..

In your view, do not pass the view to the viewmodel, and handle the event in there..

public partial class IndexView
{
    public IndexView()
    {
        InitializeComponent();
        DataContext = new IndexViewModel();
    }
    
    private void PasswordChangedHandler(object sender, RoutedEventArgs e)
    {
        var pwBox = sender as PasswordBox;
        (this.DataContext as IndexViewModel)?.PasswordChangedHandler(pwBox?.Password);
    }
}

In viewmodel, make a defual constructor, and handle the logic of password change by passing just the password string

public IndexViewModel()
{
}

public string Password { get; set; }

public void PasswordChangedHandler(string password)
{
    Password = password;
    // do something
}

CodePudding user response:

"I want to centralized all bussiness logic into viewmodel." - Business logic belongs to the Model (but I guess you know this).

"by pass view object to view model. how to do this?" - You should never pass an object of the View to the View Model.

If your real problem is "How to pass the password to the view model", then you should know that you need to pass it explicitly. This is how the control is designed to be used.

The reason for this is, that the password is a very critical information. Passing the password around the application always introduces a privacy or security issue. Strings are stored in the memory as their simple byte representation/plaintext. The memory is public. This means, everybody can read a string from the memory. That's why the PasswordBox exposes the password as SecureString.

The general recommendation is to avoid this classic authentication system where the user enters a plaintext password. The recommendation is to use existing authentication flows.

For example, you can use Windows authentication. By storing application data in the user domain, you can be sure that only the user that is currently logged in is using your application: Windows authentication ensures that a user of a instance-per-user desktop application is properly authenticated.

Alternatively, use OAuth authentication.
Modern web applications ask the user to login with their Google or Facebook account etc. Those authentication flows are very secure. The password handling is completely external as it is delegated to a 3rd party service (on behalf of the user that must have a related account). This service will maintain the implemented authentication procedure to keep it secure up to the latest security standards.

Although I highly recommend against implementing a custom authentication flow, the following example is meant to show you how PasswordBox is intended to be used:

MainWindow.xaml

<Window>
  <PasswordBox PasswordChanged="OnPasswordChanged" />
<Window>

MainWindow.xaml.cs

partial class MainWindow : Window
{
  private ViewModel { get; set; }
  public MainWindow()
  {
    InitializeComponent();

    this.ViewModel = new ViewModel();
    this.DataContext = this.ViewModel;
  }

  private void OnPasswordChanged(object sender, RoutedEventArgs args)
  {
    var passwordBox = sender as PasswordBox;
    this.ViewModel.HandlePassword(passwordBoc.SecurePassword);
  }
}

The general practice is to ensure that the desktop application is installed as instance-per-user (so that we can rely on the OS authentication system) or to use a OAuth service. OAuth is very popular for web applications where an URL can be visited from any system (which declares local OS level authentication as meaningless).

  • Related