Caliburn.Micro - sorokinDev/WPF_CSharp_Issues_Features GitHub Wiki

Setting UP

  • File > New Project > New WPF Application.
  • Add nuget package Caliburn.Micro.
  • Delete MainWindow.xaml.
  • Create the Views and ViewModels folders.
  • Add new class MainShellViewModel(inherit from "Screen") to the ViewModels folder.
  • Add new window MainShellView to the Views folder.
  • Add new class Bootstrapper to the root folder.
    //Bootstrapper.cs
    class Bootstrapper : BootstrapperBase
    {
        private SimpleContainer container;

        public Bootstrapper()
        {
            Initialize();
        }

        protected override void Configure()
        {
            container = new SimpleContainer();
            container.Instance(container);

            container
                .Singleton<IWindowManager, WindowManager>()
                .Singleton<IEventAggregator, EventAggregator>();
            
            container
                .PerRequest<MainShellViewModel>();
                /*.PerRequest<OtherShellViewModel>(); //Other viewmodels*/
        }

        protected override void OnStartup(object sender, StartupEventArgs e)
        {
            DisplayRootViewFor<MainShellViewModel>();
        }

        protected override object GetInstance(Type service, string key)
        {
            return container.GetInstance(service, key);
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return container.GetAllInstances(service);
        }

        protected override void BuildUp(object instance)
        {
            container.BuildUp(instance);
        }

        protected override void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            e.Handled = false;
            MessageBox.Show(e.Exception.Message, "An error has occurred", MessageBoxButton.OK);
        }
    }
  • Remove StartupUri from the Application element in App.xaml.
  • Add Bootstrapper as a resource
    <!-- App.xaml -->
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <local:Bootstrapper x:Key="Bootstrapper" />
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

Add Fody injections for PropertyChanged

  • Install PropertyChanged.Fody from nuget
<!-- FodyWeavers.xml -->
<Weavers>
  <PropertyChanged EventInvokerNames="NotifyOfPropertyChange" />
</Weavers>
  • Add "[AddINotifyPropertyChangedInterface]" attribute to VM classes

Open new window

container.GetInstance<IWindowManager>().ShowWindow(container.GetInstance<OtherViewModel>());

Binding events

<TextBox Text="{Binding CodeSearchText, UpdateSourceTrigger=PropertyChanged }" 
cal:Message.Attach="[Event GotFocus] = [Action CodeSearchTextBoxGotFocus($dataContext)]; [Event TextChanged] = [Action CodeSearchTextChangedAsync($eventArgs)]" />

Tab control

<TabControl x:Name="Items" TabStripPlacement="Left">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Button cal:Message.Attach="CloseTab($dataContext)" Content="X" Padding="5,0,5,0" Margin="5" />
                        <TextBox Text="{Binding CodeSearchText, UpdateSourceTrigger=PropertyChanged }" Width="150" 
cal:Message.Attach="[Event GotFocus] = [Action CodeSearchTextBoxGotFocus($dataContext)]; [Event TextChanged] = [Action CodeSearchTextChangedAsync($eventArgs)]" />
                    </StackPanel>
                </DataTemplate>
            </TabControl.ItemTemplate>
        </TabControl>
    public class TabControlViewModel : Conductor<ItemViewModel>.Collection.OneActive
    {
        private SimpleContainer container;
        
        public CodeSearchTabsViewModel(SimpleContainer container)
        {
            this.container = container;
            ActivateItem(container.GetInstance<CodeSearchTabContentViewModel>());
        }

        public void CodeSearchTextBoxGotFocus(CodeSearchTabContentViewModel dc)
        {
            ActivateItem(dc);
            if(Items.IndexOf(dc) == (Items.Count - 1))
            {
                Items.Add(container.GetInstance<CodeSearchTabContentViewModel>());
            }
        }

        public void CloseTab(CodeSearchTabContentViewModel dc)
        {
            DeactivateItem(dc, true);
        }
    }
⚠️ **GitHub.com Fallback** ⚠️