如何绑定列表视图的组合框的值,并将其包含在 wpf mvvm 视图模型中

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

我有2节课:

public class Order : ObservableCollection<string>
{    
    public Order()
    {
        Add("1st");
        Add("2nd");
        Add("3rd");
        for (int i=4; i< 100; i++)
        {
            Add($"{i}th");
        }        
    }
}

public class Id : ObservableCollection<string>
{  
    public Id()
    {
        Add("abc12345");
        Add("dce12345");
        //3000 id,...
    } 
}

在我的xaml中:

<DockPanel Grid.Row="2" Grid.Column="0" Height="Auto" Background="LightBlue">
    <DockPanel.Resources>
        <src:Order x:Key="order"/>
        <src:Id x:Key="id"/>
    </DockPanel.Resources>
    <ListView ItemsSource="{StaticResource order}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Order"/>
                <GridViewColumn Header="ID">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox Width="200"                             ItemsSource="{StaticResource id}">
                            </ComboBox>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>
</DockPanel>

绑定得很好:列表框中“顺序”列(第 1 到第 99 列)的 100 行中的每一行都有一个可以选择 ID 的组合框。但是,我如何获取每行中的每个组合框选定的值,并将它们绑定到在

public partial class MainWindowViewModel : ObservableObject
而不是
MainWindow
中创建的值(或列表)? 我认为 LINQ 是可能的,但必须从
MainWindow
而不是
MainViewModel
调用。但这对我的控制来说毫无意义。感谢任何帮助。

c# wpf .net-core mvvm
1个回答
0
投票

从列表类型继承来表达一组数据是一个典型的初学者错误:
您有很多汽车品牌,因此将

Car
改为
List
。 (错误)
您的团队中有很多玩家,因此请将
Team
设为
List
。 (错误)
您的订单中有很多产品,因此将
Order
设为
List
。 (错误)

组合通常是比使用继承更好的选择。
大多数对象的关系都可以使用组合来正确表达(就像现实世界的对象一样)。

如果有帮助,您只需在要添加新功能时扩展列表类型。
例如,

TemporaryCollection
可以跟踪其项目的存储时间并在一定时间后删除它们。 ==>新功能==>扩展
List

或者如果您想隐藏泛型类型参数。
例如,将
List<int>
变为
IntegerList

在所有其他情况下,从列表类型扩展都是错误的。

您还可以使用语义来检查您是否正确应用了正确的类设计。
例如,订单不是多个产品。但一个订单多种产品。
以及订单has一个ID和has一个时间戳和has一个关联的客户。

如果关系是 is a 那么你必须使用继承。 如果关系是 has a 那么你必须使用组合:

订单.cs

// If the class serves as a binding source and is a DependencyObject (for example a Control), 
// it MUST implement its properties as dependency properties. 
// If the class serves as a binding source is not a DependencyObject (for example a view model class),
// it MUST implement INotifyPropertyChanged.
class Order : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;

  public ObservableCollection<string> Items { get; }
  public int Id { get; }

  private Order selectedOrderItem;
  public Order SelectedOrderItem
  {
    get => this.selectedOrderItem;
    set
    {
      this.selectedOrderItem = value;
      OnPropertyChanged();
    }
  }

  public Order(int id)
  {
    this.Id = id;
    this.Items = new ObservableCollection<string>();
  }

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

MainViewModel.cs

class MainViewModel : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;

  public ObservableCollection<Order> Orders { get; }

  private Order selectedOrder;
  public Order SelectedOrder
  {
    get => this.selectedOrder;
    set
    {
      var oldSelectedOrder = this.selectedOrder;
      this.selectedOrder = value;
      OnPropertyChanged();
      OnSelectedOrderChanged(oldSelectedOrder, value);
    }
  }

  public MainViewModel()
  {
    this.Orders = new ObservableCollection<Order>();
    for (int orderId = 1; orderId < 4; orderId++)
    {
      var newOrder = new Order(orderId);
      for (int itemCount = 0; itemCount < 3; itemCount++)
      {
        string orderItem = $"Item {itemCount}";
        newOrder.Items.Add(orderItem);
      }

      this.Orders.Add(newOrder);
    }
  }

  private void OnSelectedOrderChanged(Order oldSelectedOrder, Order newSelectedOrder)
  {
    // TODO::Handle selected Order
  
    var selectedOrderItem = newSelectedOrder.SelectedOrderItem;
    var orderId = newSelectedOrder.Id;
  }

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

现在订单商品和ID:

var items = order.Items;
var orderId = order.Id;

MainWindow.xaml

<Window>
  <Window.DataContext>
    <MainViewModel />
  </Window.DataContext>

  <ListView ItemsSource="{Binding Orders}"
            SelectedItem="{Binding SelectedOrder}">
    <ListView.View>
      <GridView>
        <GridViewColumn Header="Order">
          <GridViewColumn.CellTemplate>
            <DataTemplate DataType="{x:Type local:Order}">
              <ComboBox ItemsSource="{Binding Items}"
                        SelectedItem="{Binding SelectedOrderItem}" />
            </DataTemplate>
          </GridViewColumn.CellTemplate>
        </GridViewColumn>
        <GridViewColumn Header="ID"
                        DisplayMemberBinding="{Binding Id}" />
      </GridView>
    </ListView.View>
  </ListView>
</Window>
© www.soinside.com 2019 - 2024. All rights reserved.