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

时间:2018-09-19 04:09:13

标签: c# wpf data-binding

我正在为我的应用程序实现MVVM模式。我正在执行我的视图,ViewModel,模型以及命令和转换器。现在,我无法通过命令绑定将文本框值从数据模板传递到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:Path = ProductionLineConfig; DataItem ='ProductionLineConfig'(HashCode = 47309994);目标元素是'Button'(Name ='');目标属性为“ CommandParameter”(类型为“对象”)

我已经为我的应用程序here添加了图片

这是完整的xaml代码here,这是完整的viewmodel代码here

2 个答案:

答案 0 :(得分:2)

我只会对此猜测。

假设ProductionLineConfig是模板中ProductionLineId绑定的对象。然后,您可能只是想将绑定源作为命令参数传递

CommandParameter="{Binding}"

{Binding}为空时,表示绑定已绑定到任何 Source 。这也是...的简写。

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

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

答案 1 :(得分: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. 实现
  5. 在两种方式的绑定中,请确保添加UpdateSourceTrigger=PropertyChanged