Execute Method from Codehind using ViewModel WPF
Asked Answered
D

2

3

I've abandoned the MVVM midway through app development just to get this app out.

I've written a method in the code behind to update the database/datagrid etc.

My application navigation is using Commands to the ViewModel firing some event but never touches the code-behind except one time to initialize the class.

So basically I push the button one time and it works with the default initial setting but I can't call my code-behind Update() method anymore once the view as been intialized.

How can I call this code-behind method from the view model?

Thanks!!

Update code

 //Navigation ViewModel
//PaneVm.cs

public CommandExtension NewAssignmentCommand { get; set; }
    private void CreateCommands()
    {
        NewAssignmentCommand = new CommandExtension(NewAssignment, CanNewAssignment);
}
GlobalCommands.NewAssignmentCommand = NewAssignmentCommand;

private bool CanNewGroupAssignment(object obj)
    {
        return true;
    }

    private void NewGroupAssignment(object obj)
    {
        OnPropertyChanged("NewGroupAssignmentCommand");
    }


//MainVM.cs
// [Events]
    void _PaneVm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "NewGroupAssignmentCommand")
            WorkspaceVm.CurrentVm = new NewAssignmentsVm();
}


//NewAssignmentVm.cs
//Constructor
    public NewAssignmentsVm()
    {
        var rc = new RepositoryContext();

        _RoResearchers = new ObservableCollection<Researcher>(rc.ResearcherData.GetAllResearchers());

        _QuarterDateTime = DateTime.Now;

        CreateCommands();
    }

//NewAssignment.cs
//Code-behind
//The method
private void UpdateGrid()
    {
        report_datagrid.ItemsSource = null;

        using (var rc = new RepositoryContext())
        {
            if (quarter_datepicker.SelectedDate != null)
            {
                if (!String.IsNullOrEmpty(reportType))
                    researchers = rc.ResearcherData.GetResearchersWeeksByQuarter(Convert.ToDateTime(quarter_datepicker.SelectedDate), reportType).ToList();

            }
        }
    }

UPDATE 2:

I solved my problem based off this answer. I created a Global Action

 public static class GlobalCommands 
 { 
 public static Action UpdateGrid { get; set; } 
 } 

Then in my code-behind constructor I set the value public

   MyCodeBehind() 
   { 
       GlobalCommands.UpdateGrid = new Action(() => this.UpdateGrid()); 
   } 

Didn't need to bind to the context again. Everything else was the same. Thank you

Donley answered 6/3, 2014 at 16:7 Comment(9)
LMAO.. c'mon give me a break it's just one methodDonley
it doesn't really matter if it's one method or a single line of code. Database access code does not belong into the UI. BTW, even if I wanted to answer your question without telling you to delete all that horrible code behind, I couldn't because you have not posted any code and I have no idea what you really expect as an answer.Musca
It's VM logic, not just 'one method'. In other words, you're trying to abandon the entire concept of your original design midway (or further) through. If you are willing to back track through your code a ways and undo the MVVM construction, you can eventually tie your View to your VM closely enough to execute that method. Otherwise, there is no easy solution I think.Debra
I knew I was going to get flamed for this. Here's what made me quick MVVM.. I had a datagrid, it updated based on a value from a datetime picker. I couldn't get the thing to default display data by setting the datetimepicker from the view model. For some reason it required me to manually select a date.. Yes I tired the events to no avail.Donley
Sorry not meaning to flame or anything. Your original problem actually sounds quite interesting. Would you be able to post the code?Debra
Could you write what you're trying to do in the MVVM style and that you do not work?Towhaired
I updated the question with some code.. there's lots of moving parts. I basically provided snippets of each Class that's involved.Donley
I dont know if this is going to help. Were you trying to set a default view of your datagrid? You can use InvokeCommandAction for the container in xaml and bind it to some command in the viewmodel to load the default data without any action in the view. You can use <i:Interaction.Triggers> <i:EventTrigger EventName="Loaded"> <i:InvokeCommandAction Command="{Binding LoadedCommand}" /> </i:EventTrigger> </i:Interaction.Triggers>Ardellardella
Krishna I wish I could plus one your comment.. thanks!!Donley
E
5

Main idea is:

class MyCodeBehind
{
   public MyCodeBehind()
   {
      Action action = new Action(()=> this.SomeMethodIWantToCall());
      var myVM = new MyVM(action); // This is your ViewModel
      this.DataContext = myVM;
   }

   private void SomeMethodIWantToCall(){...}
}

class MyVM
{
    private Action action;

    public MyVM(Action someAction)
    {
       this.action = someAction;
    }

    private void SomeMethodInVM()
    {
        this.action(); // Calls the method SomeMethodIWantToCall() in your code behind
    }
}
Eboat answered 6/3, 2014 at 17:26 Comment(0)
P
1

Instead of letting code-behind know about viewmodel, You can make use of NotifyOnSourceUpdated in your xaml binding.

Something like this:

<TextBlock Grid.Row="1" Grid.Column="1" Name="RentText"
  Text="{Binding Path=Rent, Mode=OneWay, NotifyOnTargetUpdated=True}"
  TargetUpdated="OnTargetUpdated"/>

Here, 'OnTargetUpdated' is a handler in your code behind. This handler will be invoked when "Rent" property of ViewModel is changed.

Details at MSDN

Peptidase answered 6/3, 2014 at 18:13 Comment(2)
Manish, this notified only once when the binding target (target) or the binding source (source) property of a binding has been updated. It might not work if we Bind collection and wanted to invoke every time when the collection is changed(added/updated/deleted). Is there anything similar to this to achieve that?Marengo
Nothing of the shelf. I would rather consider having the logic at viewmodel side for your scenario.Peptidase

© 2022 - 2024 — McMap. All rights reserved.