I am trying to let the user choose in a combobox in the datagrid, but can not find the correct approach. I have tried using both binding and x:bind. What would be the best approach? I would imagine the following code to be correct, but I am missing something.
ViewModel
public partial class CustomerModel : ObservableObject
{
private ObservableCollection<DataType> _objects;
public ObservableCollection<DataType> Objects
{
get => _objects;
set => SetProperty(ref _objects, value);
}
private ObservableCollection<string> _field;
public ObservableCollection<string> Field
{
get => _field;
set => SetProperty(ref _field, value);
}
public CustomerModel()
{
Objects = new();
Field = new ObservableCollection<string> { "Test", "Test" };
}
public class DataType : ObservableObject
{
public int ID { get; set; }
public string Name { get; set; }
public string Caption { get; set; }
public bool Numeric { get; set; }
public DataType()
{
}
}
}
.xaml
<controls:DataGrid
x:Name="dataGrid1" KeyDown="dataGrid1_KeyDown"
ItemsSource="{x:Bind Model.Objects}" AutoGenerateColumns="False" >
<controls:DataGrid.Columns>
<controls:DataGridComboBoxColumn Header="Field" ItemsSource="{x:Bind Model.Field}" Tag="Field"/>
</controls:DataGrid.Columns>
</controls:DataGrid>
Updated code which is now working. Does this look okay?
public partial class CustomerModel : ObservableObject
{
public enum Choices { A, B, C }
[ObservableProperty]
private ObservableCollection<DataType> _objects;
public CustomerModel()
{
Objects = new();
var data = new DataType();
Objects.Add(data);
}
public static Choices[] ChoicesOptions { get; } = Enum.GetValues<Choices>();
public partial class DataType : ObservableObject
{
public int ID { get; set; }
public string Name { get; set; }
public string Caption { get; set; }
public bool Numeric { get; set; }
[ObservableProperty]
private Choices _choice;
}
}
.xaml
<controls:DataGridComboBoxColumn Header="Field" Binding="{Binding Choice}" ItemsSource="{x:Bind local:CustomerModel.ChoicesOptions, Mode=OneTime}" Tag="Field"
Also, I notice you instantiate the viewmodel in the codebehind file, is this necessary? I do not:
public sealed partial class DataGridPage : Page
{
public DataGridPage()
{
this.InitializeComponent();
}
}
Try making the Enum
options static
, just like Function Bindings. For example:
public enum Sections { A, B, C }
public partial class Item : ObservableObject
{
[ObservableProperty]
private string _name = string.Empty;
[ObservableProperty]
private Sections _section;
}
public partial class SomeViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<Item> _items = [];
public SomeViewModel()
{
Items.Add(new Item { Name = "Item 1", Section = Sections.A });
Items.Add(new Item { Name = "Item 2", Section = Sections.B });
Items.Add(new Item { Name = "Item 3", Section = Sections.C });
}
public static Section[] SectionOptions { get; } = Enum.GetValues<SectionOptions>();
}
public sealed partial class SomePage : Page
{
public SomePage()
{
InitializeComponent();
}
public SomeViewModel ViewModel { get; } = new();
}
Then you can bind it with x:Bind
:
<Page
x:Class="DataGridDemo.SomePage"
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:local="using:DataGridDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="using:CommunityToolkit.WinUI.UI.Controls"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<toolkit:DataGrid
AutoGenerateColumns="False"
ItemsSource="{x:Bind ViewModel.Items}">
<toolkit:DataGrid.Columns>
<toolkit:DataGridComboBoxColumn
Binding="{Binding Section}"
Header="Section"
ItemsSource="{x:Bind local:SomeViewModel.SectionOptions}" />
</toolkit:DataGrid.Columns>
</toolkit:DataGrid>
</Page>
BTW, as you are using the ObservableObject, you should be using the ObservableProperty attribute instead of implementing properties by yourself.