ContentControl not updating
Asked Answered
T

3

6

I'm trying to have a MainWindow that is bound to the a view. I change that view in code and expect it to update in the Main Window, however that is not happening.

I have this code in my XAML

<Grid>
    <ContentControl Content="{Binding Source={StaticResource ViewModelLocator}, Path=MainWindowViewModel.CurrentControl}" />
</Grid>

I then change my Control via this code

public class MainWindowViewModel : ReactiveObject
{
    private UserControl _CurrentControl = null;
    public UserControl CurrentControl
    {
        get
        {
            if (_CurrentControl == null)
            {
                _CurrentControl = new HomePage();
            }
            return _CurrentControl;
        }
        set
        {
            this.RaiseAndSetIfChanged(x => x.CurrentControl, value);
        }
    }
}

As you can see I'm using the ReactiveUI library.

Is ContentControl the wrong thing to use in that view or am I just not binding and updating correctly?

Trieste answered 12/3, 2013 at 4:46 Comment(8)
You most certainly can databind to the Content property. Look for binding errors.Cuthbert
The current binding is correct as it shows the first view, it just doesn't update to a new view.Trieste
does RaiseAndSetIfChanged implement INotifyPropertyCHanged? If not then I would add it so that the UI is made aware of the changesTorn
@JKing I believe it does, it's from the ReactiveUI libraryTrieste
I don't know that library, do you have access to its source code to confirm. Other wise you could implement it yourself in the CurrentControl setter and see if it solves your problem. I have had other problems with the UI not updating and it usually turned out to be a problem with INotifyPropertyChangedTorn
@Rumel: Imho, you should a) check if the _CurrentControl value actually changes after you call the property setter the second time b) try to implement INotifyPropertyChanged yourself (wont take more than a minute) and see if that helpsCuthbert
can you post more of the xamlTorn
@Nik ReactiveObject already Implements INotifyPropertyChanged Refer: Using ReactiveUI to Integrate INotifyPropertyChanged & IObservableTherewith
H
11

There is actually a far better way to do this, using ViewModelViewHost:

<Grid DataContext="{Binding ViewModel, ElementName=TheUserControl}">
    <ViewModelViewHost ViewModel="{Binding CurrentControlViewModel}" />
</Grid>

Now, your class will look something like:

public class MainWindowViewModel : ReactiveObject
{
    private ReactiveObject _CurrentControlViewModel = new HomePageViewModel();
    public ReactiveObject CurrentControlViewModel {
        get { return _CurrentControl; }
        set { this.RaiseAndSetIfChanged(x => x.CurrentControlViewModel, value); }
    }
}

And somewhere in your app's startup, you should write:

RxApp.Register(typeof(IViewFor<HomePageViewModel>), typeof(HomePage));

What's ViewModelViewHost?

ViewModelViewHost will take a ViewModel object that you provide via Bindings, and look up a View that fits it, using Service Location. The Register call is how you can associate Views with ViewModels.

Hui answered 12/3, 2013 at 21:7 Comment(2)
How do I access ViewModelHost?Trieste
It's in ReactiveUI.Routing (part of the ReactiveUI-Xaml NuGet package). You need to add an 'xmlns' declaration at the top of your pageHui
A
5

why you call your class MainWindowViewModel? when you wanna do mvvm you shouldn't have properties with type UserControl in your VM.

the usual mvvm way looks like this:

  • viewmodel with INotifyPropertyChanged
public class MyViewmodel
{
    public IWorkspace MyContent {get;set;}
}
  • xaml content control with binding to your VM
<ContentControl Content="{Binding MyContent}"/>
  • datatemplate --> so that wpf knows how to render your IWorkspace
<DataTemplate DataType="{x:Type local:MyIWorkSpaceImplementationType}" >
   <view:MyWorkspaceView />
</DataTemplate>
Arjuna answered 12/3, 2013 at 7:30 Comment(2)
i have to admit i dont know ReactiveUI. i just wrote my answer because Rumel named his class ..viewmodel and i associate this with MVVMArjuna
Check below to see the ReactiveUI Way™ to do thisHui
V
3

I think you have several muddled concepts here and they are getting in each others way.

Firstly you aren't actually using ANY of the reactiveUI code, it never gets called. Since your get accessor implements a lazy instantiation pattern then it means the set accessor is ignored. This means that the view never notifies the property change, so you never get updates.

I'd recommend using something more like

private UserControl _currentControl;

public MainWindowVirwModel()
{
  CurrentControl = new HomePage();
}

public UserControl CurrentControl
{
  get { return _curentControl;}
  set { this.RaiseAndSetIfChanged(...); }
}

In addition, this still mixes up View components i.e. HomePage, inside your ViewModel tier which will making unit testing far more difficult.

Venomous answered 12/3, 2013 at 8:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.