I’m trying to apply a binding for my datagrid so that I can capture the change to the cells as it happens (as the user types), but for some reason, I can only get to trigger the PropertyChanged event after the cell loses its focus. The same works flawlessly with a regular Textbox, meaning that the OnNameChanged and OnNameChanging events are triggered as soon as the key is down. I was also able to properly make it work with the datagrid by adding a custom column with a Textbox in it, however everything regarding tab navigation among all the cells in the DataGrid became really cumbersome after taking that approach.
Is there a way to make this work using the DataGridTextColumn?
<code><Grid x:Name="ContentArea">
<TextBox Text="{x:Bind ViewModel.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<controls:DataGrid AutoGenerateColumns="False" Margin="0,50" ItemsSource="{x:Bind ViewModel.Parameters, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<controls:DataGrid.Columns>
<controls:DataGridCheckBoxColumn Header="" Width="40" Binding="{Binding IsEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" CanUserResize="False"/>
<controls:DataGridTextColumn Header="Parameter" Binding="{Binding Key, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
<controls:DataGridTextColumn Header="Value" Binding="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
<controls:DataGridTextColumn Header="Description" Binding="{Binding Description, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
</controls:DataGrid.Columns>
<code><Grid x:Name="ContentArea">
<TextBox Text="{x:Bind ViewModel.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<controls:DataGrid AutoGenerateColumns="False" Margin="0,50" ItemsSource="{x:Bind ViewModel.Parameters, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<controls:DataGrid.Columns>
<controls:DataGridCheckBoxColumn Header="" Width="40" Binding="{Binding IsEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" CanUserResize="False"/>
<controls:DataGridTextColumn Header="Parameter" Binding="{Binding Key, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
<controls:DataGridTextColumn Header="Value" Binding="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
<controls:DataGridTextColumn Header="Description" Binding="{Binding Description, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
</controls:DataGrid.Columns>
</controls:DataGrid>
</Grid>
</code>
<Grid x:Name="ContentArea">
<TextBox Text="{x:Bind ViewModel.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<controls:DataGrid AutoGenerateColumns="False" Margin="0,50" ItemsSource="{x:Bind ViewModel.Parameters, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<controls:DataGrid.Columns>
<controls:DataGridCheckBoxColumn Header="" Width="40" Binding="{Binding IsEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" CanUserResize="False"/>
<controls:DataGridTextColumn Header="Parameter" Binding="{Binding Key, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
<controls:DataGridTextColumn Header="Value" Binding="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
<controls:DataGridTextColumn Header="Description" Binding="{Binding Description, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
</controls:DataGrid.Columns>
</controls:DataGrid>
</Grid>
<code>using App1.Helpers;
using Windows.UI.ViewManagement;
public sealed partial class MainWindow : WindowEx
public MainViewModel? ViewModel { get; }
private Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue;
private UISettings settings;
AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets/WindowIcon.ico"));
Title = "AppDisplayName".GetLocalized();
// Theme change code picked from https://github.com/microsoft/WinUI-Gallery/pull/1239
dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
settings = new UISettings();
settings.ColorValuesChanged += Settings_ColorValuesChanged; // cannot use FrameworkElement.ActualThemeChanged event
ViewModel = App.GetService<MainViewModel>();
// this handles updating the caption button colors correctly when indows system theme is changed
private void Settings_ColorValuesChanged(UISettings sender, object args)
// This calls comes off-thread, hence we will need to dispatch it to current app's thread
dispatcherQueue.TryEnqueue(() =>
TitleBarHelper.ApplySystemThemeToCaptionButtons();
<code>using App1.Helpers;
using Windows.UI.ViewManagement;
using App1.ViewModels;
namespace App1;
public sealed partial class MainWindow : WindowEx
{
public MainViewModel? ViewModel { get; }
private Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue;
private UISettings settings;
public MainWindow()
{
InitializeComponent();
AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets/WindowIcon.ico"));
Content = null;
Title = "AppDisplayName".GetLocalized();
// Theme change code picked from https://github.com/microsoft/WinUI-Gallery/pull/1239
dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
settings = new UISettings();
settings.ColorValuesChanged += Settings_ColorValuesChanged; // cannot use FrameworkElement.ActualThemeChanged event
ViewModel = App.GetService<MainViewModel>();
}
// this handles updating the caption button colors correctly when indows system theme is changed
// while the app is open
private void Settings_ColorValuesChanged(UISettings sender, object args)
{
// This calls comes off-thread, hence we will need to dispatch it to current app's thread
dispatcherQueue.TryEnqueue(() =>
{
TitleBarHelper.ApplySystemThemeToCaptionButtons();
});
}
}
</code>
using App1.Helpers;
using Windows.UI.ViewManagement;
using App1.ViewModels;
namespace App1;
public sealed partial class MainWindow : WindowEx
{
public MainViewModel? ViewModel { get; }
private Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue;
private UISettings settings;
public MainWindow()
{
InitializeComponent();
AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets/WindowIcon.ico"));
Content = null;
Title = "AppDisplayName".GetLocalized();
// Theme change code picked from https://github.com/microsoft/WinUI-Gallery/pull/1239
dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
settings = new UISettings();
settings.ColorValuesChanged += Settings_ColorValuesChanged; // cannot use FrameworkElement.ActualThemeChanged event
ViewModel = App.GetService<MainViewModel>();
}
// this handles updating the caption button colors correctly when indows system theme is changed
// while the app is open
private void Settings_ColorValuesChanged(UISettings sender, object args)
{
// This calls comes off-thread, hence we will need to dispatch it to current app's thread
dispatcherQueue.TryEnqueue(() =>
{
TitleBarHelper.ApplySystemThemeToCaptionButtons();
});
}
}
<code>using System.Collections.ObjectModel;
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
namespace App1.ViewModels;
public partial class MainViewModel : ObservableRecipient
public ObservableCollection<ParameterViewModel> parameters;
Parameters = new ObservableCollection<ParameterViewModel>();
var Parameter = new ParameterViewModel() { Key = "", Value = "", Description = ""};
Parameter.PropertyChanged += Parameter_PropertyChanged;
Parameter.PropertyChanging += Parameter_PropertyChanging;
Parameters.Add(Parameter);
partial void OnNameChanged(string value)
partial void OnNameChanging(string value)
private void Parameter_PropertyChanged(object? sender, PropertyChangedEventArgs e)
private void Parameter_PropertyChanging(object? sender, PropertyChangingEventArgs e)
public partial class ParameterViewModel : ObservableRecipient
public string description;
<code>using System.Collections.ObjectModel;
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
namespace App1.ViewModels;
public partial class MainViewModel : ObservableRecipient
{
[ObservableProperty]
public string name;
[ObservableProperty]
public ObservableCollection<ParameterViewModel> parameters;
public MainViewModel()
{
Parameters = new ObservableCollection<ParameterViewModel>();
var Parameter = new ParameterViewModel() { Key = "", Value = "", Description = ""};
Parameter.PropertyChanged += Parameter_PropertyChanged;
Parameter.PropertyChanging += Parameter_PropertyChanging;
Parameters.Add(Parameter);
}
partial void OnNameChanged(string value)
{
}
partial void OnNameChanging(string value)
{
}
private void Parameter_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
}
private void Parameter_PropertyChanging(object? sender, PropertyChangingEventArgs e)
{
}
}
public partial class ParameterViewModel : ObservableRecipient
{
[ObservableProperty]
public string key;
[ObservableProperty]
public string value;
[ObservableProperty]
public string description;
}
</code>
using System.Collections.ObjectModel;
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
namespace App1.ViewModels;
public partial class MainViewModel : ObservableRecipient
{
[ObservableProperty]
public string name;
[ObservableProperty]
public ObservableCollection<ParameterViewModel> parameters;
public MainViewModel()
{
Parameters = new ObservableCollection<ParameterViewModel>();
var Parameter = new ParameterViewModel() { Key = "", Value = "", Description = ""};
Parameter.PropertyChanged += Parameter_PropertyChanged;
Parameter.PropertyChanging += Parameter_PropertyChanging;
Parameters.Add(Parameter);
}
partial void OnNameChanged(string value)
{
}
partial void OnNameChanging(string value)
{
}
private void Parameter_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
}
private void Parameter_PropertyChanging(object? sender, PropertyChangingEventArgs e)
{
}
}
public partial class ParameterViewModel : ObservableRecipient
{
[ObservableProperty]
public string key;
[ObservableProperty]
public string value;
[ObservableProperty]
public string description;
}
I tried setting up the PropertyChanged event for each Parameter added to the ObservableCollection within the MainViewModel, along with implementing the OnKeyChanged event within the ParameterViewModel, the result was the same.