MVVM:将具有可观察集合的命令绑定到列表框并从文本框中获取值

本文关键字:列表 文本 获取 绑定 命令 集合 观察 MVVM | 更新日期: 2023-09-27 18:35:25

我是MVVM的新手,在这个小应用程序中,我有一个列表框,三个文本框和两个按钮,一个是更新,另一个是添加。在 XAML 中,我已经完成了所有列表框列与文本框的绑定,根据命令,当我更改任一文本框中的值时,我的更新按钮功能正常,但我不知道如何使用命令从文本框中获取值并在集合中添加值。

这是 Xaml 代码。

<Grid Height="314">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <ListView Name="ListViewEmployeeDetails" Grid.Row="1" Margin="4,109,12,23"  ItemsSource="{Binding Products}"  >
        <ListView.View>
            <GridView x:Name="grdTest">
                <GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}"  Width="100"/>
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"  Width="100" />
                <GridViewColumn Header="Price" DisplayMemberBinding="{Binding Price}" Width="100" />
            </GridView>
        </ListView.View>
    </ListView>
    <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.ID}" />
    <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtName" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.Name}" />
    <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,61,0,0" Name="txtPrice" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.Price}" />
    <Label Content="ID" Grid.Row="1" HorizontalAlignment="Left" Margin="12,12,0,274" Name="label1" />
    <Label Content="Price" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,59,0,0" Name="label2" VerticalAlignment="Top" />
    <Label Content="Name" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,35,0,0" Name="label3" VerticalAlignment="Top" />
    <Button Content="Update" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="311,59,0,0" Name="btnUpdate"
            VerticalAlignment="Top" Width="141"
            Command="{Binding Path=UpdateCommad}"
            />
    <Button Content="Add" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="311,17,0,0" Name="btnAdd"
        VerticalAlignment="Top" Width="141"
        Command="{Binding UpdateCommad}"
            />
</Grid>

这是产品类别

public class Product : INotifyPropertyChanged
{
    private int m_ID;
    private string m_Name;
    private double m_Price;
    #region INotifyPropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion
    public int ID
    {
        get
        {
            return m_ID;
        }
        set
        {
            m_ID = value;
            OnPropertyChanged("ID");
        }
    }
    public string Name
    {
        get
        {
            return m_Name;
        }
        set
        {
            m_Name = value;
            OnPropertyChanged("Name");
        }
    }
    public double Price
    {
        get
        {
            return m_Price;
        }
        set
        {
            m_Price = value;
            OnPropertyChanged("Price");
        }
    }
}

这是视图模型类,现在我静态地将产品添加到m_Products中。

class ProductViewModel
{
    private ObservableCollection<Product> m_Products;
    public ProductViewModel()
    {
        m_Products = new ObservableCollection<Product>
    {
        new Product {ID=1, Name ="Pro1", Price=10},
        new Product{ID=2, Name="BAse2", Price=12}
    };
    }
    public ObservableCollection<Product> Products
    {
        get
        {
            return m_Products;
        }
        set
        {
            m_Products = value;
        }
    }
    private ICommand mUpdater;
    public ICommand UpdateCommand
    {
        get
        {
            if (mUpdater == null)
                mUpdater = new Updater();
            return mUpdater;
        }
        set
        {
            mUpdater = value;
        }
    }
    private ICommand addUpdater;
    public ICommand AddCommand
    {
        get 
        {
            if (addUpdater == null)
                addUpdater = new Updater();
            return addUpdater; 
        }
        set
        {
            addUpdater = value;
        }
    }

    private class Updater : ICommand
    {
        #region ICommand Members
        public bool CanExecute(object parameter)
        {
            return true;
        }
        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter)
        {
        }
        #endregion
    }

}

现在我不知道如何使用添加按钮单击上的命令将值(产品)添加到集合中。

MVVM:将具有可观察集合的命令绑定到列表框并从文本框中获取值

您可以使用中继

命令。它允许您通过传递到其构造函数的委托注入命令的逻辑:

/// <summary>
/// Class representing a command sent by a button in the UI, defines what to launch when the command is called
/// </summary>
public class RelayCommand : ICommand
{
    #region Fields
    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;
    #endregion // Fields
    #region Constructors
    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors
    #region ICommand Members
    //[DebuggerStepThrough]
    /// <summary>
    /// Defines if the current command can be executed or not
    /// </summary>
    /// <param name="parameter"></param>
    /// <returns></returns>
    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter);
    }
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
    public void Execute(object parameter)
    {
        _execute(parameter);
    }
    #endregion // ICommand Members
}

使用这种类型的命令,您可以非常轻松地执行所需的操作,例如,在您的视图模型中,您现在可以执行此操作:

public class ProductViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Product> m_Products;
    public ProductViewModel()
    {
        m_Products = new ObservableCollection<Product>
        {
            new Product {ID = 1, Name = "Pro1", Price = 10},
            new Product {ID = 2, Name = "BAse2", Price = 12}
        };
    }

    private Product _selectedProduct;
    public Product SelectedProduct
    {
        get
        {
            return _selectedProduct;
        }
        set
        {
            _selectedProduct = value;
            OnPropertyChanged("SelectedProduct");
        }
    }
    public ObservableCollection<Product> Products
    {
        get
        {
            return m_Products;
        }
        set
        {
            m_Products = value;
        }
    }
    ICommand _addCommand;
    public ICommand AddCommand
    {
        get
        {
            if (_addCommand == null)
            {
                _addCommand = new RelayCommand(param => AddItem());
            }
            return _addCommand;
        }
    }

    ICommand _deleteCommand;
    public ICommand DeleteCommand
    {
        get
        {
            if (_deleteCommand == null)
            {
                _deleteCommand = new RelayCommand(param => DeleteItem((Product)param));
            }
            return _deleteCommand;
        }
    }
    private void DeleteItem(Product product)
    {
        if (m_Products.Contains(product))
        {
            m_Products.Remove(product);
        }
    }
    private void AddItem()
    {
        m_Products.Add(new Product());
    }

    public event PropertyChangedEventHandler PropertyChanged;
    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

如您所见,有两个命令,一个用于添加产品,另一个用于删除所选产品。您不必担心更新,您使用的是ObservableCollection<>。此外,我将属性 selectedProduct 添加到您的视图模型,以了解在您的视图中选择了哪个元素:

    <Grid Height="314">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <ListView Name="ListViewEmployeeDetails" Grid.Row="1" Margin="4,109,12,23"  ItemsSource="{Binding Products}" SelectedValue="{Binding SelectedProduct}"  >
        <ListView.View>
            <GridView x:Name="grdTest">
                <GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}"  Width="100" />
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"  Width="100" />
                <GridViewColumn Header="Price" DisplayMemberBinding="{Binding Price}" Width="100" />
            </GridView>
        </ListView.View>
    </ListView>
    <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" Text="{Binding SelectedProduct.ID}" />
    <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtName" VerticalAlignment="Top" Width="178" Text="{Binding SelectedProduct.Name}" />
    <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,61,0,0" Name="txtPrice" VerticalAlignment="Top" Width="178" Text="{Binding SelectedProduct.Price}" />
    <Label Content="ID" Grid.Row="1" HorizontalAlignment="Left" Margin="12,12,0,274" Name="label1" />
    <Label Content="Price" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,59,0,0" Name="label2" VerticalAlignment="Top" />
    <Label Content="Name" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,35,0,0" Name="label3" VerticalAlignment="Top" />
    <Button Content="Remove" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="311,59,0,0" Name="btnUpdate"
        VerticalAlignment="Top" Width="141"
        Command="{Binding DeleteCommand}" CommandParameter="{Binding SelectedProduct}"
        />
    <Button Content="Add" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="311,17,0,0" Name="btnAdd"
    VerticalAlignment="Top" Width="141"
    Command="{Binding AddCommand}"
        />
</Grid>

在删除按钮中,我声明了 CommandParamameter,并将其绑定到 SelectedProduct 属性。这是接收中继命令以删除产品的参数。没有必要,您已经在视图中模型中选择了 SelectedProduct,但我还是这样做是为了展示如何将参数传递给命令。

[编辑1]

若要实现所需的行为,需要在视图模型中添加三个新属性(Id、Name 和 Price)。现在,这些属性应与文本框绑定。若要在 ListView 中编辑所选产品,请在"所选产品"属性集中设置"ID"、"名称"和"价格"属性的值。当文本框也更改其值时,您必须设置所选产品的属性。

视图模型中的更改:

  private int _id=1;
    public int Id
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
            if (SelectedProduct!=null)
            {
                SelectedProduct.ID = _id;
            }
            OnPropertyChanged("Id");
        }
    }
    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            if (SelectedProduct != null)
            {
                SelectedProduct.Name = _name;
            }
            OnPropertyChanged("Name");
        }
    }

    private double _price = 0;
    public double Price
    {
        get
        {
            return _price;
        }
        set
        {
            _price = value;
            if (SelectedProduct != null)
            {
                SelectedProduct.Price = _price;
            }
            OnPropertyChanged("Price");
        }
    }
    private Product _selectedProduct;
    public Product SelectedProduct
    {
        get
        {
            return _selectedProduct;
        }
        set
        {
            _selectedProduct = value;
            Id = _selectedProduct != null ? _selectedProduct.ID : 0;
            Name = _selectedProduct != null ? _selectedProduct.Name : "";
            Price = _selectedProduct != null ? _selectedProduct.Price : 0;
            OnPropertyChanged("SelectedProduct");
        }
    }

视图更改:

<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" Text="{Binding Id}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtName" VerticalAlignment="Top" Width="178" Text="{Binding Name}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,61,0,0" Name="txtPrice" VerticalAlignment="Top" Width="178" Text="{Binding Price}" />