You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Avalonia代码后置中DataContext为空,如何更新DataGrid?

Avalonia中通过DataContext动态配置DataGrid的问题

应用结构

视图

  • MainWindow
  • MainView
  • View1
  • View2

视图模型

  • MainViewModel

相关代码

MainWindow.xaml

<Window xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="using:Frontend.ViewModels"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:views="clr-namespace:Frontend.Views"
    mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
    x:Class="Frontend.Views.MainWindow"
    Icon="/Assets/avalonia-logo.ico"
    Title="Frontend">

    <views:MainView/>
</Window>

MainView.xaml

<UserControl 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:vm="clr-namespace:Frontend.ViewModels"
         xmlns:views="clr-namespace:Frontend.Views"
         mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
         x:Class="Frontend.Views.MainView"
         x:DataType="vm:MainViewModel">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.3*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.4*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
    
        <views:View1 Grid.Row="0" Grid.Column="0"/>
        <views:View2 Grid.Row="1" Grid.Column="1"/>
    
    </Grid>

</UserControl>

View1.xaml

<UserControl 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:vm="clr-namespace:Frontend.ViewModels"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="Frontend.Views.View1"
             x:DataType="vm:MainViewModel">

    <DataGrid Name="TableDataGrid" AutoGenerateColumns="False" IsReadOnly="True" GridLinesVisibility="All"
              CanUserReorderColumns="True" CanUserResizeColumns="True" CanUserSortColumns="True"
              BorderThickness="1" BorderBrush="Gray" VerticalAlignment="Center" HorizontalAlignment="Center"/>

</UserControl>

问题代码(View1.axaml.cs)

using Avalonia.Controls;
using Avalonia.Data;
using Frontend.ViewModels;
using System.Data;

namespace Frontend.Views;

public partial class View1 : UserControl
{
    public View1()
    {
        InitializeComponent();
        var viewModel = DataContext as MainViewModel;
        TableDataGrid.ItemsSource = viewModel.TableData.DefaultView;

        foreach (DataColumn x in viewModel.TableData.Columns)
        {
            if (x.DataType == typeof(bool))
            {
                TableDataGrid.Columns.Add(new DataGridCheckBoxColumn { Header = x.ColumnName, Binding = new Binding($"Row.ItemArray[{x.Ordinal}]") });
            }
            else
            {
                TableDataGrid.Columns.Add(new DataGridTextColumn { Header = x.ColumnName, Binding = new Binding($"Row.ItemArray[{x.Ordinal}]") });
            }
        }
    }
}

问题描述

在View1的构造函数中尝试通过DataContext获取MainViewModel时,DataContext为空。虽然View2能正常绑定MainViewModel的属性,说明父级DataContext是有效的,但View1初始化时上下文尚未完成赋值,导致无法配置DataGrid。


解决方案

方案1:监听DataContextChanged事件

控件构造时DataContext还未从父级继承,因此需要订阅DataContextChanged事件,在上下文赋值完成后再执行DataGrid的配置逻辑:

using Avalonia.Controls;
using Avalonia.Data;
using Frontend.ViewModels;
using System.Data;

namespace Frontend.Views;

public partial class View1 : UserControl
{
    public View1()
    {
        InitializeComponent();
        // 订阅DataContext变化事件
        DataContextChanged += OnDataContextChanged;
    }

    private void OnDataContextChanged(object? sender, EventArgs e)
    {
        var viewModel = DataContext as MainViewModel;
        // 空值校验,避免异常
        if (viewModel == null || viewModel.TableData == null)
            return;
            
        // 清除已有列,防止重复添加
        if (TableDataGrid.Columns.Count > 0)
            TableDataGrid.Columns.Clear();

        TableDataGrid.ItemsSource = viewModel.TableData.DefaultView;

        foreach (DataColumn x in viewModel.TableData.Columns)
        {
            if (x.DataType == typeof(bool))
            {
                TableDataGrid.Columns.Add(new DataGridCheckBoxColumn 
                { 
                    Header = x.ColumnName, 
                    Binding = new Binding($"Row.ItemArray[{x.Ordinal}]") 
                });
            }
            else
            {
                TableDataGrid.Columns.Add(new DataGridTextColumn 
                { 
                    Header = x.ColumnName, 
                    Binding = new Binding($"Row.ItemArray[{x.Ordinal}]") 
                });
            }
        }
    }
}

方案2:适配异步加载的场景

如果MainViewModel中的TableData是异步加载的,还需要监听ViewModel的属性变化,确保数据加载完成后更新DataGrid:

首先让MainViewModel实现INotifyPropertyChanged:

using System.ComponentModel;
using System.Data;

namespace Frontend.ViewModels;

public class MainViewModel : INotifyPropertyChanged
{
    private DataTable _tableData;
    public DataTable TableData
    {
        get => _tableData;
        set
        {
            _tableData = value;
            OnPropertyChanged(nameof(TableData));
        }
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // 示例数据加载方法
    public void LoadData()
    {
        // 模拟异步加载(实际场景可能用Task)
        TableData = new DataTable();
        // 添加列和数据逻辑...
    }
}

然后在View1中同时监听DataContext变化和ViewModel的属性变化:

using Avalonia.Controls;
using Avalonia.Data;
using Frontend.ViewModels;
using System.ComponentModel;
using System.Data;

namespace Frontend.Views;

public partial class View1 : UserControl
{
    private MainViewModel? _currentViewModel;

    public View1()
    {
        InitializeComponent();
        DataContextChanged += OnDataContextChanged;
    }

    private void OnDataContextChanged(object? sender, EventArgs e)
    {
        // 取消订阅旧ViewModel的事件
        if (_currentViewModel != null)
            _currentViewModel.PropertyChanged -= ViewModel_PropertyChanged;

        _currentViewModel = DataContext as MainViewModel;
        if (_currentViewModel == null)
            return;

        // 订阅新ViewModel的属性变化事件
        _currentViewModel.PropertyChanged += ViewModel_PropertyChanged;
        // 初始配置DataGrid
        ConfigureDataGrid(_currentViewModel);
    }

    private void ViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e)
    {
        // 当TableData属性变化时重新配置
        if (e.PropertyName == nameof(MainViewModel.TableData))
        {
            var viewModel = sender as MainViewModel;
            ConfigureDataGrid(viewModel);
        }
    }

    private void ConfigureDataGrid(MainViewModel? viewModel)
    {
        if (viewModel == null || viewModel.TableData == null)
            return;
            
        TableDataGrid.Columns.Clear();
        TableDataGrid.ItemsSource = viewModel.TableData.DefaultView;

        foreach (DataColumn x in viewModel.TableData.Columns)
        {
            if (x.DataType == typeof(bool))
            {
                TableDataGrid.Columns.Add(new DataGridCheckBoxColumn 
                { 
                    Header = x.ColumnName, 
                    Binding = new Binding($"Row.ItemArray[{x.Ordinal}]") 
                });
            }
            else
            {
                TableDataGrid.Columns.Add(new DataGridTextColumn 
                { 
                    Header = x.ColumnName, 
                    Binding = new Binding($"Row.ItemArray[{x.Ordinal}]") 
                });
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者user107586

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:58:11