簡體   English   中英

如何在WPF MVVM中單擊此按鈕?

[英]How does this button click work in WPF MVVM?

我開始研究WFM MVVM模式。

但我無法理解為什么這個Button點擊工作而不綁定任何事件或動作。

視圖

<Window x:Class="WPF2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:WPF2.ViewModel"
    Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <vm:MainWindowViewModel x:Key="MainViewModel" />
    </Window.Resources>

    <Grid x:Name="LayoutRoot"
          DataContext="{Binding Source={StaticResource MainViewModel}}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewProducts,Path=SelectedItem.ProductId}" />
        <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtName" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewProducts,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=ListViewProducts,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 Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="141" Height="23" Margin="310,40,0,0" Content="Update" />

        <ListView Name="ListViewProducts" Grid.Row="1" Margin="4,109,12,23"  ItemsSource="{Binding Path=Products}"  >
            <ListView.View>
                <GridView x:Name="grdTest">
                    <GridViewColumn Header="Product ID" DisplayMemberBinding="{Binding ProductId}" Width="100"/>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="250" />
                    <GridViewColumn Header="Price" DisplayMemberBinding="{Binding Price}" Width="127" />
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

視圖模型

class MainWindowViewModel : INotifyPropertyChanged
{
    public const string ProductsPropertyName = "Products";

    private ObservableCollection<Product> _products;

    public ObservableCollection<Product> Products
    {
        get
        {
            return _products;
        }
        set
        {
            if (_products == value)
            {
                return;
            }

            _products = value;
            RaisePropertyChanged(ProductsPropertyName);
        }
    }

    public MainWindowViewModel()
    {
        _products = new ObservableCollection<Product>
        {
            new Product {ProductId=1, Name="Pro1", Price=11},
            new Product {ProductId=2, Name="Pro2", Price=12},
            new Product {ProductId=3, Name="Pro3", Price=13},
            new Product {ProductId=4, Name="Pro4", Price=14},
            new Product {ProductId=5, Name="Pro5", Price=15}
        };
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion
}

我從我讀過的教程中找到了這段代碼。 當我從列表視圖中單擊一行時,將設置文本框值。 當我編輯這些值並單擊按鈕時,listview上的值會更新。

按鈕上沒有事件也沒有綁定命令。 那么按鈕點擊如何更新listview中的值?

我知道這已經過時了,但我正在研究這個場景,並找到了答案。 首先,在MVVM理論中,“代碼隱藏”不應該包含所有代碼應該在ViewModel類中的代碼。 因此,為了實現按鈕單擊,您可以在ViewModel中使用此代碼(除了INotifyPropertyChanged實現):

        public ICommand ButtonCommand { get; set; }

        public MainWindowViewModel()
        {
            ButtonCommand = new RelayCommand(o => MainButtonClick("MainButton"));
        }

        private void MainButtonClick(object sender)
        {
            MessageBox.Show(sender.ToString());            
        }

使用課程:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace <your namespace>.ViewModels
{
    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;

        public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
        {
            if (execute == null) throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        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 ?? "<N/A>");
        }

    }
}

在XAML中:

 <Window.DataContext> <viewModels:MainWindowViewModel /> </Window.DataContext> <Button Content="Button" Command="{Binding ButtonCommand}" /> 

您需要將UpdateSourceTrigger設置為Explicit並在ButtonClick事件上設置更新綁定源。

Button s Click事件首先在Command之前執行。 因此,可以在Click事件中更新源屬性。 我修改了你的代碼來證明這一點。

注意:

  1. 為簡單起見,我在代碼后面編寫了視圖模型。
  2. 我已經使用了RelayCommandMVVMLight庫。

第一次XAML變更

    <Button Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="141" Height="23" Margin="310,40,0,0" Content="Update" Click="Button_Click" Command="{Binding UpdateCommand}"/>

第二次XAML變更

    <ListView Name="ListViewProducts" Grid.Row="1" Margin="4,109,12,23"  ItemsSource="{Binding Path=Products}" SelectedItem="{Binding SelectedProduct}" >

代碼背后

using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WPF2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            txtID.GetBindingExpression(TextBox.TextProperty).UpdateSource();
            txtName.GetBindingExpression(TextBox.TextProperty).UpdateSource();
            txtPrice.GetBindingExpression(TextBox.TextProperty).UpdateSource();
        }
    }

    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public const string ProductsPropertyName = "Products";

        private ObservableCollection<Product> _products;

        public ObservableCollection<Product> Products
        {
            get
            {
                return _products;
            }
            set
            {
                if (_products == value)
                {
                    return;
                }

                _products = value;
                RaisePropertyChanged(ProductsPropertyName);
            }
        }

        private Product _SelectedProduct;

        public Product SelectedProduct
        {
            get { return _SelectedProduct; }
            set
            {
                _SelectedProduct = value;
                RaisePropertyChanged("SelectedProduct");
            }
        }


        private ICommand _UpdateCommand;

        public ICommand UpdateCommand
        {
            get
            {
                if (_UpdateCommand == null)
                {
                    _UpdateCommand = new RelayCommand(() =>
                        {
                            MessageBox.Show( String.Format("From ViewModel:\n\n Updated Product : ID={0}, Name={1}, Price={2}", SelectedProduct.ProductId, SelectedProduct.Name, SelectedProduct.Price));
                        });
                }
                return _UpdateCommand;
            }
        }


        public MainWindowViewModel()
        {
            _products = new ObservableCollection<Product>
            {
                new Product {ProductId=1, Name="Pro1", Price=11},
                new Product {ProductId=2, Name="Pro2", Price=12},
                new Product {ProductId=3, Name="Pro3", Price=13},
                new Product {ProductId=4, Name="Pro4", Price=14},
                new Product {ProductId=5, Name="Pro5", Price=15}
            };

        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}

在上面的示例代碼段中,ListView被綁定到Product的ObservableCollection ,它在內部實現了INotfiyPropertyChanged接口。 此接口負責引發PropertyChanged事件,並在更改時更新綁定的UI元素值。

您可以在此處看到,所有TextBox的Text屬性綁定為Text="{Binding ElementName=ListViewProducts,Path=SelectedItem.ProductId}

Binding ElementName - 這是一個標記擴展,它將告訴XAML編譯器將ListView綁定到Textbox控件

Path - 這將指向Binded UI Element的特定屬性。 在這種情況下,它將指向ListView.SelectedItem對象屬性。 即。 Product.ProductID

默認情況下,WPF UI元素的綁定模式為TwoWay 因此,只要值發生變化,它就會更新Source和Target。 您可以通過將模式更改為OneWay來嘗試此操作

<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewProducts,Path=SelectedItem.ProductId,Mode=OneWay}" />

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM