Get Started With Toolbars
This tutorial shows how to use the Eremex Toolbars library to create a toolbar UI from scratch. It introduces controls to implement the toolbar UI, and demonstrates main toolbar settings.
The tutorial creates a toolbar UI for two text editors placed in the center of the window. The toolbar UI consists of the main menu, status bar, and regular toolbars that display various items: buttons, check buttons, in-place editors, sub-menus, and text items.
All but one of the toolbars are docked to the edges of the window. These toolbars have commands that work with the first text editor. One toolbar (standalone toolbar) is placed between the text editors. It provides commands for the second text editor.
The tutorial also shows how to associate a text editor with a context menu from the Toolbars&Menu library.
1. Create a ToolbarManager Component
Start by defining a ToolbarManager
component in XAML.
xmlns:mxb="https://schemas.eremexcontrols.net/avalonia/bars"
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<mxb:ToolbarManager IsWindowManager="True">
<Grid RowDefinitions="Auto, *, Auto, *, Auto" ColumnDefinitions="Auto, *, Auto">
<TextBox Grid.Row="1" Grid.Column="1" x:Name="textBox1"
Text="Text Editor" AcceptsReturn="True"/>
<TextBox x:Name="textBox2" Grid.Row="3" Grid.Column="1"
Text="Text Editor #2" AcceptsReturn="True"/>
</Grid>
</mxb:ToolbarManager>
ToolbarManager
is the main component that manages toolbars, context menus, and menu items. The component processes keyboard shortcuts, invokes commands associated with corresponding items, maintains toolbar runtime customization, and performs bar UI serialization and deserialization.
The ToolbarManager
component should wrap the client control (controls) for which a toolbar UI is created.
2. Create Toolbar Containers
To allow a toolbar to be docked at a specific position in a window/UserControl, first create a toolbar container (ToolbarContainerControl
). A toolbar container is a control that displays toolbars in the docked state, and maintains toolbar drag-and-drop operations.
In XAML, create four toolbar containers (ToolbarContainerControl
objects) along the top, bottom, left and right edges of the window. You will then be able to dock toolbars at these positions.
xmlns:mxb="https://schemas.eremexcontrols.net/avalonia/bars"
<mxb:ToolbarManager IsWindowManager="True">
<Grid RowDefinitions="Auto, *, Auto, *, Auto" ColumnDefinitions="Auto, *, Auto">
<mxb:ToolbarContainerControl DockType="Top" Grid.ColumnSpan="3"/>
<mxb:ToolbarContainerControl DockType="Left" Grid.Row="1"
Grid.Column="0" Grid.RowSpan="3" />
<TextBox Grid.Row="1" Grid.Column="1" x:Name="textBox1"
Text="Text Editor" AcceptsReturn="True"/>
<TextBox x:Name="textBox2" Grid.Row="3" Grid.Column="1"
Text="Text Editor #2" AcceptsReturn="True"/>
<mxb:ToolbarContainerControl DockType="Right" Grid.Row="1"
Grid.Column="2" Grid.RowSpan="3"/>
<mxb:ToolbarContainerControl DockType="Bottom"
Grid.Row="4" Grid.ColumnSpan="3"/>
</Grid>
</mxb:ToolbarManager>
Toolbar Container Options
A ToolbarContainerControl
's main setting is ToolbarContainerControl.DockType
, which specifies how the container is docked to its parent. You can set the DockType
property to Left
, Right
, Top
, Bottom
, and Standalone
.
The DockType
setting determines the container's border visibility, and default alignment of nested toolbars. For instance, if a container's DockType
option is Left
, the container draws a border at its right edge, and arranges nested toolbars vertically. The image below demonstrates the toolbar container that has its DockType
option set to Left
. The child toolbars are oriented vertically according to the DockType
setting.
3. Create Toolbars
Add toolbars (Toolbar
objects) to required toolbar containers.
xmlns:mxb="https://schemas.eremexcontrols.net/avalonia/bars"
<mxb:ToolbarManager IsWindowManager="True">
<Grid RowDefinitions="Auto, *, Auto, *, Auto" ColumnDefinitions="Auto, *, Auto">
<mxb:ToolbarContainerControl DockType="Top" Grid.ColumnSpan="3">
<mxb:Toolbar x:Name="MainMenu" ToolbarName="Main Menu" DisplayMode="MainMenu">
</mxb:Toolbar>
<mxb:Toolbar x:Name="EditToolbar" ToolbarName="Edit"
ShowCustomizationButton="True">
</mxb:Toolbar>
<mxb:Toolbar x:Name="FontToolbar" ToolbarName="Font"
ShowCustomizationButton="True">
</mxb:Toolbar>
</mxb:ToolbarContainerControl>
<mxb:ToolbarContainerControl DockType="Left" Grid.Row="1"
Grid.Column="0" Grid.RowSpan="3">
<mxb:Toolbar x:Name="TextEditingToolbar" ToolbarName="Text Editing"
ShowCustomizationButton="True" >
</mxb:Toolbar>
</mxb:ToolbarContainerControl>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="textBox1" Text="Text Editor"
AcceptsReturn="True" CornerRadius="0" FontFamily="Arial" FontSize="20"/>
<TextBox x:Name="textBox2" Grid.Row="3" Grid.Column="1" Text="Text Editor #2"
AcceptsReturn="True" CornerRadius="0" FontFamily="Arial" FontSize="20"/>
<mxb:ToolbarContainerControl DockType="Right" Grid.Row="1"
Grid.Column="2" Grid.RowSpan="3"/>
<mxb:ToolbarContainerControl DockType="Bottom" Grid.Row="4" Grid.ColumnSpan="3">
<mxb:Toolbar DisplayMode="StatusBar" ToolbarName="Status Bar" x:Name="StatusBar">
</mxb:Toolbar>
</mxb:ToolbarContainerControl>
</Grid>
</mxb:ToolbarManager>
The snippet above populates three toolbar containers with toolbars, and leaves one toolbar container empty. Users will be able to drag and drop toolbars to any of the four toolbar containers at runtime.
Specify the Main Menu and Status Bar
To indicate that a toolbar is the main menu or status bar, set its Toolbar.DisplayMode
property to MainMenu
and StatusBar
, respectively.
<mxb:Toolbar x:Name="MainMenu" ToolbarName="Main Menu" DisplayMode="MainMenu">
</mxb:Toolbar>
The main menu and status bar have distinctive appearance settings and behavior. For instance, they do not contain a drag handle, so they cannot be dragged by users. A user cannot hide the main menu and status bar at runtime.
Toolbar Options
Toolbar
objects expose many options to customize their view, layout, and behavior settings. Some of these options include:
ToolbarName
— The toolbar's display name. Toolbar names are displayed in the Customization window and also when a toolbar is in the floating state.ShowCustomizationButton
— Specifies the visibility of the Customization button used to activate customization mode and open the Customization window.AllowDragToolbar
— Specifies the visibility of a drag handle that enables users to drag the toolbar.DockType
— This property allows you to move a toolbar to a specific toolbar container in code-behind, or make the toolbar floating.StretchToolbar
— Enables toolbar stretching. In this mode, no other toolbar can be displayed in the same row.WrapItems
— Enables a multiple row layout for a toolbar.
4. Create Toolbar Items
The next step is to populate toolbars with toolbar items: regular buttons, check buttons, in-place editors, sub-menus, and text items. Toolbar items are encapsulated by classes derived from the ToolbarItem
class, which exposes common toolbar item options.
This tutorial creates the following toolbar items:
ToolbarButtonItem
A regular button that fires a command specified by the Command
property.
<mxb:Toolbar x:Name="EditToolbar" ToolbarName="Edit" ShowCustomizationButton="True" >
<mxb:ToolbarButtonItem Header="Cut" Command="{Binding #textBox1.Cut}"
IsEnabled="{Binding #textBox1.CanCut}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditCut.svg'}"
Category="Edit"/>
<mxb:ToolbarButtonItem Header="Copy" Command="{Binding #textBox1.Copy}"
IsEnabled="{Binding #textBox1.CanCopy}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditCopy.svg'}"
Category="Edit"/>
</mxb:Toolbar>
Common Toolbar Item Options
The base ToolbarItem
class provides common options inherited by all toolbar items. Some of these options include:
Alignment
— The item's alignment within the toolbar.Category
— A category to which the item belongs. Categories are used to organize items into logical groups within the Customization window.Command
— A command executed when the button is clicked.CommandParameter
— A command parameter passed to the specified command.DisplayMode
— Gets whether to display only the glyph, the header, or both.Header
— The item's display text.Glyph
— The item's image.GlyphAlignment
— The glyph alignment relative to the item's header.GlyphSize
— The glyph display size.ShowSeparator
— Allows you to display a separator before the item.
Assign a Dropdown Control/Menu to a ToolbarButtonItem
You can associate a dropdown control/menu with a ToolbarButtonItem
object. The dropdown is activated by a click on the built-in dropdown arrow or the item itself (see the DropDownArrowVisibility
option below for more information).
Let's associate the Paste button (ToolbarButtonItem
) with a dropdown menu. The dropdown menu will display the Paste and Paste As commands.
<mxb:ToolbarButtonItem Header="Paste" Command="{Binding #textBox1.Paste}"
IsEnabled="{Binding #textBox1.CanPaste}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditPaste.svg'}"
Category="Edit">
<mxb:ToolbarButtonItem.DropDownControl>
<mxb:PopupMenu>
<mxb:ToolbarButtonItem Header="Paste" Command="{Binding #textBox1.Paste}"
IsEnabled="{Binding #textBox1.CanPaste}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditPaste.svg'}"/>
<mxb:ToolbarButtonItem Header="Paste As"
Command="{Binding PasteAsCommand}"
IsEnabled="{Binding #textBox1.CanPaste}"/>
</mxb:PopupMenu>
</mxb:ToolbarButtonItem.DropDownControl>
</mxb:ToolbarButtonItem>
The following properties are used to specify a dropdown control and the way it is displayed:
DropDownControl
— Gets or sets a dropdown control/menu associated with the item. This property acceptsPopupContainer
andPopupMenu
objects.DropDownArrowVisibility
— Specifies whether the item displays a dropdown arrow used to invoke the associated dropdown control. Supported options include:ShowArrow
— The dropdown arrow is visible. The item and arrow act as a single button. A click on them displays an associated dropdown control.ShowSplitArrow
orDefault
— The dropdown arrow is visible. It acts as a separate button embedded in the item. A click on the dropdown arrow invokes the associated dropdown control. A click on the item invokes its command.Hide
— The dropdown arrow is hidden. A click on the item invokes the dropdown control.
ToolbarMenuItem
A button that invokes a sub-menu. To add items to the sub-menu, define them between the start and end <ToolbarMenuItem>
tags in XAML markup, or add them to the Items
collection.
<mxb:Toolbar x:Name="MainMenu" ToolbarName="Main Menu" DisplayMode="MainMenu">
<mxb:ToolbarMenuItem Header="File" Category="File">
<mxb:ToolbarButtonItem Header="New"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/FileNew.svg'}"
Category="File" Command="{Binding NewFileCommand}"/>
<mxb:ToolbarButtonItem Header="Open"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/FileOpen.svg'}"
Category="File" Command="{Binding OpenFileCommand}"/>
<mxb:ToolbarButtonItem Header="Print"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/FilePrint.svg'}"
Category="File" Command="{Binding PrintCommand}" ShowSeparator="True"/>
</mxb:ToolbarMenuItem>
</mxb:Toolbar>
You can add all supported item types to the sub-menu.
ToolbarCheckItem
A check button that can be either in the normal or pressed state.
<mxb:Toolbar x:Name="FontToolbar" ToolbarName="Font" ShowCustomizationButton="False">
<mxb:ToolbarCheckItem Header="Bold"
IsChecked="{Binding #textBox1.FontWeight,
Converter={local:BoolToFontWeightConverter}, Mode=TwoWay}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/FontBold.svg'}"
Category="Font"/>
...
</mxb:Toolbar>
ToolbarCheckItem Options
IsChecked
— Gets or sets the button's check state.CheckedChanged
— The event that fires when the checked state changes.
ToolbarEditorItem
An item that allows you to embed an Eremex editor in a toolbar or menu.
<mxb:Toolbar x:Name="FontToolbar" ToolbarName="Font" ShowCustomizationButton="False">
<mxb:ToolbarEditorItem Header="Font:" EditorWidth="150" Category="Font"
EditorValue="{Binding #textBox1.FontFamily,
Converter={local:FontNameToFontFamilyConverter}}">
<mxb:ToolbarEditorItem.EditorProperties>
<mxe:ComboBoxEditorProperties
ItemsSource="{Binding $parent[local:MainWindow].Fonts}"
IsTextEditable="False"/>
</mxb:ToolbarEditorItem.EditorProperties>
</mxb:ToolbarEditorItem>
...
</mxb:Toolbar>
ToolbarEditorItem Options
EditorValue
— Allows you to set and read the inplace editor's value.EditorProperties
— Specifies the type of the editor to be embedded in a toolbar/menu. In the code snippet above, theEditorProperties
property is set to aComboBoxEditorProperties
object. This object contains settings specific to theComboBoxEditor
control. A toolbar will automatically create aComboBoxEditor
control at runtime from the specifiedComboBoxEditorProperties
object.
ToolbarTextItem
A text label. A click on a text label does not raise any action (command).
<mxb:Toolbar DisplayMode="StatusBar" ToolbarName="Status Bar"
x:Name="StatusBar" ShowCustomizationButton="False">
<mxb:ToolbarTextItem Name="tbTextItem1" Alignment="Far"
ShowSeparator="True" ShowBorder="False" Category="Info"
CustomizationName="Position Info"
Header="{Binding $parent[local:MainWindow].LineNumber}"/>
</mxb:Toolbar>
ToolbarTextItem Options
SizeMode
— Gets or sets whether the item is auto-sized to fit its content, or stretched to occupy the available space in the toolbar.ShowBorder
— Gets or sets whether to display a border around the item.
Other Toolbar Item Types
The Toolbars library also supports other toolbar item types that are not demonstrated in this tutorial:
ToolbarItemGroup
— A group of toolbar items.ToolbarCheckItemGroup
— A group of check buttons. Use it to create a group of mutually exclusive check items, or a group that supports selecting multiple items at a time.
See the following topic for more information: Toolbar Items.
5. Create a Standalone Toolbar
You can place toolbars at any position within a window, not only along its edges. For instance, you can place toolbars with commands next to a target control. These toolbars are called 'standalone', because they reside within 'standalone' toolbar containers.
To create a standalone toolbar, do the following:
Create a toolbar container (
ToolbarContainerControl
) at the required position. Set itsDockType
property toStandalone
.Standalone toolbar containers do not have borders.
Add a toolbar with commands to this toolbar container.
The code below displays a standalone toolbar between two text editors. The toolbar's Select All command selects text in the second text editor.
<mxb:ToolbarManager Name="toolbarManager1" IsWindowManager="True" >
<Grid RowDefinitions="Auto, *, Auto, *, Auto" ColumnDefinitions="Auto, *, Auto">
...
<TextBox Grid.Row="1" Grid.Column="1" x:Name="textBox1" Text="Text Editor"
AcceptsReturn="True"/>
<mxb:ToolbarContainerControl DockType="Standalone" Grid.Row="2" Grid.Column="1">
<mxb:Toolbar x:Name="TextEditor2Toolbar" ToolbarName="Standalone Toolbar"
ShowCustomizationButton="True" AllowDragToolbar="true" >
<mxb:ToolbarButtonItem Header="Select All"
Command="{Binding #textBox2.SelectAll}" Category="TextEditor2 Toolbar" />
<mxb:ToolbarButtonItem Header="Make Toolbar Floating"
Command="{Binding $parent[local:MainWindow].MakeToolbar2Floating}"
ShowSeparator="True"
Category="TextEditor2 Toolbar"/>
</mxb:Toolbar>
</mxb:ToolbarContainerControl>
<TextBox x:Name="textBox2" Grid.Row="3" Grid.Column="1" Text="Text Editor #2"
AcceptsReturn="True"/>
</Grid>
</mxb:ToolbarManager>
6. Assign a Context Menu to a Text Editor
To specify a context menu for a control, create a PopupMenu
object and assign it to the target control using the ToolbarManager.ContextPopup
attached property. Toolbar items of any type can be added to popup menus.
<TextBox Grid.Row="1" Grid.Column="1" x:Name="textBox1" Text="Text Editor"
AcceptsReturn="True" CornerRadius="0" FontFamily="Arial" FontSize="20" >
<mxb:ToolbarManager.ContextPopup>
<mxb:PopupMenu ShowIconStrip="True" Header="Text Box Menu" ShowHeader="True">
<mxb:ToolbarButtonItem Header="Undo" HotKeyDisplayString="Ctrl+Z"
Command="{Binding #textBox1.Undo}" IsEnabled="{Binding #textBox1.CanUndo}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditUndo.svg'}"
Category="Edit"/>
<mxb:ToolbarButtonItem Header="Redo" HotKeyDisplayString="Ctrl+Y"
Command="{Binding #textBox1.Redo}" IsEnabled="{Binding #textBox1.CanRedo}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditRedo.svg'}"
Category="Edit"/>
<mxb:ToolbarSeparatorItem/>
<mxb:ToolbarButtonItem Header="Clear" Command="{Binding #textBox1.Clear}"
HotKeyDisplayString="Ctrl+Q" Category="Edit"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditDelete.svg'}"/>
</mxb:PopupMenu>
</mxb:ToolbarManager.ContextPopup>
</TextBox>
PopupMenu Options
ContentRightIndent
— Specifies the width of the empty space to the right of menu items' text.Header
— Allows you to specify a menu header.ShowHeader
— Gets or sets whether the menu header is visible.ShowIconStrip
— Gets or sets whether to display a vertical strip of icons for menu items. A menu item's icon is specified by the item'sGlyph
property.
7. Specify Hotkeys for Toolbar Items
Use the ToolbarItem.HotKey
property to assign shortcuts to items.
<mxb:ToolbarButtonItem
Header="Clear" Command="{Binding #textBox1.Clear}" HotKey="Ctrl+Q"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditDelete.svg'}" Category="Edit"/>
The ToolbarManager
component's bounds define the default hotkey scope. If focus is within the hotkey scope, the ToolbarManager
can intercept and process hotkeys.
You can set the ToolbarManager.IsWindowManager
property to true
to expand the hotkey scope to the entire window. In this case, the ToolbarManager
registers hotkeys in the window, and it can handle hotkeys even if focus is beyond the ToolbarManager
's bounds.
See the following topic for more information: Toolbar Item Hotkeys.
8. Assign Tooltips to Toolbar Items
The ToolTip
property allows you to specify tooltips for toolbar items.
<mxb:ToolbarButtonItem Header="Cut" Command="{Binding #textBox1.Cut}"
IsEnabled="{Binding #textBox1.CanCut}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditCut.svg'}"
Category="Edit"
ToolTip.Tip="Cut Selection"/>
9. Make a Toolbar Floating
Let's make a toolbar floating in code-behind. Ensure that the target toolbar has a name, so you can access it. After you get the toolbar object, set its Toolbar.DockType
property to Floating
. Use the Toolbar.FloatingPosition
property to set the floating toolbar's location.
EditToolbar.DockType = Eremex.AvaloniaUI.Controls.Bars.MxToolbarDockType.Floating;
EditToolbar.FloatingPosition = new PixelPoint(200, 200);
To create a floating toolbar in XAML, define a Toolbar
object in the ToolbarManager.Toolbars
collection, and set the Toolbar.DockType
property to Floating
.
See the following topic for more information: Floating Toolbars.
10. Runtime
The Toolbars library supports toolbar customization by users at runtime. Run the application to see these features in action:
- Bar drag-and-drop — Toolbars display drag handles that allow you to rearrange bars.
- Quick toolbar customization — You can quickly move items within and between bars using drag-and-drop by holding the Alt key down.
- Customization Mode and Customization Window — Click a toolbar's Customization button ('...'), and then select the 'Customize' command. Activation of customization mode displays the Customization Window:
In customization mode, you can do the following:
- Hide and restore toolbars.
- Create and manage user toolbars.
- Hide, restore and rearrange toolbar items between bars and sub-menus.
11. Complete Code
Below you can find the complete code of this tutorial.
The SVG images used in this example are placed in the bars_sample/Images/Toolbars
folder. They have the Build Action
property set to AvaloniaResource
.
MainWindow.axaml:
<Window xmlns="https://github.com/avaloniaui"
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:mxe="https://schemas.eremexcontrols.net/avalonia/editors"
xmlns:mxb="https://schemas.eremexcontrols.net/avalonia/bars"
xmlns:mx="https://schemas.eremexcontrols.net/avalonia"
xmlns:col="using:System.Collections"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:BarsSample"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="BarsSample.MainWindow"
Title="Toolbars Sample"
Width="600" Height="400"
>
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<mxb:ToolbarManager Name="toolbarManager1" IsWindowManager="True" >
<Grid RowDefinitions="Auto, *, Auto, *, Auto" ColumnDefinitions="Auto, *, Auto">
<mxb:ToolbarContainerControl DockType="Top" Grid.ColumnSpan="3">
<mxb:Toolbar x:Name="MainMenu" ToolbarName="Main Menu" DisplayMode="MainMenu" >
<mxb:ToolbarMenuItem Header="File" Category="File">
<mxb:ToolbarButtonItem Header="New"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/FileNew.svg'}"
Category="File"
Command="{Binding NewFileCommand}"/>
<mxb:ToolbarButtonItem Header="Open"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/FileOpen.svg'}"
Category="File"
Command="{Binding OpenFileCommand}"/>
<mxb:ToolbarButtonItem Header="Print"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/FilePrint.svg'}"
Category="File"
Command="{Binding PrintCommand}" ShowSeparator="True"/>
</mxb:ToolbarMenuItem>
<mxb:ToolbarMenuItem Header="Edit" Category="Edit" >
<mxb:ToolbarButtonItem Header="Cut"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditCut.svg'}"
Category="Edit"
Command="{Binding #textBox1.Cut}" IsEnabled="{Binding #textBox1.CanCut}"/>
<mxb:ToolbarButtonItem Header="Copy"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditCopy.svg'}"
Category="Edit"
Command="{Binding #textBox1.Copy}" IsEnabled="{Binding #textBox1.CanCopy}"/>
<mxb:ToolbarButtonItem Header="Paste"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditPaste.svg'}"
Category="Edit"
Command="{Binding #textBox1.Paste}" IsEnabled="{Binding #textBox1.CanPaste}"/>
</mxb:ToolbarMenuItem>
<mxb:ToolbarButtonItem Header="About" Category="Options" ShowSeparator="True"
Alignment="Far" Command="{Binding AboutCommand}"/>
</mxb:Toolbar>
<mxb:Toolbar x:Name="EditToolbar" ToolbarName="Edit" ShowCustomizationButton="True" >
<mxb:ToolbarButtonItem Header="Cut" Command="{Binding #textBox1.Cut}"
IsEnabled="{Binding #textBox1.CanCut}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditCut.svg'}"
Category="Edit"/>
<mxb:ToolbarButtonItem Header="Copy" Command="{Binding #textBox1.Copy}"
IsEnabled="{Binding #textBox1.CanCopy}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditCopy.svg'}"
Category="Edit"/>
<mxb:ToolbarButtonItem Header="Paste"
Command="{Binding #textBox1.Paste}"
IsEnabled="{Binding #textBox1.CanPaste}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditPaste.svg'}"
Category="Edit"
DropDownArrowVisibility="ShowArrow" DropDownArrowAlignment="Default">
<mxb:ToolbarButtonItem.DropDownControl>
<mxb:PopupMenu>
<mxb:ToolbarButtonItem Header="Paste"
Command="{Binding #textBox1.Paste}"
IsEnabled="{Binding #textBox1.CanPaste}"/>
<mxb:ToolbarButtonItem Header="Paste As"
Command="{Binding PasteAsCommand}"
IsEnabled="{Binding #textBox1.CanPaste}"/>
</mxb:PopupMenu>
</mxb:ToolbarButtonItem.DropDownControl>
</mxb:ToolbarButtonItem>
</mxb:Toolbar>
<mxb:Toolbar x:Name="FontToolbar" ToolbarName="Font" ShowCustomizationButton="True" >
<mxb:ToolbarCheckItem Header="Bold"
IsChecked="{Binding #textBox1.FontWeight,
Converter={local:BoolToFontWeightConverter}, Mode=TwoWay}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/FontBold.svg'}"
Category="Font"/>
<mxb:ToolbarCheckItem Header="Italic"
IsChecked="{Binding #textBox1.FontStyle,
Converter={local:BoolToFontStyleConverter}, Mode=TwoWay}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/FontItalic.svg'}"
Category="Font"/>
<mxb:ToolbarEditorItem Header="Font:" IsVisible="" EditorWidth="150" Category="Font"
EditorValue="{Binding #textBox1.FontFamily,
Converter={local:FontNameToFontFamilyConverter}}">
<mxb:ToolbarEditorItem.EditorProperties>
<mxe:ComboBoxEditorProperties
ItemsSource="{Binding $parent[local:MainWindow].Fonts}"
IsTextEditable="False" PopupMaxHeight="145"/>
</mxb:ToolbarEditorItem.EditorProperties>
</mxb:ToolbarEditorItem>
</mxb:Toolbar>
</mxb:ToolbarContainerControl>
<mxb:ToolbarContainerControl DockType="Left" Grid.Row="1" Grid.Column="0"
Grid.RowSpan="3">
<mxb:Toolbar x:Name="TextEditingToolbar" ToolbarName="Text Editing"
ShowCustomizationButton="True" >
<mxb:ToolbarButtonItem Header="Undo" HotKeyDisplayString="Ctrl+Z"
Command="{Binding #textBox1.Undo}" IsEnabled="{Binding #textBox1.CanUndo}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditUndo.svg'}"
Category="Edit"/>
<mxb:ToolbarButtonItem Header="Redo" HotKeyDisplayString="Ctrl+Y"
Command="{Binding #textBox1.Redo}" IsEnabled="{Binding #textBox1.CanRedo}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditRedo.svg'}"
Category="Edit"/>
<mxb:ToolbarButtonItem Header="Clear" Command="{Binding #textBox1.Clear}"
HotKey="Ctrl+Q"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditDelete.svg'}"
Category="Edit"/>
</mxb:Toolbar>
</mxb:ToolbarContainerControl>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="textBox1" Text="Text Editor"
AcceptsReturn="True" CornerRadius="0" FontFamily="Arial" FontSize="20">
<mxb:ToolbarManager.ContextPopup>
<mxb:PopupMenu ShowIconStrip="True" Header="Text Box Menu" ShowHeader="True">
<mxb:ToolbarButtonItem Header="Undo" HotKeyDisplayString="Ctrl+Z"
Command="{Binding #textBox1.Undo}" IsEnabled="{Binding #textBox1.CanUndo}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditUndo.svg'}"
Category="Edit"/>
<mxb:ToolbarButtonItem Header="Redo" HotKeyDisplayString="Ctrl+Y"
Command="{Binding #textBox1.Redo}" IsEnabled="{Binding #textBox1.CanRedo}"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditRedo.svg'}"
Category="Edit"/>
<mxb:ToolbarSeparatorItem/>
<mxb:ToolbarButtonItem Header="Clear" Command="{Binding #textBox1.Clear}"
HotKeyDisplayString="Ctrl+Q" Category="Edit"
Glyph="{SvgImage 'avares://bars_sample/Images/Toolbars/EditDelete.svg'}"/>
</mxb:PopupMenu>
</mxb:ToolbarManager.ContextPopup>
</TextBox>
<mxb:ToolbarContainerControl DockType="Standalone" Grid.Row="2" Grid.Column="1">
<mxb:Toolbar x:Name="TextEditor2Toolbar" ToolbarName="Standalone Toolbar"
ShowCustomizationButton="True" AllowDragToolbar="true" >
<mxb:ToolbarButtonItem Header="Select All"
Command="{Binding #textBox2.SelectAll}" Category="TextEditor2 Toolbar"/>
<mxb:ToolbarButtonItem Header="Make Toolbar Floating"
Command="{Binding $parent[local:MainWindow].MakeToolbar2Floating}"
ShowSeparator="True"
Category="TextEditor2 Toolbar"/>
</mxb:Toolbar>
</mxb:ToolbarContainerControl>
<TextBox x:Name="textBox2" Grid.Row="3" Grid.Column="1" Text="Text Editor #2"
AcceptsReturn="True" CornerRadius="0" FontFamily="Arial" FontSize="20"/>
<mxb:ToolbarContainerControl DockType="Right" Grid.Row="1" Grid.Column="2"
Grid.RowSpan="3"/>
<mxb:ToolbarContainerControl DockType="Bottom" Grid.Row="4" Grid.ColumnSpan="3">
<mxb:Toolbar DisplayMode="StatusBar" ToolbarName="Status Bar" x:Name="StatusBar">
<mxb:ToolbarTextItem Name="tbTextItem1" Alignment="Far"
ShowSeparator="True" ShowBorder="False" Category="Info"
CustomizationName="Position Info"
Header="{Binding $parent[local:MainWindow].LineNumber}"/>
</mxb:Toolbar>
</mxb:ToolbarContainerControl>
</Grid>
</mxb:ToolbarManager>
</Window>
App.axaml:
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
RequestedThemeVariant="Light"
x:Class="BarsSample.App">
<Application.Resources>
<ResourceDictionary>
</ResourceDictionary>
</Application.Resources>
<Application.Styles>
<FluentTheme/>
<StyleInclude Source="avares://Eremex.Avalonia.Controls/Themes/Light/Theme.axaml"/>
<StyleInclude Source="avares://Eremex.Avalonia.Controls/Themes/Generic.axaml"/>
</Application.Styles>
</Application>
MainWindow.axaml.cs:
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Runtime.CompilerServices;
namespace BarsSample
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
textBox1.PropertyChanged += TextBox_PropertyChanged;
}
private void TextBox_PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == TextBox.CaretIndexProperty)
{
NotifyPropertyChanged("LineNumber");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
IReadOnlyList<string> fonts;
public IReadOnlyList<string> Fonts => fonts ??
(
fonts = FontManager.Current.SystemFonts.Select(x => x.Name).OrderBy(x => x).ToList()
);
[RelayCommand]
public void MakeToolbar2Floating()
{
TextEditor2Toolbar.DockType = Eremex.AvaloniaUI.Controls.Bars.MxToolbarDockType.Floating;
TextEditor2Toolbar.FloatingPosition = new PixelPoint(200, 200);
}
public string LineNumber
{
get
{
TextBox textBox = this.textBox1;
string text = textBox.Text;
string newLine = textBox.NewLine;
int currentIndex = 0;
int lineNumber = 0;
while (currentIndex <= textBox.CaretIndex)
{
lineNumber++;
int newLineIndex = text.IndexOf(newLine, currentIndex);
if (newLineIndex >= 0)
currentIndex = newLineIndex + newLine.Length;
else
break;
}
return "Line Number: " + lineNumber;
}
}
}
}
MainViewModel.cs:
using Avalonia.Data.Converters;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using CommunityToolkit.Mvvm.Input;
using Eremex.AvaloniaUI.Controls.Common;
using System;
using System.Globalization;
namespace BarsSample
{
public partial class MainViewModel : ViewModelBase
{
public MainViewModel()
{
}
[RelayCommand]
void About()
{
}
[RelayCommand]
void NewFile()
{
}
[RelayCommand]
void OpenFile()
{
}
[RelayCommand]
void Print()
{
}
}
public class BoolToFontWeightConverter : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((FontWeight)value) == FontWeight.Bold;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? FontWeight.Bold : FontWeight.Normal;
}
}
public class BoolToFontStyleConverter : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (FontStyle)value == FontStyle.Italic;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? FontStyle.Italic : FontStyle.Normal;
}
}
public class FontNameToFontFamilyConverter : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((FontFamily)value).Name;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return new FontFamily((string)value);
}
}
}