【问题标题】:Adding Items to Collection using MVVM pattern使用 MVVM 模式将项目添加到集合
【发布时间】:2015-02-17 14:27:45
【问题描述】:

我无法通过附加到每个项目的命令访问 ObservableCollection(这是我的 ItemsSource)。

我正在尝试制作两个列表,一个包含所有对象,第二个包含用户选择的对象。

这是我的视图模型。

class ViewModel : VMBase
{
    private ObservableCollection<Card> _cardsCollection;
    public ObservableCollection<Card> CardsCollection
    {
        get { return _cardsCollection; }
        set { _cardsCollection = value; }
    }

    static private ObservableCollection<Card> _pickedCards;
    static public ObservableCollection<Card> PickedCards
    {
        get { return _pickedCards; }
        set { _pickedCards = value;
              NotifyPropertyChanged("PickedCards");
            }
    }
}
class Card : VMBase
{
    public string Name { get; set; }
    public Card(string name, int cost, CardType type, CardRarity rarity)
    {
        this.Name = name;
        this.BackgroundImage = String.Format("/Images/Cards/{0}.png", name);

        this.PickCardCommand = new MvvmCommand();
        this.PickCardCommand.CanExecuteFunc = obj => true;
        this.PickCardCommand.ExecuteFunction = PickCard;
    }
    public MvvmCommand PickCardCommand { get; set; }
    public void PickCard(object parameter)
    {
        PickedCards.Add(currentCard); 
        //Above Does not work, not accessible
        CreateDeckModel.PickedCards.Add(currentCard);
        //Above does work but only if Collection is static
        //but if collection is static I am unable to call NotifyPropertyChanged()
    }
}

这是我的带有绑定的 XAML 文件

<GridView Grid.Row="1" ItemsSource="{Binding CardsCollection, Mode=TwoWay}">
     <GridView.ItemTemplate>
         <DataTemplate>
             <Grid>
                  <Button Height="258" Width="180" Content="{Binding}" Margin="0,0,0,0" 
                          Command="{Binding PickCardCommand}" CommandParameter="{Binding}">
                      <Button.Template>
                          <ControlTemplate>
                              <StackPanel Orientation="Vertical">
                                  <Border BorderThickness="2" BorderBrush="White" Height="258" Width="180">
                                      <Border.Background>
                                          <ImageBrush ImageSource="{Binding BackgroundImage}" />
                                      </Border.Background>
                                   </Border>
                              </StackPanel>
                          </ControlTemplate>
                       </Button.Template>
                   </Button>
               </Grid>
           </DataTemplate>
       </GridView.ItemTemplate>
   </GridView>

这是我的 MvvmCommand 类

class MvvmCommand : ICommand
{
    public Predicate<object> CanExecuteFunc { get; set; }
    public Action<object> ExecuteFunction { get; set; }
    public void Execute(object parameter)
    {
        ExecuteFunction(parameter);
    }

    public event EventHandler CanExecuteChanged;
    public bool CanExecute(object parameter)
    {
        return CanExecuteFunc(parameter);
    }
}

}

有没有办法从 Item 或 DataContext 访问 ItemsSource,或者让 ViewModel 类可以访问命令?

【问题讨论】:

    标签: c# wpf xaml mvvm


    【解决方案1】:

    您可以通过将 xaml 文件中的按钮更改为以下内容,将 Command 指向您的 ViewModel 类:

    <Button Height="258" Width="180" Content="{Binding}" Margin="0,0,0,0" Command="{Binding DataContext.PickCardCommand,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type vw:ViewClass}}}" CommandParameter="{Binding}">
    

    在 RelativeSource 绑定中,您需要更改以下内容:

    vw 是您的视图的命名空间,这必须与您的 xaml 文件中的其他命名空间一起声明。

    ViewClass 是您的班级名称。

    那么您显然需要将 Command 从 Card 类移至 ViewModel 类。

    Windows 手机

    <GridView x:Name="myGridView" Grid.Row="1" ItemsSource="{Binding CardsCollection, Mode=TwoWay}">
         <GridView.ItemTemplate>
             <DataTemplate>
                 <Grid>
                      <Button Height="258" Width="180" Content="{Binding}" Margin="0,0,0,0" 
                              Command="{Binding ElementName=myGridView,
                       Path=DataContext.PickCardCommand}" CommandParameter="{Binding}">
                          <Button.Template>
                              <ControlTemplate>
                                  <StackPanel Orientation="Vertical">
                                      <Border BorderThickness="2" BorderBrush="White" Height="258" Width="180">
                                          <Border.Background>
                                              <ImageBrush ImageSource="{Binding BackgroundImage}" />
                                          </Border.Background>
                                       </Border>
                                  </StackPanel>
                              </ControlTemplate>
                           </Button.Template>
                       </Button>
                   </Grid>
               </DataTemplate>
           </GridView.ItemTemplate>
       </GridView>
    

    您会看到我现在已经命名了 GridView,然后在绑定中使用了 GridView 的名称作为 ElementName。我相信这应该可行。

    【讨论】:

    • 我认为他的命令绑定是正确的,他需要一种方法来访问项目的父集合。
    • 如果他想修改父 ViewModel 上的集合,那么在 ViewModel 上声明 Command 并在那里修改集合会更干净。
    • 很遗憾 FindAncestor 在 Windows Phone 中无法访问。
    • @user2847238 我已经用 Windows Phone 部分更新了我的答案。
    【解决方案2】:

    您可以在创建时将PickedCardsAdd 方法传递给Card

    class Card : VMBase
    {
        private readonly Action<Card> _addCard;
    
        public Card(..., Action<Card> addCard)
        {
            ...
            _addCard = addCard;
    
            this.PickCardCommand = new MvvmCommand();
            this.PickCardCommand.CanExecuteFunc = obj => true;
            this.PickCardCommand.ExecuteFunction = PickCard;
        }
    
        public MvvmCommand PickCardCommand { get; set; }
    
        public void PickCard(object parameter)
        {
            _addCard(this);
        }
    }
    

    那么当你创建卡片时:

    var card = new Card(..., ..., ..., ..., PickedCards.Add)
    

    【讨论】:

      【解决方案3】:

      您可以将您的集合绑定到 Command 参数。命令参数当前绑定到 Item DataSource 而不是集合

      CommandParameter="{Binding}"
      

      改为使用RelativeBinding并绑定到网格的itemSource

      【讨论】:

      • 如果您在相对绑定方面需要帮助,请告诉我
      • 如果你能帮助我就好了。
      猜你喜欢
      • 2011-03-01
      • 2013-11-18
      • 1970-01-01
      • 2012-10-28
      • 2023-03-20
      • 1970-01-01
      • 2016-01-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多