ViewModelLocator.AutoWireViewModel - No DataContext for MainWindow - c#

MainWindow UI
<Window x:Class="PrismSanity.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock Text="{Binding MyName}"></TextBlock>
</Grid>
</Window>
MainWindowViewModel
public class MainWindowViewModel : BindableBase
{
private string _MyName = "John";
public string MyName
{
get { return _MyName = "John"; }
set { SetProperty(ref _MyName, value); }
}
}
I installed SNOOP to see what was happening, but the VM is not being Linked to the View. If I do the same thing with a second view, and use
<ContectContainer>
<views:ViewA/>
</ContentContainer>
in the Mainwindow
Then I get the ViewA and ViewAViewModel to link fine.
Thanks for looking.

Prism supports only UserControl class not Window class. AutoWireViewModel wokrs only with UserControl class.
I have the same problem I resolve this binding the context in code behind - partial using Unity. Something like that:
public partial class ShellView : Window
{
public ShellView(ShellViewModel viewModel)
{
this.InitializeComponent();
// Set the ViewModel as this View's data context.
this.DataContext = viewModel;
}
When app create the ShellView (it is your PrismSanity.MainWindow) unity inject the viewModel (ShellViewModel )
It is little technology debt.

Related

How to handle Master-Detail screen communication in WPF with MVVM architecture?

I'm trying to build my first app with WPF and in order to fully understand MVVM I'm not using any framework, the only helper I use is Microsoft.Toolkit.Mvvm
I have thi app with 2 pages, one is the master and the other one is the detail.
I did set up navigation as it's explained in WPF MVVM navigate views
Now I don't understand how I should tell to the detail screen which data it should display, since I'm not allowed to pass parameters to the viewmodel that I am instantiating in the datacontext.
My MainWindow.xaml
<Window x:Class="AlgsManagerDesktop.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AlgsManagerDesktop"
xmlns:views="clr-namespace:AlgsManagerDesktop.Views"
xmlns:viewModel="clr-namespace:AlgsManagerDesktop.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate DataType="{x:Type viewModel:MasterViewModel}">
<views:MasterView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:DetailsViewModel}">
<views:DetailsView />
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<viewModel:MainWindowViewModel />
</Window.DataContext>
<Grid>
<ContentControl Content="{Binding ViewModel}" />
</Grid>
</Window>
MainWindowViewModel.cs
public class MainWindowViewModel : ObservableObject
{
private BaseViewModel viewModel;
public BaseViewModel ViewModel
{
get => viewModel;
set => SetProperty(ref viewModel, value);
}
public RelayCommand SwitchToDetailsCommand { get; }
public MainWindowViewModel()
{
ViewModel = new MasterViewModel();
SwitchToDetailsCommand = new RelayCommand(SwitchToDetails);
}
private void SwitchToDetails()
{
ViewModel = new DetailsViewModel();
}
}
MasterViewModel.cs
public class MasterViewModel : BaseViewModel
{
private ItemModel selectedItem;
public ItemModel SelectedItem
{
get => selectedItem;
set
{
SetProperty(ref selectedItem, value);
DeleteCommand.NotifyCanExecuteChanged();
}
}
public ObservableCollection<ItemModel> items { get; set; }
public RelayCommand DeleteCommand { get; }
public MasterViewModel()
{
DeleteCommand = new RelayCommand(RemoveItem, ItemIsSelected);
}
private void RemoveItems()
{
AlgSets.Remove(SelectedItem);
}
private bool ItemIsSelected()
{
return SelectedItem != null;
}
}
MasterView.xaml
<UserControl x:Class="AlgsManagerDesktop.Views.MasterView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AlgsManagerDesktop.Views"
xmlns:viewModel="clr-namespace:AlgsManagerDesktop.ViewModel"
xmlns:root="clr-namespace:AlgsManagerDesktop"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.DataContext>
<viewModel:MasterViewModel/>
</UserControl.DataContext>
<!-- ListBox here that updates a SelectedItem property -->
<!-- this button handles navigation to details screen, I'd like to pass SelectedItem to the next screen -->
<Button Command="{Binding DataContext.SwitchToDetailsCommand,
RelativeSource={RelativeSource AncestorType={x:Type root:MainWindow}},
Mode=OneWay}">
Open Selected
</Button>
</UserControl>
DetailsView.xaml
<UserControl x:Class="AlgsManagerDesktop.Views.DetailsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AlgsManagerDesktop.Views"
xmlns:viewModel="clr-namespace:AlgsManagerDesktop.ViewModel"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.DataContext>
<viewModel:DetailsViewModel/>
</UserControl.DataContext>
<-- Item details here, I'd like to take them from an Item property in the DetailsViewModel -->
</UserControl>
The DetailsView should inherit the DataContext from the ViewModel property of the MainWindowViewModel which it will if you remove the following XAML markup from it, i.e. you should not set the DataContext of the UserControl explicitly somewhere:
<UserControl.DataContext>
<viewModel:DetailsViewModel/>
</UserControl.DataContext>
It's then up to the MainWindowViewModel to initialize and set the state of the DetailsViewModel.
You created a SelectedItem property in MasterViewModel, presumably to bind to the SelectedItem property of your presumable ListBox that's missing from your XAML, but that is a dead-end view model. In fact I'd argue that you shouldn't split your view model in three (the actual view model, the master one and the details one) because they're all linked together -- they're one view split in a view and 2 sub-views, so logically you should have one view model.
It should be immediately obvious that your approach isn't going to work because when you create the master/details view models in your code you don't link them together at all, you just create throw-aways.
The alternative if you want to keep your 3 view models separate for whatever reason is to keep a property link to the main view model in both of them, and to move the SelectedItem property to the main view model, then bind to it in both sub-views.

Trivial binding to property of a UserControl - not working yet no errors [duplicate]

This question already has answers here:
Issue with DependencyProperty binding
(3 answers)
How to correctly bind to a dependency property of a usercontrol in a MVVM framework
(4 answers)
Closed 4 years ago.
I am attempting to get to grips with DataBinding, and I have just started to introduce UserControls into the mix, but it appears I cannot even get the most basic example working.
I have a MainWindow that contains a property (Subtitle) along with an instance of a UserControl. A property of the UserControl (LabelContent) is bound to the Subtitle property. The expected result is that changing the Subtitle property of MainWindow will update the LabelContent property of the UserControl, which is bound to the actual Content property of a Label within the UserControl:
I have MainWindow.xaml:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<local:UserControlSample LabelContent="{Binding Subtitle}"/>
With the following code behind (MainWindow.cs):
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
Subtitle = "Test";
}
public String Subtitle
{
get;
set;
}
}
UserControlSample.xaml:
<UserControl x:Class="WpfApp1.UserControlSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Label Content="{Binding Path=LabelContent}"/>
UserControl.cs:
public partial class UserControlSample : UserControl
{
public static DependencyProperty LabelContentProperty = DependencyProperty.Register("LabelContent", typeof(String), typeof(UserControlSample));
public UserControlSample()
{
InitializeComponent();
DataContext = this;
}
public String LabelContent
{
get { return (String)GetValue(LabelContentProperty); }
set { SetValue(LabelContentProperty, value); }
}
}
I believe it is something to do with DataContexts however I do not understand them too well as yet. If I change UserControl to the following, then I achieve the expected results. However this does not explain the reasons why the original code fails:
UserControlSample.xaml
<Label Content="{Binding Path=Subtitle}"/>
UserControl.cs
public UserControlSample()
{
InitializeComponent();
}
You would need changes at two places,
First in Xaml, you need to set the source object of the Binding to the UserControl
<Label Content="{Binding Path=LabelContent,RelativeSource={RelativeSource AncestorType=UserControl}}" />
Secondly,
public UserControl1()
{
InitializeComponent();
}
That should allow you to bind the User Control correctly

Window property and Checkbox databinding xaml

I have been a few hours now trying to understand how to do data-binding.
Initially I was following some examples but they all show to do the databinding using {Binding Source={StaticResource myObject}, Path=myObject.myProperty}
or {Binding Path=myObject.myProperty}
Nothing of this seem to bind the Config object inside the controller that is inside the Window.
If I do the binding as an StaticResource it does the binding to an object of the Controller class but is NOT the object that is created inside the window class, this Config seems to be a new separate instance. This is the part I don't understand. If someone could explain or give me some reference where to look I would greatly appreciate it.
This is some code very simplified
Window1.cs
<Window x:Class="Sample.UI.Main"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controller="clr-namespace:Sample.Controller"
mc:Ignorable="d"
Title="SampleApp" Height="600" Width="800" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
<Window.Resources>
<ResourceDictionary>
<controller:PublisherController x:Key="oController" />
</ResourceDictionary>
</Window.Resources>
<CheckBox x:Name="chkBoxShowRoom" Style="{StaticResource checkBoxTemplate}" Content="{StaticResource configShowRoom}" IsChecked="{Binding Source={StaticResource oController}, Path=Config.ShowRoom}"/>
Then my Window1.cs
public partial class Main : Window
{
public PublisherController Controller { get; set; }
Then Controller.cs
public class PublisherController
{
public Configuration Config { get; set; }
Then the Configuration.cs
public class Configuration : AbstractEntity, INotifyPropertyChanged
{
private bool _ShowRoom;
public bool ShowRoom
{
get
{
return _ShowRoom;
}
set
{
if (value != _ShowRoom)
{
this._ShowRoom = value;
OnPropertyChanged();
}
}
}
...

Navigation from one view to another in WPF MVVM

I wrote code which should navigate between user controls in WPF application using MVVM, but I realised that this code doesn't work.
From window LoginView I want to change the view to VotingCardView.
Actually, after clicking on the button in the LoginView, the method DisplayVCV gets executed, but the view is not going to change. What am I doing wrong?
MainView.xaml:
<Window x:Class="ElectionCalculator.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ElectionCalculator"
xmlns:v="clr-namespace:ElectionCalculator.View"
xmlns:vm="clr-namespace:ElectionCalculator.ViewModel"
mc:Ignorable="d"
Title="Election calculator" Height="350" Width="525">
<Window.DataContext>
<vm:MainViewModel />
</Window.DataContext>
<ContentControl Content="{Binding ViewModel}" />
</Window>
LoginView.xaml:
<UserControl x:Class="ElectionCalculator.View.LoginView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ElectionCalculator.View"
xmlns:vm="clr-namespace:ElectionCalculator.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button Command="{Binding DataContext.DisplayVC, RelativeSource={RelativeSource AncestorType={x:Type Window}}, Mode=OneWay}" Margin="161,147,47,124" />
</Grid>
</UserControl>
MainViewModel.cs
class MainViewModel : BaseViewModel
{
public BaseViewModel ViewModel { get; set; }
public MainViewModel()
{
ViewModel = new LoginViewModel();
}
public ICommand DisplayVC { get { return new RelayCommand(DisplayVCV); } }
public void DisplayVCV()
{
ViewModel = new VotingCardViewModel();
MessageBox.Show("DisplayVCCommandExecuted");
}
}
Your ViewModel property implementation doesn't raise a PropertyChanged event when the value changes. This is usually done via an INotifyPropertyChanged implementation. Because of that, your view doesn't get notified that something has changed.
In your case, this means that you need a backing field for your ViewModel property and implement your ViewModel property similar to this:
private BaseViewModel _viewModel;
public BaseViewModel ViewModel
{
get { return _viewModel; }
set
{
if(_viewModel != value)
{
_viewModel = value;
OnPropertyChanged("ViewModel");
}
}
}
Since you are already deriving from BaseViewModel I assume that the method OnPropertyChanged (or some method with a similar name) is implemented there. It is also quite common that you don't have to specify the property name ("ViewModel") as an argument, since lots of implementations use the [CallerMemberName] attribute for this purpose.

Get collection from subusercontrol in WPF

I have
<Window x:Class="Repo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Repo="clr-namespace:Repo" Title="Window1" Height="300" Width="300">
<Grid>
<Button Click="SaVeEverythingInDatabase></Button>
<Repo:UserControlTasks/>
</Grid>
</Window>
public class UserControlTasks:userControl
public partial class UserControlTasks: UserControl
{
public UserControlTasks()
{
InitializeComponent();
LoadView();
}
private void LoadView()
{
this.lbTasks.ItemsSource = new TaskModelView();//collectionOfTasks
}
How to get collection from lbTasks in UserControlTasks when I click button on MainWindow?
I must add that I this collection is a part of instances of class Student which is datacontext of MainWindow.
Create TaskModelView in MainWindow class and assign it to Button control and UserControlTasks control. You will need to add a dependecy property for this to UserControlTasks.

Categories

Resources