I created a new C# WPF project based on https://www.codemag.com/Article/1905031/A-Design-Pattern-for-Building-WPF-Business-Applications-Part-1
with Caliburn Micro and Windsor Castle based on .NET 7.0 as target framework.
The Problem is: None of the Property Changes is updating the UI (The ugly gray InfoMessageArea should be hidden and a Text should appear while starting the App - as well as the WindowTitle that should reflect a change to "Test"). What am I missing here? The left list box correctly loads the implemented Modules using Windsor Castle, but the basic binding stuff is not working. And I would appreciate if anybody has an idea how the content of the window would "stretch" to full window's size as a side node.
I created a new ShellView, that is acting as the Main Window of the application.
The ShellViewModel derives from Conductor which has an ancestor Caliburn.Micro.PropertyChangedBase implementing INotifyPropertyChangedEx.
The ShellView.xaml code is as follows:
<Window x:Class="BM.App.Views.ShellView"
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:vm="clr-namespace:BM.App.ViewModels"
xmlns:local="clr-namespace:BM.App.Views"
mc:Ignorable="d"
d:DataContext="{x:Type vm:ShellViewModel}"
Title="{Binding WindowTitle}"
Height="450" Width="800"
WindowStartupLocation="CenterScreen"
Loaded="Window_Loaded">
<Window.Resources>
<vm:ShellViewModel x:Key="viewModel"
InfoMessageTitle="Please Wait While Loading Application..."
InfoMessage="Sample of Business Application Screens" />
</Window.Resources>
<Grid Style="{StaticResource contentAreaStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<ListBox x:Name="MenuItems" DisplayMemberPath="Caption" Grid.Column="0"/>
<ContentControl x:Name="CurrentView" Grid.Row="0" Grid.Column="1" Margin="2"/>
<!-- Informational Message Area -->
<Border Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="1" Panel.ZIndex="2"
Visibility="{Binding Path=IsInfoMessageVisible, Converter={StaticResource visibilityConverter}}" Style="{StaticResource infoMessageArea}">
<StackPanel>
<TextBlock FontSize="20" Text="{Binding Path=InfoMessageTitle}" />
<TextBlock FontSize="12" Text="{Binding Path=InfoMessage}" />
</StackPanel>
</Border>
<StatusBar x:Name="stbMain" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" MinWidth="500"></StatusBar>
</Grid>
The ShellView.xaml.cs as follows:
public partial class ShellView : Window
{
// Main window's view model class
private ShellViewModel _viewModel;
public ShellView()
{
InitializeComponent();
// Connect to instance of the view model created by the XAML
_viewModel = (ShellViewModel)this.Resources["viewModel"];
}
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
await LoadApplication();
// Turn off informational message area
_viewModel.ClearInfoMessages();
}
public async Task LoadApplication()
{
// INFO: This text is not visible in the InfoMessage Area
_viewModel.InfoMessage = "Loading application (method 1)...";
//INFO: the 5 seconds delay are successfully invoked.
//TODO: Load Stuff...
await Dispatcher.BeginInvoke(new Action(() => {
System.Threading.Thread.Sleep(5000);
}), DispatcherPriority.Background);
// INFO: Test will not be visible in the application's window!
_viewModel.WindowTitle = "Test";
// INFO: Neither Refresh() is updating the UI.
_viewModel.Refresh();
await Task.CompletedTask;
}
}
The ShellViewModel.cs Code:
using BM.Contracts;
using Caliburn.Micro;
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace BM.App.ViewModels
{
public class ShellViewModel : Conductor<object>
{
public ObservableCollection<ViewModelBase> OpenTabs { get; private set; } = new ObservableCollection<ViewModelBase>();
public ObservableCollection<ShellMenuItem> MenuItems { get; private set; } = new ObservableCollection<ShellMenuItem>();
private const string WindowTitleDefault = "mp Beleg Matching (LF | DATEV | SB)";
private string _windowTitle = WindowTitleDefault;
public ShellViewModel()
{
MenuItems = new ObservableCollection<ShellMenuItem>();
AddTabCommand = null;
CloseTabCommand = null;
_selectedMenuItem = null;
}
ICommand AddTabCommand;
ICommand CloseTabCommand;
private bool _IsInfoMessageVisible = true;
private string _InfoMessageTitle = string.Empty;
private string _InfoMessage = string.Empty;
public bool IsInfoMessageVisible
{
get { return _IsInfoMessageVisible; }
set
{
_IsInfoMessageVisible = value;
NotifyOfPropertyChange("IsInfoMessageVisible");
}
}
public string InfoMessage
{
get { return _InfoMessage; }
set
{
_InfoMessage = value;
if (!_IsInfoMessageVisible && !string.IsNullOrEmpty(value))
{
IsInfoMessageVisible = true;
}
NotifyOfPropertyChange("InfoMessage");
}
}
public string InfoMessageTitle
{
get { return _InfoMessageTitle; }
set
{
_InfoMessageTitle = value;
NotifyOfPropertyChange("InfoMessageTitle");
}
}
public void ClearInfoMessages()
{
InfoMessage = string.Empty;
InfoMessageTitle = string.Empty;
IsInfoMessageVisible = false;
}
public string WindowTitle
{
get { return _windowTitle; }
set
{
_windowTitle = value;
NotifyOfPropertyChange(() => WindowTitle);
}
}
private ShellMenuItem _selectedMenuItem;
public ShellMenuItem SelectedMenuItem
{
get { return _selectedMenuItem; }
set
{
if (_selectedMenuItem == value)
return;
_selectedMenuItem = value;
NotifyOfPropertyChange(() => SelectedMenuItem);
NotifyOfPropertyChange(() => CurrentView);
}
}
public object? CurrentView
{
get { return _selectedMenuItem?.ScreenViewModel; }
}
}
}
You do a mixture with code behind and MVVM. If you are using Caliburn, use MVVM. Castle Windsor is a container, so i dont know, i am using Ninject and Caliburn (last version).
Sample to display a splash screen during 3 sec and change the title of ShellViewModel: just create a WPF .NET project then:
Modify App.xaml:
Bootsrapper.cs:
SplashView.xaml:
SplashViewModel.cs
ShellView.xaml
And finally ShellViewModel.cs