XAML WPF动态选项卡控件与内容视图(MVVM)

alen0pnh  于 2023-08-01  发布在  其他
关注(0)|答案(1)|浏览(119)

我在TabControl中生成动态选项卡,每个选项卡的内容应该是填充DataGrid的视图/UserControl。
数据似乎已经加载,但是绑定有问题,因为视图没有显示任何内容。我认为ViewModel与View本身的绑定不匹配。
x1c 0d1x的数据
如果我在MainWindow.xaml中添加<views:MachineView DataContext="{Binding}"/>,我会得到更新的数据,但我需要删除并添加它才能“工作”。


MainWindow.xaml

<TabControl x:Name="machineTabs" Grid.Row="1" ItemsSource="{Binding Tabs}" SelectedIndex="{Binding SelectedIndex}"  >
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Header}"/>
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <DataTemplate DataType="{x:Type viewModels:MachineViewModel}">
            <views:MachineView/>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

字符串
标签头(<TabControl.ItemTemplate>)成功绑定到Header字段,但是当我尝试在视图本身中输出相同的值时,它不显示。

MainWindow.xaml.cs

public partial class MainWindow : Window
{

    private readonly MainWindowModel mainWindowModel;

    public MainWindow()
    {
        mainWindowModel = new MainWindowModel();
        DataContext = mainWindowModel;
        InitializeComponent();
    }
}

MainWindowModel.cs

public class MainWindowModel : ObservableObject
{
    private SqlConnection connection;
    public ObservableCollection<MachineViewModel> Tabs { get; } = new ObservableCollection<MachineViewModel>();
    public MainWindowModel()
    {
        connection = new(GetConnectionString());

        AddTab("Free");
        AddTab("Night Shift");
        AddTab("Day Shift");
        AddTab("Afternoon Shift");
    }

    private void AddTab(string header)
    {
        var mvm = new MachineViewModel();
        mvm.Initialize(header, connection);
        Tabs.Add(mvm);
    }

    public ICommand SearchCommand => new RelayCommand(Search);

    public int SelectedIndex { get; set; }

    /* ... */
}

MachineView.xaml

<UserControl x:Class="Namespace.View.MachineView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Namespace.View"
             xmlns:vm="clr-namespace:Namespace.ViewModel"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid Background="LightBlue">
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Text="{Binding Header}" HorizontalAlignment="Center" VerticalAlignment="Center" />
        <DataGrid x:Name="DataGrid" Grid.Row="1" ItemsSource="{Binding DataTable}" AutoGenerateColumns="True" IsReadOnly="True"/>
    </Grid>
</UserControl>

MachineView.xaml.cs

public partial class MachineView : UserControl
{

    private readonly MachineViewModel machineViewModel;

    public MachineView()
    {
        machineViewModel = new MachineViewModel();
        DataContext = machineViewModel;
        InitializeComponent();
    }

}

MachineViewModel.cs

public sealed class MachineViewModel : ObservableObject
{
    public string Header { get; private set; } = "";
    private SqlConnection? connection;

    private SqlDataAdapter? adapter;
    private DataTable? dataTable;
    private DataView? dataTableView;

    public void Initialize(string header, SqlConnection connection)
    {
        this.connection = connection;
        Header = header;
        OnPropertyChanged(nameof(Header));
    }

    public void Search()
    {
        if (connection == null) return;
        try
        {
            connection.Open();

            using SqlCommandBuilder sqlcommandbuilder = new();
            string dmc = sqlcommandbuilder.QuoteIdentifier(Header);

            string query = "select xyz";
            using SqlCommand command = new(query, connection);

            // Init the command and the builder
            adapter = new SqlDataAdapter(command);
            SqlCommandBuilder commandBuilder = new(adapter);

            // Fill the table with the values from the adapter and set it to the public field to notify about changes
            dataTable = new DataTable();
            adapter.Fill(dataTable);

            DataTable = dataTable.DefaultView;
            connection.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    public DataView? DataTable
    {
        get => dataTableView;
        set
        {
            if(dataTableView != value)
            {
                dataTableView = value;
                OnPropertyChanged(nameof(DataTable));
            }
        }
    }

}


请注意,必须使用Header来填充数据表。我喜欢使用构造函数,但xaml需要一个无参数的视图构造函数(?)
为什么即使我将视图绑定到DataTable并且在更新时调用OnPropertyChanged(nameof(DataTable));,内容也没有更新?

ekqde3dh

ekqde3dh1#

MachineView不能创建它自己的私有视图模型示例,而是操作它通过其DataContext属性的继承值获得的视图模型。
因此,只需从其构造函数中删除DataContext赋值:

public partial class MachineView : UserControl
{
    public MachineView()
    {
        InitializeComponent();
    }
}

字符串
由于TabControl不会为每个数据项创建新的TabItem和新的MachineView,因此您可以在DataContextChanged事件处理程序中“重置”单个MachineView的可视状态:

public partial class MachineView : UserControl
{
    public MachineView()
    {
        InitializeComponent();

        DataContextChanged += (s, e) =>
        {
            DataGrid.ScrollIntoView(...); // or similar
        };
    }
}

相关问题