无法通过命令将值从视图传递到viewmodel

问题描述 投票:0回答:2

我正在为我的应用程序实现MVVM模式。我正在实现我的Views,ViewModel,Model和Commands and Converters。现在,我无法通过命令绑定将我的textboxes值从我的datatemplate传递给我的ViewModel。我可以单击按钮来尝试更新过程,但它无法传递文本框值。我的命令类有什么需要改变的吗?

这是我的XAML:

<DataGrid AutoGenerateColumns="False" Grid.Row="2" Grid.ColumnSpan="4" Grid.RowSpan="3" x:Name="productionLineConfigDataGrid" Margin="70,0.2,70,0" ItemsSource="{Binding listAllProductionLineConfigs}">
<DataTemplate>
<StackPanel>
        <StackPanel Orientation="Horizontal">
                <TextBlock FontSize="12" Text="ID: " VerticalAlignment="Center" />
                <TextBlock x:Name="txtBlockLineId" FontSize="16" Foreground="MidnightBlue" Text="{Binding ProductionLineId, Mode=TwoWay}" VerticalAlignment="Center" />
        </StackPanel>
        <StackPanel>
                <Button x:Name="btnUpdate" Content="Update" VerticalAlignment="Center" HorizontalAlignment="Right" Click="btnUpdate_Click" Command="{Binding DataContext.updateProductionLineConfigCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:production_line_config_home}}}" CommandParameter="{Binding ProductionLineConfig}"/>
        </StackPanel>
</StackPanel>
</DataTemplate>
</DataGrid>

以下是我的ViewModel中的方法:

public ProductionLineConfig ProductionLineConfig
    {
        get { return productionlineconfig; }

        set
        {
            productionlineconfig = value;
            OnPropertyChanged("ProductionLineConfig");
        }
    }

这是我得到的错误消息:

System.Windows.Data错误:40:BindingExpression路径错误:'对象'''ProductionLineConfig'(HashCode = 47309994)'上找不到'ProductionLineConfig'属性。 BindingExpression:路径= ProductionLineConfig; DataItem ='ProductionLineConfig'(HashCode = 47309994); target元素是'Button'(Name =''); target属性是'CommandParameter'(类型'Object')

我已将图像包含在我的应用程序here

这是整个xaml代码here,这是整个viewmodel代码here

c# wpf data-binding
2个回答
0
投票

根据您的代码源,我做了一个示例实现,以实现您的要求。

示例VM:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApp5.ViewModels
{
    public class ProductionLineConfigViewModel : INotifyPropertyChanged
    {
        public CustomCommand<ProductionLineConfig> UpdateCommand { get; }

        public ProductionLineConfigViewModel()
        {
            PopulateProductionLineConfigs();
            UpdateCommand = new CustomCommand<ProductionLineConfig>(UpdateConfig, (u) => true);
        }

        private ObservableCollection<ProductionLineConfig> _listAllProductionLineConfigs;
        public ObservableCollection<ProductionLineConfig> listAllProductionLineConfigs
        {
            get { return _listAllProductionLineConfigs; }
            set
            {
                _listAllProductionLineConfigs = value;
                OnPropertyChanged();
            }
        }

        //  Call this from constructor.
        private void PopulateProductionLineConfigs()
        {
            listAllProductionLineConfigs = new ObservableCollection<ProductionLineConfig>
            {
                new ProductionLineConfig
                {
                    ProductionLineId = 1,
                    ProductionLineCode = "001",
                    ProductionLineCreatedDate = DateTime.Today.Date,
                    ProductionLineName = "safdsf",
                    ProductionLineStatus = true
                },
                new ProductionLineConfig
                {
                    ProductionLineId = 1,
                    ProductionLineCode = "002",
                    ProductionLineCreatedDate = DateTime.Today.Date,
                    ProductionLineName = "sadfadfsdf",
                    ProductionLineStatus = true
                }
            };
        }

        private void UpdateConfig(ProductionLineConfig config)
        {
            MessageBox.Show("Line Name update: " + config.ProductionLineName);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

    }

    public class ProductionLineConfig
    { 
        public int ProductionLineId { get; set; }

        public string ProductionLineCode { get; set; }

        public string ProductionLineName { get; set; }

        public bool ProductionLineStatus { get; set; }
        public DateTime ProductionLineCreatedDate { get; set; }
    }
}

示例XAML:

<Window x:Name="Root" x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewModels="clr-namespace:WpfApp5.ViewModels"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <viewModels:ProductionLineConfigViewModel/>
    </Window.DataContext>

    <Grid Background="#FF006E8C">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Label Grid.ColumnSpan="4" Content="KAD ShopFloor System" HorizontalAlignment="Center" Margin="10" FontWeight="Bold" FontSize="30" FontFamily="Segoe UI" Foreground="White"/>
        <Separator Grid.ColumnSpan="4" Grid.RowSpan="3" Background="White" Margin="0,-35,-0.4,39.2"/>
        <DataGrid AutoGenerateColumns="False" Grid.Row="2" Grid.ColumnSpan="4" Grid.RowSpan="3" x:Name="productionLineConfigDataGrid" Margin="70,0.2,70,0"
                  ItemsSource="{Binding DataContext.listAllProductionLineConfigs, ElementName=Root}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Binding="{Binding ProductionLineId, Mode=TwoWay}"/>
                <DataGridTextColumn Header="Production Line Code" Binding="{Binding ProductionLineCode, Mode=TwoWay}"/>
                <DataGridTextColumn Header="Production Line Name" Binding="{Binding ProductionLineName, Mode=TwoWay}"/>
                <DataGridTextColumn Header="Status" Binding="{Binding ProductionLineStatus, Mode=TwoWay}"/>
                <DataGridTextColumn Header="Created Date" Binding="{Binding ProductionLineCreatedDate, Mode=TwoWay}"/>
            </DataGrid.Columns>
            <DataGrid.RowDetailsTemplate>
                <DataTemplate>
                    <Border BorderThickness="0" Background="BlanchedAlmond" Padding="10">
                        <StackPanel Orientation="Vertical" x:Name="stck">
                            <StackPanel Orientation="Horizontal">
                                <TextBlock FontSize="12" Text="ID: " VerticalAlignment="Center" />
                                <TextBlock x:Name="txtBlockLineId" FontSize="16" Foreground="MidnightBlue" Text="{Binding ProductionLineId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock FontSize="12" Text="Line Code: " VerticalAlignment="Center" />
                                <TextBlock x:Name="txtBlockLineCode" FontSize="16" Foreground="MidnightBlue" Text="{Binding ProductionLineCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock FontSize="12" Text="Line Name: " VerticalAlignment="Center" />
                                <TextBox x:Name="txtLineName" FontSize="16" Foreground="MidnightBlue" Text="{Binding ProductionLineName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
                            </StackPanel>
                            <!--<StackPanel Orientation="Horizontal">
                                <TextBlock FontSize="12" Text="Status: " VerticalAlignment="Center" />
                                <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type DataGrid}},
                                    Path=DataContext.Statusstring}" SelectedValue="{Binding ProductionLineStatus, Converter={StaticResource statusToBooleanConverter}, Mode=TwoWay}" x:Name="cbProductionLineStatus" FlowDirection="LeftToRight" FontSize="16" Foreground="MidnightBlue"
                                    HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
                            </StackPanel>-->
                            <StackPanel>
                                <Button x:Name="btnUpdate" Content="Update" VerticalAlignment="Center" HorizontalAlignment="Right"
                                        Command="{Binding DataContext.UpdateCommand, ElementName=Root}"
                                        CommandParameter="{Binding}" />
                            </StackPanel>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </DataGrid.RowDetailsTemplate>
        </DataGrid>

    </Grid>
</Window>

样本输出:

enter image description here

enter image description here

这里的主要变化,

  1. 您需要将列表更改为可观察的集合
  2. 创建一个接受对象的自定义命令,请参阅以下文章:[UWP/MVVM]Enable/Disable Button in RadDataGrid Data Template Column that have commands bound to them upon conditions
  3. 命令参数应该是迭代项,可以通过CommandParameter={Binding}实现
  4. 在双向绑定中,请务必添加UpdateSourceTrigger=PropertyChanged

2
投票

我只想猜测一下。

假设ProductionLineConfig是你在模板中绑定ProductionLineId的东西。那么您可能只是希望将绑定源作为命令参数传递

CommandParameter="{Binding}"

{Binding}为空时,意味着Binding绑定到任何Source。这也只是...的简写

{Binding DataContext,RelativeSource={RelativeSource Self}}.

反过来(如果星星对齐),那么它应该是你的ProductionLineConfig

© www.soinside.com 2019 - 2024. All rights reserved.