【问题标题】:WPF DataGrid calling command, bindingWPF DataGrid 调用命令,绑定
【发布时间】:2020-08-07 00:00:01
【问题描述】:

我昨天刚开始学习 WPF,我的目标是用简单的网格创建带有酒店预订信息的窗口。现在只有房间号、客人人数、日期和“行动”列。在“操作”栏中有“保存”按钮。在新行中单击时,它应该能够保存更新或创建新预订。问题是当我单击“保存”按钮时,未调用 SaveBooking 方法。我也不确定如何正确绑定到 CurrentBooking 对象。由于我是 WPF 新手,我试图从几个教程中弄清楚。这是我创建的。

XAML:

<Window x:Class="HotelApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:HotelApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="800" Width="1000">
    <Grid>
        <TabControl>
            <TabItem Header="Bookings">
                <DataGrid AutoGenerateColumns = "False" ItemsSource="{Binding Bookings}">

                    <DataGrid.Columns>
                        <DataGridTextColumn Header = "Room" Binding = "{Binding Room, Mode=TwoWay}" />
                        <DataGridTextColumn Header = "Floor" Binding = "{Binding NumOfGuests, Mode=TwoWay}" />
                        <DataGridTextColumn Header = "From" Binding = "{Binding From, Mode=TwoWay}"/>
                        <DataGridTextColumn Header = "To" Binding = "{Binding To, Mode=TwoWay}"/>
                        <DataGridTemplateColumn Header = "Actions">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Button Content="Save" Command="{Binding DataContext.SaveBookingCommand }" />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                    </DataGrid.Columns>
                </DataGrid>
            </TabItem>
            <TabItem Header="Guests" />
        </TabControl>
        
    </Grid>
</Window>

型号:

public class BookingModel : ObservableObject
{
    private int _room;
    public int Room
    {
        get => _room;
        set
        {
            if (value != _room)
            {
                _room = value;
                OnPropertyChanged("Room");
            }
        }
    }

    private int _numOfGuests;
    public int NumOfGuests
    {
        get => _numOfGuests;
        set
        {

            _numOfGuests = value;
            OnPropertyChanged("NumOfGuests");
        }
    }

    private DateTime _from;
    public DateTime From
    {
        get => _from;
        set
        {

            _from = value;
            OnPropertyChanged("From");
        }
    }

    private DateTime _to;

    public DateTime To
    {
        get => _to;
        set
        {

            _to = value;
            OnPropertyChanged("To");
        }
    }
}

视图模型:

public class MainWindowVM : ObservableObject
{
    private readonly IBookingService _bookingService;

    private ICommand _saveBookingCommand;
    public ICommand SaveBookingCommand
    {
        get
        {
            if (_saveBookingCommand == null)
            {
                _saveBookingCommand = new RelayCommand(
                    param => SaveBooking(),
                    param => (CurrentBooking != null)
                );
            }
            return _saveBookingCommand;
        }
    }

    private ObservableCollection<BookingModel> _Bookings { get; set; }

    private BookingModel _currentBookng;
    public BookingModel CurrentBooking
    {
        get { return _currentBookng; }
        set
        {
            if (value != _currentBookng)
            {
                _currentBookng = value;
                OnPropertyChanged("CurrentBooking");
            }
        }
    }

    public ObservableCollection<BookingModel> Bookings
    {
        get { return _Bookings; }
        set { _Bookings = value; }
    }

    public MainWindowVM(IBookingService bookingService)
    {
        _bookingService = bookingService;
        BrowseBookings();
    }

    public void BrowseBookings()
    {
        var bookings = _bookingService.Browse().Select(x => new BookingModel { Room = x.Room.RoomId, NumOfGuests = x.NumOfGuests, From = x.From, To = x.To });
        Bookings = new ObservableCollection<BookingModel>(bookings);

    }

    private void SaveBooking()
    {
        // send CurrentBooking to service
    }
}

中继命令:

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]
    public bool CanExecute(object parameters)
    {
        return _canExecute == null ? true : _canExecute(parameters);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameters)
    {
        _execute(parameters);
    }

    #endregion // ICommand Members
}

【问题讨论】:

    标签: c# wpf datagrid


    【解决方案1】:

    您的命令位于整个数据网格 MainWindowVM 的数据上下文中。

    您的按钮的数据上下文是该行的数据上下文 - 一个 BookingModel。

    您需要一些关于该绑定的相关资源。

    原则上是这样的:

    {Binding DataContext.ParentVMProperty,
    RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
    

    在这种情况下,您的类型将是 DataGrid。

    您还可以在 datagrid 上绑定 selecteditem,并在他们单击按钮时确保使用 datagrid 属性进行选择。

    或者

    你可以在命令上有一个命令参数

     CommandParameter="{Binding .}"
    

    Relaycommand 通常有两种形式,一种是 RelayCommand

    也许我错过了它,但在您的实施中我没有看到。我建议您获取 MVVM Light 的源代码并粘贴到您的解决方案中以获得更完整的实现。或者,如果您不使用 .net 核心,则只需添加 nuget 包。您需要 relaycommand 的 commandwpf 命名空间版本。

    【讨论】:

      【解决方案2】:

      您遗漏了很多代码,所以我不知道您为 ObservableObject 使用了哪个 nuget 包。无论如何,我伪造了 ObservableObject 并让绑定工作。主要问题是您试图在 BookingModel 级别绑定 SaveBookingCommand,而在您的代码中您将其写入 MainWindowVM 级别。

      您可以通过在 BookingModel 中设置 MainWindowVM 来轻松解决此问题,并将绑定更改为 Command={Binding Parent.SaveBookingCommand}

      以下是我所做编辑的一些提示:

      MainWindow.xaml.cs

          <DataTemplate>
              <Button Content="Save" Command="{Binding Parent.SaveBookingCommand}" />
          </DataTemplate>
      

      BookingModel.cs

      public class BookingModel : ObservableObject
      {
          public MainWindowVM Parent { get; private set; }
      
          public BookingModel()
          {
              this.Parent = null;
          }
      
          public BookingModel(MainWindowVM parent)
          {
              this.Parent = parent;
          }
      
          // ... you know the rest
      

      MainWindowVM.cs

      public MainWindowVM : ObservableObject
      {
          public void BrowseBookings()
          {
              // NOTICE that I added 'this' as the parameter argument to connect MainWindowVM to the BookingModel.
              var bookings = _bookingService.Browse().Select(x => new BookingModel(this) { Room = x.Room, NumOfGuests = x.NumOfGuests, From = x.From, To = x.To });
              Bookings = new ObservableCollection<BookingModel>(bookings);
              CurrentBooking = Bookings.First();
          }
      
          // ... you know the rest
      

      【讨论】:

        猜你喜欢
        • 2012-02-23
        • 2012-10-31
        • 2021-08-29
        • 1970-01-01
        • 1970-01-01
        • 2016-05-07
        • 2015-07-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多