Access UI controls between partial classes - wpf

In my XAML I have a Button, with a button click event. I initialize the component in my MainWindow class : RibbonWindow. I have a the Button Click function in a separate class, but error window gives me "FooApplication.MainWindow" does not contain a definition for fooBtn_Click", below is my code
namespace FooApplication1 {
public partial class MainWindow : RibbonWindow
{
public MainWindow()
{
InitializeComponent();
}
}
/* in another .cs class file located in the same project */
namespace FooApplication1
{
public partial class Jenny : MainWindow
{
public void btnApplyL_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello");
}
}
}
I tried to give Jenny a RibbonWindow partial, thinking it might be the issue, but gives error. What is wrong?

Your XAML file needs to point to the class responsible for the event handling via the class attribute.
x:Class="FooApplication1.Jenny"
Defining event handlers within the XAML forces the use of the class attribute as it will dictate where the handlers exist. You can still have the partial classes; it's just that the XAML needs to know which class is responsible for the event handling which modifying the class attribute will address.
In addition you will need to move the InitializeComponent(); call from the MainWindow class to the Jenny class.
public partial class Jenny : MainWindow
{
public Jenny()
{
InitializeComponent();
}
...
}

Related

DataContext of usercontrol in WPF

I'm new to WPF and I'm trying to start a little project with a maximum of good practice. I'm using MVVM and dependency injection.
I have a concern which seems to be easy to understand but i can't find an answer (at this step, DataContext is not very clear for me).
The UserControlView of type UserControl contains just a button for testing.
This is the app class :
public App()
{
IServiceCollection services = new ServiceCollection();
services.AddSingleton<MainWindow>();
services.AddSingleton<UserControlViewModel>();
services.AddSingleton<UserControlView>();
_serviceProvider = services.BuildServiceProvider();
}
The user control is included in the Main windows like that :
<Grid>
<views:UserControlView/>
</Grid>
Now, in the OnStartup overrided method :
protected override void OnStartup(StartupEventArgs e)
{
MainWindow = _serviceProvider.GetRequiredService<MainWindow>();
MainWindow.DataContext = _serviceProvider.GetRequiredService<PaymentMeansViewModel>();
MainWindow.Show();
}
Like that it works, my button is correctly binded to the command.
But what is strange for me is that I have to set the 'UserControlViewModel' as the DataContext of the Main Window.
Isn'it possible to bind it to the 'UserControlView', something like :
protected override void OnStartup(StartupEventArgs e)
{
MainWindow = _serviceProvider.GetRequiredService<MainWindow>();
UserControlView testUC = _serviceProvider.GetRequiredService<UserControlView>();
testUC.DataContext = _serviceProvider.GetRequiredService<UserControlViewModel>();
MainWindow.Show();
}
Thanks for help.
Finally I did it.
I think (I hope I'm right) that I understood.
First of all, let's begin with the basic.
A view must have a viewmodel to bind the properties. A usercontrol is a kind of view "encapsulated" in a view. Therefore a usercontrol must have its own viewmodel and the view must have its own viewmodel.
The datacontext of the MainWindow is set in the app onstartup method :
MainWindow = new MainWindow()
{
DataContext = new MainWindowViewModel()
};
MainWindow must implement INotifyPropertyChanged. All view models must implement this interface. We can create a base class which will be derived in the view models :
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged(string? propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The DataContext of the usercontrol must be explicit in the xaml of the MainWindow:
<Grid>
<views:UserControlView DataContext="{Binding CurrentViewModel}"/>
</Grid>
"CurrentViewModel" is a DataContext, then it's a ViewModel, and as it is binded, it must be a property of the MainViewModel.
public class MainWindowViewModel : ViewModelBase
{
public ViewModelBase CurrentViewModel { get; }
public MainWindowViewModel()
{
CurrentViewModel=new UserControlViewModel();
}
}
Hope it can help.

OnNavigatedTo is not called in TabControl when selecting tab when using PRISM regions

I have registered my views for the TabControl with Region manager and views are shown properly when tab is selected.
The problem is that when I select new tab item OnNavigatedTo is not called for that view or its view model.
I'm using PRISM 6.3
UPDATE
ViewModel
`public class ValuationViewModel : IViewModel, INavigationAware
{
private IRegionManager _regionManager;
public string Title { get; set; }
public ValuationViewModel(IRegionManager regionManager)
{
Title = "PERFORM VALUATION";
_regionManager = regionManager;
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
}`
View
`public partial class ValuationView : UserControl, IView
{
private IRegionManager _regionManager;
public ValuationView(ValuationViewModel viewModel)
{
InitializeComponent();
ViewModel = viewModel;
}
public IViewModel ViewModel
{
get
{
return (IViewModel)DataContext;
}
set
{
DataContext = value;
}
}
}`
Without code, nobody can give you the correct answer.
Its probably the best, if you show us your ViewModel for your "TabItem" View.
Assuming you registered your view and set your ViewModel in DataContext correctly, it could be possible that forget just a simple thing.
To manage your problem make sure you implemented the following things correctly:
Create a region for your TabControl
Register your view in that region
Make sure the DataContext is correctly set to your ViewModel
Make sure your ViewModel implemented INavigationAware
Update 1:
After testing a lot I found a simple answer unfortunately:
Members of INavigationAware (OnNavigatedTo, IsNavigationTarget & OnNavigatedFrom) are called when the NavigationService is navigating.
They aren't if you click on the TabItemHeader.
To solve your problem you have several options.
One option is to start a navigation request when the user click on the TabItemHeader ( bad approach).
In my opinion you should use the IActiveAware Interface ( https://msdn.microsoft.com/en-us/library/microsoft.practices.prism.iactiveaware(v=pandp.50).aspx).
It will solve your problem, because the navigation via RegionManager and the clicking on the TabItemHeader results in the same: INavigationAware.IsActive = true.
Now you are able to detect when your tab is shown or not and react.

caliburn micro: MVVM parent view and child view of parent need to deactivate child

I need some help with reaching my TicketViewModel with Caliburn micro using ContentControl. I want to reach the ticketView(Model) using a button in StartView. (and deactivating startView)
next picture are the interactions i want to have with their CM implementations
https://imgur.com/a/SluXZ
this is the app thus far
https://imgur.com/a/TncE0
The header and styleElements are of the ShellView. The center square is a contentcontrol. with default the startview in activated.
As you can see, I want to reach TicketsView using a button in startView(that itself is nested in a contentControl in ShellView), and using a a MenuItem in ShellView.
Code in Shellview
<ContentControl Grid.Column="1" Grid.Row="1" x:Name="ActiveItem"/>
Code in ShellViewModel
public class ShellViewModel : Conductor<object>
{
public ShellViewModel(){
ActivateItem(new StartViewModel());}
public void AlleTicketsPageLaden(){
ActivateItem(new AlleTicketsViewModel());}
Code in StartView <Button Content="Tickets" x:Name="StartTicketKnop"/>
Code In StartViewModel
public class StartViewModel : Conductor<object>
{
public void StartTicketKnop()
{
ActivateItem(new AlleTicketsViewModel());
}
You could do the following:
Create class ActivateWindow like this:
public static class ActivateWindow
{
public static ShellViewModel Parent;
public static void OpenItem(IScreen t)
{
Parent.ActivateItem(t);
}
}
And in your ShellViewModel constructor
public ShellViewModel()
{
ActivateWindow.Parent = this;
}
Now in any ViewModel you can do the folowing:
ActivateWindow.OpenItem(new YourViewModel());

Dependency injection with Unity on wpf MVVM application

I have been trying to set up dependency injection in a wpf application using Unity, but can't seem to fully understand how the views and viewmodels should be set up.
Have looked into another SO post --> Wpf Unity but can't seem to understand it quite yet. I have used Unity before, but just in a MVC application, so I know how to inject it in the contructors.
Here is my views and viewModels in the application.
Views:
MainWindow.xaml
BookingView.xaml
ContactDetailsView.xaml
ReservationsView.xaml
ViewModels:
MenuViewModel (MainWindow uses this viewModel)
BookingViewModel
ContactViewModel
ReservationsViewModel
My ViewModels all have Interfaces implemented, like IMenuViewModel, should the view also have an interface?
I guess that since the MainWindow is the starting point, it should be here to register the container right?
Update:
Have found something, but not sure if I have done it right. Here is what I have done so far!
1: Using startup method in app.cs
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
IUnityContainer container = new UnityContainer();
container.RegisterType<IViewMainWindowViewModel, MainWindow>();
container.RegisterType<IViewMainWindowViewModel, MenuViewModel>();
var mainWindow = container.Resolve<MainWindow>(); // Creating Main window
mainWindow.Show();
}
}
2: Remove uri from start up.
3: Make IViewMainWindowViewModel interface in MainWindow class, the interface is empty.
public interface IViewMainWindowViewModel
{
}
4: Make a reference to this interface in the MainWindow
public partial class MainWindow : Window, IViewMainWindowViewModel
{
public MainWindow(IViewMainWindowViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
5: Also for the MenuViewModel
public class MenuViewModel : IViewMainWindowViewModel
{
Code not shown!
}
This will not even start the application..
Update 2
My MainWindow class look like this:
public interface IViewMainWindowViewModel
{
}
public partial class MainWindow : Window, IViewMainWindowViewModel
{
public MainWindow(IViewMainWindowViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
App class now look like this:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
IUnityContainer container = new UnityContainer();
container.RegisterType<IViewMainWindowViewModel, MainWindow>();
container.RegisterType<IViewMainWindowViewModel, MenuViewModel>();
container.Resolve<MainWindow>().Show();
//Do the same actions for all views and their viewmodels
}
I get an exception on this line when running the application
container.Resolve<MainWindow>().Show();
Update 3
In my MenuViewModel it has two command which will open two views, do I then need to inject those views in the MenuViewModel's constructor or can you just make another empty interface between MenuViewModel and BookingView as an example?
Let me show an example with explanations just for your MainWindows, as for the rest views and viewmodels steps to do are the same.
At first, you should create a contract between View and ViewModel. It shoud be some interface and let it call IViewMainWindowViewModel (keep in mind that name has to be different for other view and viewModels, for example IViewBookingViewViewModel):
public interface IViewMainWindowViewModel
{
/*This interface should not have any methods or commands. It is just
contract between View and ViewModels and helps to decide to Unity
container what it should inject(appropriate viewModel to necessary
View)*/
}
then in your viewmodel we should implement this interface:
public MenuViewModel:IViewMainWindowViewModel
{}
The view should inject this interface MainWindows.xaml.cs:
public partial class MainWindows : UserControl, IContentAView
{
public MainWindows(IViewMainWindowViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
}
Delete StartupUri and override a method OnStartup in App.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
IUnityContainer container = new UnityContainer();
container.RegisterType<IViewMainWindowViewModel, MainWindow>();
container.RegisterType<IViewMainWindowViewModel, MainWindowViewModel >();
container.Resolve<MainWindow>().Show();
//Do the same actions for all views and their viewmodels
}

UserControl inherited from a base custom UserControl does not have the default size

I've got a strange problem...
I have a UserControl inherited from another custom base UserControl and the default size that I set in my UserControl are not maintained when the control renders. What is strange is that if I remove the inheritance (my UC inherits directly from UserControl), the rendered size is correct!
My inherited control is loaded into a panel at run-time.
panel.Controls.Add(new ucLanguageSelection());
These are my controls:
public partial class ucBaseControl : UserControl
{
public ucBaseControl()
{
InitializeComponent();
}
public virtual void Reset()
{
}
public new virtual void Update()
{
}
}
public partial class ucLanguageSelection : ucBaseControl
{
public ucLanguageSelection()
{
InitializeComponent();
}
}

Resources