ContentControl Content Property not changing with hosted content












4















I am trying to learn MVVM and have come across a weird snag. I have a main menu with a drawer control that comes out and shows a menu:
enter image description here



In the main window where this drawer is, I have a ContentControl where I set its content with a Binding.



<ContentControl x:Name="MainWindowContentControl" Content="{Binding Path=WindowContent}"/>


This window's binding is set to a view model.



<Window.DataContext>
<viewmodels:MainWindowViewModel/>
</Window.DataContext>


and here is the ViewModel:



MainWindowViewModel.cs



public class MainWindowViewModel: ViewModelBase
{

private object _content;

public object WindowContent
{
get { return _content; }
set
{
_content = value;
RaisePropertyChanged(nameof(WindowContent));
}
}
public ICommand SetWindowContent { get; set; }

public MainWindowViewModel()
{
SetWindowContent = new ChangeWindowContentCommand(this);
}


}


So far up to this point, everything works fine. So for example, if I click "Recovery Operations", I get this:



RecoveryOperationsView.xaml
enter image description here



In "RecoveryOperationsView.xaml" (which is a UserControl) I also reference the view model from above like so..



<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>


and have a button to call the command to change the Content property of the ContentControl from the main window..



<Button Grid.Row="2" Content="Restore Database" Width="150" Style="{StaticResource MaterialDesignFlatButton}" Command="{Binding SetWindowContent}" CommandParameter="DatabaseRecovery" >


In my class to process the commands, I change the content based off of the passed parameter using a switch statement like so



ChangeWindowContentCommand.cs



public class ChangeWindowContentCommand : ICommand
{
private MainWindowViewModel viewModel;
public ChangeWindowContentCommand(MainWindowViewModel vm)
{
this.viewModel = vm;
}

public event EventHandler CanExecuteChanged;

public bool CanExecute(object parameter)
{
return true;
}

public void Execute(object parameter)
{
switch (parameter)
{
case "Home":
viewModel.WindowContent = new HomeView();
break;
case "RecoveryOps":
viewModel.WindowContent = new RecoveryOperationsView();
break;
case "DatabaseRecovery":
viewModel.WindowContent = new DatabaseRestoreView();
break;
}
}
}


However, this is where I get lost... If I click something within this new window, say "Restore Database" and inspect it with a breakpoint, I can see the property being changed but the actual ContentControl Content property doesnt change to the new UserControl I made... I can change the content with anything in the drawer, but if I try to click a button in the hosted Content of the ContentControl nothing changes. What am I missing?










share|improve this question




















  • 1





    "I can see the property being changed but the actual window content doesn't". Changed to what? Are you perhaps by accident creating a duplicate MainWindowViewModel somewhere? "but if I try to use anything in the hosted content of the ContentControl, nothing works" What is that "anything"? I have no idea what you mean with this sentence. Please edit and improve your question to clarify this.

    – elgonzo
    Nov 19 '18 at 23:16













  • @elgonzo I've updated my question with as much clarification I could get. I don't think I am making multiple references to the MainWindowViewModel anywhere unless adding the datacontext in XAML does exactly that... In the breakpoint, when I click the "Restore Database" button, I can see the WindowContent property changing to an instance of DatabaseRestoreView.

    – tastydew
    Nov 20 '18 at 0:21


















4















I am trying to learn MVVM and have come across a weird snag. I have a main menu with a drawer control that comes out and shows a menu:
enter image description here



In the main window where this drawer is, I have a ContentControl where I set its content with a Binding.



<ContentControl x:Name="MainWindowContentControl" Content="{Binding Path=WindowContent}"/>


This window's binding is set to a view model.



<Window.DataContext>
<viewmodels:MainWindowViewModel/>
</Window.DataContext>


and here is the ViewModel:



MainWindowViewModel.cs



public class MainWindowViewModel: ViewModelBase
{

private object _content;

public object WindowContent
{
get { return _content; }
set
{
_content = value;
RaisePropertyChanged(nameof(WindowContent));
}
}
public ICommand SetWindowContent { get; set; }

public MainWindowViewModel()
{
SetWindowContent = new ChangeWindowContentCommand(this);
}


}


So far up to this point, everything works fine. So for example, if I click "Recovery Operations", I get this:



RecoveryOperationsView.xaml
enter image description here



In "RecoveryOperationsView.xaml" (which is a UserControl) I also reference the view model from above like so..



<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>


and have a button to call the command to change the Content property of the ContentControl from the main window..



<Button Grid.Row="2" Content="Restore Database" Width="150" Style="{StaticResource MaterialDesignFlatButton}" Command="{Binding SetWindowContent}" CommandParameter="DatabaseRecovery" >


In my class to process the commands, I change the content based off of the passed parameter using a switch statement like so



ChangeWindowContentCommand.cs



public class ChangeWindowContentCommand : ICommand
{
private MainWindowViewModel viewModel;
public ChangeWindowContentCommand(MainWindowViewModel vm)
{
this.viewModel = vm;
}

public event EventHandler CanExecuteChanged;

public bool CanExecute(object parameter)
{
return true;
}

public void Execute(object parameter)
{
switch (parameter)
{
case "Home":
viewModel.WindowContent = new HomeView();
break;
case "RecoveryOps":
viewModel.WindowContent = new RecoveryOperationsView();
break;
case "DatabaseRecovery":
viewModel.WindowContent = new DatabaseRestoreView();
break;
}
}
}


However, this is where I get lost... If I click something within this new window, say "Restore Database" and inspect it with a breakpoint, I can see the property being changed but the actual ContentControl Content property doesnt change to the new UserControl I made... I can change the content with anything in the drawer, but if I try to click a button in the hosted Content of the ContentControl nothing changes. What am I missing?










share|improve this question




















  • 1





    "I can see the property being changed but the actual window content doesn't". Changed to what? Are you perhaps by accident creating a duplicate MainWindowViewModel somewhere? "but if I try to use anything in the hosted content of the ContentControl, nothing works" What is that "anything"? I have no idea what you mean with this sentence. Please edit and improve your question to clarify this.

    – elgonzo
    Nov 19 '18 at 23:16













  • @elgonzo I've updated my question with as much clarification I could get. I don't think I am making multiple references to the MainWindowViewModel anywhere unless adding the datacontext in XAML does exactly that... In the breakpoint, when I click the "Restore Database" button, I can see the WindowContent property changing to an instance of DatabaseRestoreView.

    – tastydew
    Nov 20 '18 at 0:21
















4












4








4


1






I am trying to learn MVVM and have come across a weird snag. I have a main menu with a drawer control that comes out and shows a menu:
enter image description here



In the main window where this drawer is, I have a ContentControl where I set its content with a Binding.



<ContentControl x:Name="MainWindowContentControl" Content="{Binding Path=WindowContent}"/>


This window's binding is set to a view model.



<Window.DataContext>
<viewmodels:MainWindowViewModel/>
</Window.DataContext>


and here is the ViewModel:



MainWindowViewModel.cs



public class MainWindowViewModel: ViewModelBase
{

private object _content;

public object WindowContent
{
get { return _content; }
set
{
_content = value;
RaisePropertyChanged(nameof(WindowContent));
}
}
public ICommand SetWindowContent { get; set; }

public MainWindowViewModel()
{
SetWindowContent = new ChangeWindowContentCommand(this);
}


}


So far up to this point, everything works fine. So for example, if I click "Recovery Operations", I get this:



RecoveryOperationsView.xaml
enter image description here



In "RecoveryOperationsView.xaml" (which is a UserControl) I also reference the view model from above like so..



<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>


and have a button to call the command to change the Content property of the ContentControl from the main window..



<Button Grid.Row="2" Content="Restore Database" Width="150" Style="{StaticResource MaterialDesignFlatButton}" Command="{Binding SetWindowContent}" CommandParameter="DatabaseRecovery" >


In my class to process the commands, I change the content based off of the passed parameter using a switch statement like so



ChangeWindowContentCommand.cs



public class ChangeWindowContentCommand : ICommand
{
private MainWindowViewModel viewModel;
public ChangeWindowContentCommand(MainWindowViewModel vm)
{
this.viewModel = vm;
}

public event EventHandler CanExecuteChanged;

public bool CanExecute(object parameter)
{
return true;
}

public void Execute(object parameter)
{
switch (parameter)
{
case "Home":
viewModel.WindowContent = new HomeView();
break;
case "RecoveryOps":
viewModel.WindowContent = new RecoveryOperationsView();
break;
case "DatabaseRecovery":
viewModel.WindowContent = new DatabaseRestoreView();
break;
}
}
}


However, this is where I get lost... If I click something within this new window, say "Restore Database" and inspect it with a breakpoint, I can see the property being changed but the actual ContentControl Content property doesnt change to the new UserControl I made... I can change the content with anything in the drawer, but if I try to click a button in the hosted Content of the ContentControl nothing changes. What am I missing?










share|improve this question
















I am trying to learn MVVM and have come across a weird snag. I have a main menu with a drawer control that comes out and shows a menu:
enter image description here



In the main window where this drawer is, I have a ContentControl where I set its content with a Binding.



<ContentControl x:Name="MainWindowContentControl" Content="{Binding Path=WindowContent}"/>


This window's binding is set to a view model.



<Window.DataContext>
<viewmodels:MainWindowViewModel/>
</Window.DataContext>


and here is the ViewModel:



MainWindowViewModel.cs



public class MainWindowViewModel: ViewModelBase
{

private object _content;

public object WindowContent
{
get { return _content; }
set
{
_content = value;
RaisePropertyChanged(nameof(WindowContent));
}
}
public ICommand SetWindowContent { get; set; }

public MainWindowViewModel()
{
SetWindowContent = new ChangeWindowContentCommand(this);
}


}


So far up to this point, everything works fine. So for example, if I click "Recovery Operations", I get this:



RecoveryOperationsView.xaml
enter image description here



In "RecoveryOperationsView.xaml" (which is a UserControl) I also reference the view model from above like so..



<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>


and have a button to call the command to change the Content property of the ContentControl from the main window..



<Button Grid.Row="2" Content="Restore Database" Width="150" Style="{StaticResource MaterialDesignFlatButton}" Command="{Binding SetWindowContent}" CommandParameter="DatabaseRecovery" >


In my class to process the commands, I change the content based off of the passed parameter using a switch statement like so



ChangeWindowContentCommand.cs



public class ChangeWindowContentCommand : ICommand
{
private MainWindowViewModel viewModel;
public ChangeWindowContentCommand(MainWindowViewModel vm)
{
this.viewModel = vm;
}

public event EventHandler CanExecuteChanged;

public bool CanExecute(object parameter)
{
return true;
}

public void Execute(object parameter)
{
switch (parameter)
{
case "Home":
viewModel.WindowContent = new HomeView();
break;
case "RecoveryOps":
viewModel.WindowContent = new RecoveryOperationsView();
break;
case "DatabaseRecovery":
viewModel.WindowContent = new DatabaseRestoreView();
break;
}
}
}


However, this is where I get lost... If I click something within this new window, say "Restore Database" and inspect it with a breakpoint, I can see the property being changed but the actual ContentControl Content property doesnt change to the new UserControl I made... I can change the content with anything in the drawer, but if I try to click a button in the hosted Content of the ContentControl nothing changes. What am I missing?







c# wpf mvvm material-design-in-xaml






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 20 '18 at 0:19







tastydew

















asked Nov 19 '18 at 23:00









tastydewtastydew

523514




523514








  • 1





    "I can see the property being changed but the actual window content doesn't". Changed to what? Are you perhaps by accident creating a duplicate MainWindowViewModel somewhere? "but if I try to use anything in the hosted content of the ContentControl, nothing works" What is that "anything"? I have no idea what you mean with this sentence. Please edit and improve your question to clarify this.

    – elgonzo
    Nov 19 '18 at 23:16













  • @elgonzo I've updated my question with as much clarification I could get. I don't think I am making multiple references to the MainWindowViewModel anywhere unless adding the datacontext in XAML does exactly that... In the breakpoint, when I click the "Restore Database" button, I can see the WindowContent property changing to an instance of DatabaseRestoreView.

    – tastydew
    Nov 20 '18 at 0:21
















  • 1





    "I can see the property being changed but the actual window content doesn't". Changed to what? Are you perhaps by accident creating a duplicate MainWindowViewModel somewhere? "but if I try to use anything in the hosted content of the ContentControl, nothing works" What is that "anything"? I have no idea what you mean with this sentence. Please edit and improve your question to clarify this.

    – elgonzo
    Nov 19 '18 at 23:16













  • @elgonzo I've updated my question with as much clarification I could get. I don't think I am making multiple references to the MainWindowViewModel anywhere unless adding the datacontext in XAML does exactly that... In the breakpoint, when I click the "Restore Database" button, I can see the WindowContent property changing to an instance of DatabaseRestoreView.

    – tastydew
    Nov 20 '18 at 0:21










1




1





"I can see the property being changed but the actual window content doesn't". Changed to what? Are you perhaps by accident creating a duplicate MainWindowViewModel somewhere? "but if I try to use anything in the hosted content of the ContentControl, nothing works" What is that "anything"? I have no idea what you mean with this sentence. Please edit and improve your question to clarify this.

– elgonzo
Nov 19 '18 at 23:16







"I can see the property being changed but the actual window content doesn't". Changed to what? Are you perhaps by accident creating a duplicate MainWindowViewModel somewhere? "but if I try to use anything in the hosted content of the ContentControl, nothing works" What is that "anything"? I have no idea what you mean with this sentence. Please edit and improve your question to clarify this.

– elgonzo
Nov 19 '18 at 23:16















@elgonzo I've updated my question with as much clarification I could get. I don't think I am making multiple references to the MainWindowViewModel anywhere unless adding the datacontext in XAML does exactly that... In the breakpoint, when I click the "Restore Database" button, I can see the WindowContent property changing to an instance of DatabaseRestoreView.

– tastydew
Nov 20 '18 at 0:21







@elgonzo I've updated my question with as much clarification I could get. I don't think I am making multiple references to the MainWindowViewModel anywhere unless adding the datacontext in XAML does exactly that... In the breakpoint, when I click the "Restore Database" button, I can see the WindowContent property changing to an instance of DatabaseRestoreView.

– tastydew
Nov 20 '18 at 0:21














1 Answer
1






active

oldest

votes


















3














It's hard to be 100% sure without having your project to test with, but I am fairly confident that at least one of the issues is that your UserControl and your MainWindow use different instances of the MainWindowViewModel. You do not need to instantiate the VM for the user control, as it will inherit the DataContext from the MainWindow. The way it works in WPF is that if any given UIElement does not have theDataContext assigned explicitly, it will inherit it from the first element up the logical tree that does has one assigned.



So, just delete this code, and it should solve at least that issue.



<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>


And since you're learning WPF, I feel obligated to provide a couple other tips. Even though you're using a ViewModel, you are still mixing UI and logic by creating a very specific implementation of ICommand and assigning a UI element through your ViewModel. This breaks the MVVM pattern. I know MVVM takes a little time to understand, but once you do, it is very easy to use and maintain.



To solve your problem, I would suggest creating View Models for each of your user controls. Please see this answer, where I go into quite a bit of detail on the implementation.



For switching the different views, you have a couple of options. You can either use a TabControl, or if you want to use a command, you can have a single ContentControl bound to a property of MainWindowViewModel that is of type ViewModelBase. Let's call it CurrentViewModel. Then when the command fires, you assign the view model of the desired user control to that bound property. You will also need to utilize implicit data templates. The basic idea is that you create a template for each of the user control VM types, which would just contains an instance of the Views. When you assign the user control VM to the CurrentViewModel property, the binding will find those data templates and render the user control. For example:



<Window.Resources>
<DataTemplate DataType = "{x:Type viewmodels:RecoveryOperationsViewModel}">
<views:RecoveryOperationsView/>
</DataTemplate>
<!-- Now add a template for each of the views-->
</Window.Resources>

<ContentControl x:Name="MainWindowContentControl" Content="{Binding CurrentViewModel}"/>


See how this approach keeps UI and logic at an arm's length?



And lastly, consider creating a very generic implementation of ICommand to use in all your ViewModels rather than many specific implementations. I think most WPF programmers have more or less this exact RelayCommand implementation in their arsenal.






share|improve this answer





















  • 1





    This was absolutely the issue! I really appreciate the help and the excellent explanation of de-coupling my viewmodels from my views! My approach was much like the one you suggested of the two where I create a ViewModel for every user control. I guess its the implementation of switching between them that i need to work on. Thanks again!

    – tastydew
    Nov 20 '18 at 4:02






  • 1





    My pleasure. Glad it helped. It looks like you're almost there, just a small change in concept. You should use the implicit data templates as above and move the switching code into your MainViewModel (rather than ICommand class), while using the generic implementation of RelayCommand above. That will perfectly adhere to the MVVM pattern!

    – Nik
    Nov 20 '18 at 5:03











  • So I implemented the DataTemplate method you provided using an exposed property public ViewModelBase CurrentViewModel to change the current view, however, when I try to click a button in one of the views that appear in the UserControl, it appears as though the inherited DataContext is lost up the VisualTree.It looks like the output console logs the following: ` BindingExpression path error: 'ChangeCurrentViewModel' property not found on 'object' ''RecoveryOperationsViewModel' (HashCode=58033516)'. Is this because setting the CurrentViewModel changes the context for the view?

    – tastydew
    Nov 20 '18 at 21:09








  • 1





    So the way that will work, is the user controls will no longer inherit the data context from the window, but rather from the ContentControl due to the binding. This DataContext will now be RecoveryOperationsViewModel rather than MainWindowViewModel, where the command is defined. Hence the binding error. You should be able to use RelativeSource binding to fire the command. Or move the command to the child view model, and have the child communicate with parent VM. Not sure how much this makes sense, but I can flesh this out in my answer for you after work today.

    – Nik
    Nov 20 '18 at 21:18






  • 1





    One simple concept that helped me A LOT when I was first learning WPF is: Everything is a tree! And everything inherits from up the logic tree. This applies to styles, data templates, and any other dependency property. To skip some levels in the logical tree (i.e. to select the correct datacontext), you would generally use RelativeSource binding (among other techniques).

    – Nik
    Nov 20 '18 at 21:21











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383868%2fcontentcontrol-content-property-not-changing-with-hosted-content%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









3














It's hard to be 100% sure without having your project to test with, but I am fairly confident that at least one of the issues is that your UserControl and your MainWindow use different instances of the MainWindowViewModel. You do not need to instantiate the VM for the user control, as it will inherit the DataContext from the MainWindow. The way it works in WPF is that if any given UIElement does not have theDataContext assigned explicitly, it will inherit it from the first element up the logical tree that does has one assigned.



So, just delete this code, and it should solve at least that issue.



<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>


And since you're learning WPF, I feel obligated to provide a couple other tips. Even though you're using a ViewModel, you are still mixing UI and logic by creating a very specific implementation of ICommand and assigning a UI element through your ViewModel. This breaks the MVVM pattern. I know MVVM takes a little time to understand, but once you do, it is very easy to use and maintain.



To solve your problem, I would suggest creating View Models for each of your user controls. Please see this answer, where I go into quite a bit of detail on the implementation.



For switching the different views, you have a couple of options. You can either use a TabControl, or if you want to use a command, you can have a single ContentControl bound to a property of MainWindowViewModel that is of type ViewModelBase. Let's call it CurrentViewModel. Then when the command fires, you assign the view model of the desired user control to that bound property. You will also need to utilize implicit data templates. The basic idea is that you create a template for each of the user control VM types, which would just contains an instance of the Views. When you assign the user control VM to the CurrentViewModel property, the binding will find those data templates and render the user control. For example:



<Window.Resources>
<DataTemplate DataType = "{x:Type viewmodels:RecoveryOperationsViewModel}">
<views:RecoveryOperationsView/>
</DataTemplate>
<!-- Now add a template for each of the views-->
</Window.Resources>

<ContentControl x:Name="MainWindowContentControl" Content="{Binding CurrentViewModel}"/>


See how this approach keeps UI and logic at an arm's length?



And lastly, consider creating a very generic implementation of ICommand to use in all your ViewModels rather than many specific implementations. I think most WPF programmers have more or less this exact RelayCommand implementation in their arsenal.






share|improve this answer





















  • 1





    This was absolutely the issue! I really appreciate the help and the excellent explanation of de-coupling my viewmodels from my views! My approach was much like the one you suggested of the two where I create a ViewModel for every user control. I guess its the implementation of switching between them that i need to work on. Thanks again!

    – tastydew
    Nov 20 '18 at 4:02






  • 1





    My pleasure. Glad it helped. It looks like you're almost there, just a small change in concept. You should use the implicit data templates as above and move the switching code into your MainViewModel (rather than ICommand class), while using the generic implementation of RelayCommand above. That will perfectly adhere to the MVVM pattern!

    – Nik
    Nov 20 '18 at 5:03











  • So I implemented the DataTemplate method you provided using an exposed property public ViewModelBase CurrentViewModel to change the current view, however, when I try to click a button in one of the views that appear in the UserControl, it appears as though the inherited DataContext is lost up the VisualTree.It looks like the output console logs the following: ` BindingExpression path error: 'ChangeCurrentViewModel' property not found on 'object' ''RecoveryOperationsViewModel' (HashCode=58033516)'. Is this because setting the CurrentViewModel changes the context for the view?

    – tastydew
    Nov 20 '18 at 21:09








  • 1





    So the way that will work, is the user controls will no longer inherit the data context from the window, but rather from the ContentControl due to the binding. This DataContext will now be RecoveryOperationsViewModel rather than MainWindowViewModel, where the command is defined. Hence the binding error. You should be able to use RelativeSource binding to fire the command. Or move the command to the child view model, and have the child communicate with parent VM. Not sure how much this makes sense, but I can flesh this out in my answer for you after work today.

    – Nik
    Nov 20 '18 at 21:18






  • 1





    One simple concept that helped me A LOT when I was first learning WPF is: Everything is a tree! And everything inherits from up the logic tree. This applies to styles, data templates, and any other dependency property. To skip some levels in the logical tree (i.e. to select the correct datacontext), you would generally use RelativeSource binding (among other techniques).

    – Nik
    Nov 20 '18 at 21:21
















3














It's hard to be 100% sure without having your project to test with, but I am fairly confident that at least one of the issues is that your UserControl and your MainWindow use different instances of the MainWindowViewModel. You do not need to instantiate the VM for the user control, as it will inherit the DataContext from the MainWindow. The way it works in WPF is that if any given UIElement does not have theDataContext assigned explicitly, it will inherit it from the first element up the logical tree that does has one assigned.



So, just delete this code, and it should solve at least that issue.



<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>


And since you're learning WPF, I feel obligated to provide a couple other tips. Even though you're using a ViewModel, you are still mixing UI and logic by creating a very specific implementation of ICommand and assigning a UI element through your ViewModel. This breaks the MVVM pattern. I know MVVM takes a little time to understand, but once you do, it is very easy to use and maintain.



To solve your problem, I would suggest creating View Models for each of your user controls. Please see this answer, where I go into quite a bit of detail on the implementation.



For switching the different views, you have a couple of options. You can either use a TabControl, or if you want to use a command, you can have a single ContentControl bound to a property of MainWindowViewModel that is of type ViewModelBase. Let's call it CurrentViewModel. Then when the command fires, you assign the view model of the desired user control to that bound property. You will also need to utilize implicit data templates. The basic idea is that you create a template for each of the user control VM types, which would just contains an instance of the Views. When you assign the user control VM to the CurrentViewModel property, the binding will find those data templates and render the user control. For example:



<Window.Resources>
<DataTemplate DataType = "{x:Type viewmodels:RecoveryOperationsViewModel}">
<views:RecoveryOperationsView/>
</DataTemplate>
<!-- Now add a template for each of the views-->
</Window.Resources>

<ContentControl x:Name="MainWindowContentControl" Content="{Binding CurrentViewModel}"/>


See how this approach keeps UI and logic at an arm's length?



And lastly, consider creating a very generic implementation of ICommand to use in all your ViewModels rather than many specific implementations. I think most WPF programmers have more or less this exact RelayCommand implementation in their arsenal.






share|improve this answer





















  • 1





    This was absolutely the issue! I really appreciate the help and the excellent explanation of de-coupling my viewmodels from my views! My approach was much like the one you suggested of the two where I create a ViewModel for every user control. I guess its the implementation of switching between them that i need to work on. Thanks again!

    – tastydew
    Nov 20 '18 at 4:02






  • 1





    My pleasure. Glad it helped. It looks like you're almost there, just a small change in concept. You should use the implicit data templates as above and move the switching code into your MainViewModel (rather than ICommand class), while using the generic implementation of RelayCommand above. That will perfectly adhere to the MVVM pattern!

    – Nik
    Nov 20 '18 at 5:03











  • So I implemented the DataTemplate method you provided using an exposed property public ViewModelBase CurrentViewModel to change the current view, however, when I try to click a button in one of the views that appear in the UserControl, it appears as though the inherited DataContext is lost up the VisualTree.It looks like the output console logs the following: ` BindingExpression path error: 'ChangeCurrentViewModel' property not found on 'object' ''RecoveryOperationsViewModel' (HashCode=58033516)'. Is this because setting the CurrentViewModel changes the context for the view?

    – tastydew
    Nov 20 '18 at 21:09








  • 1





    So the way that will work, is the user controls will no longer inherit the data context from the window, but rather from the ContentControl due to the binding. This DataContext will now be RecoveryOperationsViewModel rather than MainWindowViewModel, where the command is defined. Hence the binding error. You should be able to use RelativeSource binding to fire the command. Or move the command to the child view model, and have the child communicate with parent VM. Not sure how much this makes sense, but I can flesh this out in my answer for you after work today.

    – Nik
    Nov 20 '18 at 21:18






  • 1





    One simple concept that helped me A LOT when I was first learning WPF is: Everything is a tree! And everything inherits from up the logic tree. This applies to styles, data templates, and any other dependency property. To skip some levels in the logical tree (i.e. to select the correct datacontext), you would generally use RelativeSource binding (among other techniques).

    – Nik
    Nov 20 '18 at 21:21














3












3








3







It's hard to be 100% sure without having your project to test with, but I am fairly confident that at least one of the issues is that your UserControl and your MainWindow use different instances of the MainWindowViewModel. You do not need to instantiate the VM for the user control, as it will inherit the DataContext from the MainWindow. The way it works in WPF is that if any given UIElement does not have theDataContext assigned explicitly, it will inherit it from the first element up the logical tree that does has one assigned.



So, just delete this code, and it should solve at least that issue.



<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>


And since you're learning WPF, I feel obligated to provide a couple other tips. Even though you're using a ViewModel, you are still mixing UI and logic by creating a very specific implementation of ICommand and assigning a UI element through your ViewModel. This breaks the MVVM pattern. I know MVVM takes a little time to understand, but once you do, it is very easy to use and maintain.



To solve your problem, I would suggest creating View Models for each of your user controls. Please see this answer, where I go into quite a bit of detail on the implementation.



For switching the different views, you have a couple of options. You can either use a TabControl, or if you want to use a command, you can have a single ContentControl bound to a property of MainWindowViewModel that is of type ViewModelBase. Let's call it CurrentViewModel. Then when the command fires, you assign the view model of the desired user control to that bound property. You will also need to utilize implicit data templates. The basic idea is that you create a template for each of the user control VM types, which would just contains an instance of the Views. When you assign the user control VM to the CurrentViewModel property, the binding will find those data templates and render the user control. For example:



<Window.Resources>
<DataTemplate DataType = "{x:Type viewmodels:RecoveryOperationsViewModel}">
<views:RecoveryOperationsView/>
</DataTemplate>
<!-- Now add a template for each of the views-->
</Window.Resources>

<ContentControl x:Name="MainWindowContentControl" Content="{Binding CurrentViewModel}"/>


See how this approach keeps UI and logic at an arm's length?



And lastly, consider creating a very generic implementation of ICommand to use in all your ViewModels rather than many specific implementations. I think most WPF programmers have more or less this exact RelayCommand implementation in their arsenal.






share|improve this answer















It's hard to be 100% sure without having your project to test with, but I am fairly confident that at least one of the issues is that your UserControl and your MainWindow use different instances of the MainWindowViewModel. You do not need to instantiate the VM for the user control, as it will inherit the DataContext from the MainWindow. The way it works in WPF is that if any given UIElement does not have theDataContext assigned explicitly, it will inherit it from the first element up the logical tree that does has one assigned.



So, just delete this code, and it should solve at least that issue.



<UserControl.DataContext>
<viewmodels:MainWindowViewModel/>
</UserControl.DataContext>


And since you're learning WPF, I feel obligated to provide a couple other tips. Even though you're using a ViewModel, you are still mixing UI and logic by creating a very specific implementation of ICommand and assigning a UI element through your ViewModel. This breaks the MVVM pattern. I know MVVM takes a little time to understand, but once you do, it is very easy to use and maintain.



To solve your problem, I would suggest creating View Models for each of your user controls. Please see this answer, where I go into quite a bit of detail on the implementation.



For switching the different views, you have a couple of options. You can either use a TabControl, or if you want to use a command, you can have a single ContentControl bound to a property of MainWindowViewModel that is of type ViewModelBase. Let's call it CurrentViewModel. Then when the command fires, you assign the view model of the desired user control to that bound property. You will also need to utilize implicit data templates. The basic idea is that you create a template for each of the user control VM types, which would just contains an instance of the Views. When you assign the user control VM to the CurrentViewModel property, the binding will find those data templates and render the user control. For example:



<Window.Resources>
<DataTemplate DataType = "{x:Type viewmodels:RecoveryOperationsViewModel}">
<views:RecoveryOperationsView/>
</DataTemplate>
<!-- Now add a template for each of the views-->
</Window.Resources>

<ContentControl x:Name="MainWindowContentControl" Content="{Binding CurrentViewModel}"/>


See how this approach keeps UI and logic at an arm's length?



And lastly, consider creating a very generic implementation of ICommand to use in all your ViewModels rather than many specific implementations. I think most WPF programmers have more or less this exact RelayCommand implementation in their arsenal.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 20 '18 at 15:09

























answered Nov 20 '18 at 3:36









NikNik

1,3431619




1,3431619








  • 1





    This was absolutely the issue! I really appreciate the help and the excellent explanation of de-coupling my viewmodels from my views! My approach was much like the one you suggested of the two where I create a ViewModel for every user control. I guess its the implementation of switching between them that i need to work on. Thanks again!

    – tastydew
    Nov 20 '18 at 4:02






  • 1





    My pleasure. Glad it helped. It looks like you're almost there, just a small change in concept. You should use the implicit data templates as above and move the switching code into your MainViewModel (rather than ICommand class), while using the generic implementation of RelayCommand above. That will perfectly adhere to the MVVM pattern!

    – Nik
    Nov 20 '18 at 5:03











  • So I implemented the DataTemplate method you provided using an exposed property public ViewModelBase CurrentViewModel to change the current view, however, when I try to click a button in one of the views that appear in the UserControl, it appears as though the inherited DataContext is lost up the VisualTree.It looks like the output console logs the following: ` BindingExpression path error: 'ChangeCurrentViewModel' property not found on 'object' ''RecoveryOperationsViewModel' (HashCode=58033516)'. Is this because setting the CurrentViewModel changes the context for the view?

    – tastydew
    Nov 20 '18 at 21:09








  • 1





    So the way that will work, is the user controls will no longer inherit the data context from the window, but rather from the ContentControl due to the binding. This DataContext will now be RecoveryOperationsViewModel rather than MainWindowViewModel, where the command is defined. Hence the binding error. You should be able to use RelativeSource binding to fire the command. Or move the command to the child view model, and have the child communicate with parent VM. Not sure how much this makes sense, but I can flesh this out in my answer for you after work today.

    – Nik
    Nov 20 '18 at 21:18






  • 1





    One simple concept that helped me A LOT when I was first learning WPF is: Everything is a tree! And everything inherits from up the logic tree. This applies to styles, data templates, and any other dependency property. To skip some levels in the logical tree (i.e. to select the correct datacontext), you would generally use RelativeSource binding (among other techniques).

    – Nik
    Nov 20 '18 at 21:21














  • 1





    This was absolutely the issue! I really appreciate the help and the excellent explanation of de-coupling my viewmodels from my views! My approach was much like the one you suggested of the two where I create a ViewModel for every user control. I guess its the implementation of switching between them that i need to work on. Thanks again!

    – tastydew
    Nov 20 '18 at 4:02






  • 1





    My pleasure. Glad it helped. It looks like you're almost there, just a small change in concept. You should use the implicit data templates as above and move the switching code into your MainViewModel (rather than ICommand class), while using the generic implementation of RelayCommand above. That will perfectly adhere to the MVVM pattern!

    – Nik
    Nov 20 '18 at 5:03











  • So I implemented the DataTemplate method you provided using an exposed property public ViewModelBase CurrentViewModel to change the current view, however, when I try to click a button in one of the views that appear in the UserControl, it appears as though the inherited DataContext is lost up the VisualTree.It looks like the output console logs the following: ` BindingExpression path error: 'ChangeCurrentViewModel' property not found on 'object' ''RecoveryOperationsViewModel' (HashCode=58033516)'. Is this because setting the CurrentViewModel changes the context for the view?

    – tastydew
    Nov 20 '18 at 21:09








  • 1





    So the way that will work, is the user controls will no longer inherit the data context from the window, but rather from the ContentControl due to the binding. This DataContext will now be RecoveryOperationsViewModel rather than MainWindowViewModel, where the command is defined. Hence the binding error. You should be able to use RelativeSource binding to fire the command. Or move the command to the child view model, and have the child communicate with parent VM. Not sure how much this makes sense, but I can flesh this out in my answer for you after work today.

    – Nik
    Nov 20 '18 at 21:18






  • 1





    One simple concept that helped me A LOT when I was first learning WPF is: Everything is a tree! And everything inherits from up the logic tree. This applies to styles, data templates, and any other dependency property. To skip some levels in the logical tree (i.e. to select the correct datacontext), you would generally use RelativeSource binding (among other techniques).

    – Nik
    Nov 20 '18 at 21:21








1




1





This was absolutely the issue! I really appreciate the help and the excellent explanation of de-coupling my viewmodels from my views! My approach was much like the one you suggested of the two where I create a ViewModel for every user control. I guess its the implementation of switching between them that i need to work on. Thanks again!

– tastydew
Nov 20 '18 at 4:02





This was absolutely the issue! I really appreciate the help and the excellent explanation of de-coupling my viewmodels from my views! My approach was much like the one you suggested of the two where I create a ViewModel for every user control. I guess its the implementation of switching between them that i need to work on. Thanks again!

– tastydew
Nov 20 '18 at 4:02




1




1





My pleasure. Glad it helped. It looks like you're almost there, just a small change in concept. You should use the implicit data templates as above and move the switching code into your MainViewModel (rather than ICommand class), while using the generic implementation of RelayCommand above. That will perfectly adhere to the MVVM pattern!

– Nik
Nov 20 '18 at 5:03





My pleasure. Glad it helped. It looks like you're almost there, just a small change in concept. You should use the implicit data templates as above and move the switching code into your MainViewModel (rather than ICommand class), while using the generic implementation of RelayCommand above. That will perfectly adhere to the MVVM pattern!

– Nik
Nov 20 '18 at 5:03













So I implemented the DataTemplate method you provided using an exposed property public ViewModelBase CurrentViewModel to change the current view, however, when I try to click a button in one of the views that appear in the UserControl, it appears as though the inherited DataContext is lost up the VisualTree.It looks like the output console logs the following: ` BindingExpression path error: 'ChangeCurrentViewModel' property not found on 'object' ''RecoveryOperationsViewModel' (HashCode=58033516)'. Is this because setting the CurrentViewModel changes the context for the view?

– tastydew
Nov 20 '18 at 21:09







So I implemented the DataTemplate method you provided using an exposed property public ViewModelBase CurrentViewModel to change the current view, however, when I try to click a button in one of the views that appear in the UserControl, it appears as though the inherited DataContext is lost up the VisualTree.It looks like the output console logs the following: ` BindingExpression path error: 'ChangeCurrentViewModel' property not found on 'object' ''RecoveryOperationsViewModel' (HashCode=58033516)'. Is this because setting the CurrentViewModel changes the context for the view?

– tastydew
Nov 20 '18 at 21:09






1




1





So the way that will work, is the user controls will no longer inherit the data context from the window, but rather from the ContentControl due to the binding. This DataContext will now be RecoveryOperationsViewModel rather than MainWindowViewModel, where the command is defined. Hence the binding error. You should be able to use RelativeSource binding to fire the command. Or move the command to the child view model, and have the child communicate with parent VM. Not sure how much this makes sense, but I can flesh this out in my answer for you after work today.

– Nik
Nov 20 '18 at 21:18





So the way that will work, is the user controls will no longer inherit the data context from the window, but rather from the ContentControl due to the binding. This DataContext will now be RecoveryOperationsViewModel rather than MainWindowViewModel, where the command is defined. Hence the binding error. You should be able to use RelativeSource binding to fire the command. Or move the command to the child view model, and have the child communicate with parent VM. Not sure how much this makes sense, but I can flesh this out in my answer for you after work today.

– Nik
Nov 20 '18 at 21:18




1




1





One simple concept that helped me A LOT when I was first learning WPF is: Everything is a tree! And everything inherits from up the logic tree. This applies to styles, data templates, and any other dependency property. To skip some levels in the logical tree (i.e. to select the correct datacontext), you would generally use RelativeSource binding (among other techniques).

– Nik
Nov 20 '18 at 21:21





One simple concept that helped me A LOT when I was first learning WPF is: Everything is a tree! And everything inherits from up the logic tree. This applies to styles, data templates, and any other dependency property. To skip some levels in the logical tree (i.e. to select the correct datacontext), you would generally use RelativeSource binding (among other techniques).

– Nik
Nov 20 '18 at 21:21




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383868%2fcontentcontrol-content-property-not-changing-with-hosted-content%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Tangent Lines Diagram Along Smooth Curve

Yusuf al-Mu'taman ibn Hud

Zucchini