Sorry another beginner question.
I am trying to include an example from the Avalonia Documentation into my test project but I am getting stuck on trying to use MainWindowViewModel as well as code-behind for MainWindow (MainWindow.axaml.cs)
The example is the last one on https://docs.avaloniaui.net/docs/reference/controls/combobox which is unfortunately a little out of date.
<StackPanel Margin="20">
<ComboBox x:Name="fontComboBox" SelectedIndex="0"
Width="200" MaxDropDownHeight="300">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontFamily="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
using Avalonia.Controls;
using Avalonia.Media;
using System.Linq;
namespace AvaloniaControls.Views
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
fontComboBox.Items = FontManager.Current
.GetInstalledFontFamilyNames()
.Select(x => new FontFamily(x))
.OrderBy(x=>x.Name);
fontComboBox.SelectedIndex = 0;
}
}
}
The MainWindow has several other controls using MVVM view model
x:DataType="vm:MainWindowViewModel"
so whenever I type {Binding } rider helpfully reminds me with '(MainWindowViewModel). Path=' I have also learnt that when you use the term 'Binding' it must be to a Property - unless, perhaps, this is in the Code Behind. (Which is just doing my head in when trying to populate, in this case, a ComboBox.)
I think I have sucessfully changed the code-behind to... (at least in debug lFonts contains the data I expect)
public List<string> lFonts = new List<string>();
public MainWindow()
{
InitializeComponent();
ColourComboBox.ItemsSource = ColourBasesTxt;
ThemesComboBox.ItemsSource = Themes;
IFontCollection allFonts = FontManager.Current.SystemFonts;
foreach (var font in allFonts)
{
lFonts.Add(font.Name);
}
FontComboBox.ItemsSource = lFonts;
Now what I cant workout is how to link this to the xaml. The example code had
<ComboBox x:Name="fontComboBox" SelectedIndex="0"
Width="200" MaxDropDownHeight="300">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontFamily="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
in my code
<ComboBox x:Name="FontComboBox" Grid.Column="1" Grid.Row="3"
HorizontalAlignment="Left" HorizontalContentAlignment="Left" VerticalAlignment="Center"
MaxDropDownHeight="300" Width="150" Height="40" FontSize="16"
SelectedItem="{ Binding SelectedFont}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Now
<TextBlock Text="{Binding Name}" />
does not work because its trying to bind to MainWindowViewModel.Name
I have tried many crazy suggestions to get the data context within the DataTemplate to be the code-behind.
All but 1 did not pass the syntax check.
I cant refocus the whole ComboBox because the 'selectedItem' needs to be to a property in MainWindowViewModel (which it is).
The one that got close is
<TextBlock Text="{Binding ElementName=FontComboBox}" />
That actually ran but the ComboBox is filled with text 'Avalonia.Controls.ComboBox' line after line.
I am sorry I am so new to this method I even lack the language to formulate the question properly. Perhaps it is "For a list type control, how can you code it so as to have the 'source' (code supplying the list content) in one module and the 'SelectedItem' in a different module."
or maybe " how can you specify a DataContext to be the code behind module for any given xaml"
Thanks for your patience JC
Adding Full code for a cut down version. Any auto generated code has been left in
MainWindow.axaml
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Colour_Font_experiment3v1_snip.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:Colour_Font_experiment3v1_snip.Views"
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="450"
Width="900" Height="450"
x:Class="Colour_Font_experiment3v1_snip.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="Colour_Font_experiment3v1_snip">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainWindowViewModel/>
</Design.DataContext>
<StackPanel Orientation="Horizontal" Spacing="10" Background="#E6F5FC" >
<Border HorizontalAlignment="Left"
BorderBrush="Gray" BorderThickness="1"
CornerRadius="5" Padding="15 3">
<StackPanel Orientation="Vertical" Spacing="10">
<TextBlock Text="{Binding DummyPlaceHolder}" HorizontalAlignment="Left" VerticalAlignment="Center" Width="200" FontStyle="Italic"/>
<Grid ColumnDefinitions="*, 3*" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto" Margin="4"
ShowGridLines ="True">
<Label Content="" Grid.Column="0" Grid.Row="0" Height="1" />
<Label Content="Theme :" Grid.Column="0" Grid.Row="1" Height="50"/>
<Label Content="Font :" Grid.Column="0" Grid.Row="2" Height="50" />
<Label Content="Start Folder:" Grid.Column="0" Grid.Row="3" Height="50" />
<Label Content="" Grid.Column="0" Grid.Row="4" Height="50" />
<!-- see MainWindow.axaml.cs for ItemsSource ==> ThemesCombobox.ItemsSource = Themes; -->
<ComboBox x:Name="ThemesComboBox" Grid.Column="1" Grid.Row="1"
SelectedItem="{Binding SelectedTheme}"
Width="150" Height="40" >
</ComboBox>
<!-- and https://docs.avaloniaui.net/docs/reference/controls/combobox for use of textblock within ComboBox -->
<ComboBox x:Name="FontComboBox" Grid.Column="1" Grid.Row="2"
MaxDropDownHeight="300" Width="150" Height="40"
SelectedItem="{ Binding SelectedFont}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="xxxx" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBox Grid.Column="1" Grid.Row="3"
Text="{Binding StartFolder}"
Padding="10,8"
Width="400" Height="40" />
<Button Grid.Column="1" Grid.Row="4"
Command="{Binding SaveButtonClick}"
Content="Set / Save"
Height="40" Width="100" />
</Grid>
</StackPanel>
</Border>
</StackPanel>
</Window>
MainWindow.axaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Fonts.Inter;
using Avalonia.Media;
using Avalonia.Media.Fonts;
namespace Colour_Font_experiment3v1_snip.Views;
public partial class MainWindow : Window
{
private string[] Themes = new string[] { "Dark", "Light" };
private List<string> lFonts = new List<string>();
public MainWindow()
{
InitializeComponent();
ThemesComboBox.ItemsSource = Themes;
IFontCollection allFonts = FontManager.Current.SystemFonts;
foreach (var font in allFonts)
{
Console.WriteLine(font.Name);
lFonts.Add(font.Name);
}
Console.WriteLine($"{lFonts.Count} font Names loaded");
FontComboBox.ItemsSource = lFonts;
FontComboBox.SelectedIndex = 0;
}
}
MainWindowViewModel
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive;
using Avalonia;
using Avalonia.Interactivity;
using ReactiveUI;
using Romzetron.Avalonia;
namespace Colour_Font_experiment3v1_snip.ViewModels;
public class MainWindowViewModel : ViewModelBase
{
// *****************************************************************
private string _dummyPlaceHolder = "Under Construction!";
public string DummyPlaceHolder
{
get => _dummyPlaceHolder;
set => this.RaiseAndSetIfChanged(ref _dummyPlaceHolder, value);
}
public ReactiveCommand<Unit, Unit> SaveButtonClick { get; }
private string _selectedTheme = "Light";
public string SelectedTheme
{
get => _selectedTheme;
set => this.RaiseAndSetIfChanged(ref _selectedTheme, value);
}
private string _selectedFont;
public string SelectedFont
{
get => _selectedFont;
set => this.RaiseAndSetIfChanged(ref _selectedFont, value);
}
private string _startFolder = @"M:\Museum\ManagedCatalog";
public string StartFolder
{
get => _startFolder;
set => this.RaiseAndSetIfChanged(ref _startFolder, value);
}
// **********************************************************
// Constructor
public MainWindowViewModel()
{
SaveButtonClick = ReactiveCommand.Create(PerformSaveAction);
DummyPlaceHolder = "Current Colour Base is : 'redacted' " ;
}
private void PerformSaveAction()
{
Console.WriteLine("The \'Set / Save\' button was pressed.");
}
//*******************************************
private ColorTheme getCurrentTheme()
{
return GetRomzetronAvaloniaTheme().ColorTheme;
}
// **********************************************************
// JC added from https://github.com/Romzetron/Romzetron.Avalonia?tab=readme-ov-file
private static RomzetronTheme? GetRomzetronAvaloniaTheme()
{
// Get a reference to the current application.
if (Application.Current is not App app)
return null;
// Loop through the styles in the application.
foreach (var style in app.Styles)
{
// Return RomzetronTheme if it is found.
if (style is RomzetronTheme theme)
return theme;
}
return null;
}
}
And just to refocus. The issue is to get the xaml line
<TextBlock Text="xxxx" />
actually connected to lFonts
in the code behind
Thanks again
JC
your Item source in the ComboBox is list of strings not list of objects so you should bind to it directly as following
<TextBlock Text="{Binding .}" />