简体   繁体   English

使用MVVM模式将项目添加到集合

[英]Adding Items to Collection using MVVM pattern

I am having truble accessing ObservableCollection (which is my ItemsSource) from command attached to each of the items. 我无法通过附加到每个项目的命令来访问ObservableCollection(这是我的ItemsSource)。

I am trying make two list, one with all the objects and the second one with objects picked by user. 我正在尝试制作两个列表,一个列出所有对象,第二个列出用户选择的对象。

Here is my view model. 这是我的视图模型。

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()
    }
}

Here is my XAML file with binding 这是我的具有绑定的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>

Here is my MvvmCommand Class 这是我的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);
    }
}

} }

Is there a way to access ItemsSource from Item or DataContext alternatively make command accessible for ViewModel Class? 有没有一种方法可以从Item或DataContext访问ItemsSource,或者使ViewModel类可以访问命令?

You can point the Command to your ViewModel class by changing the button in your xaml file to the following: 通过将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}">

In the RelativeSource binding you will need to change the following: 在RelativeSource绑定中,您将需要更改以下内容:

vw is the namespace for your View, this will have to be declared with the other namespaces in your xaml file. vw是View的名称空间,必须与xaml文件中的其他名称空间一起声明。

ViewClass is the name of your class. ViewClass是您的类的名称。

Then you obviously need to move the Command over to the ViewModel class from your Card class. 然后,显然您需要将Command从Card类移到ViewModel类。

Windows Phone Windows Phone

<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>

You will see that I have now named the GridView and then used the name of the GridView in the binding as the ElementName. 您将看到我现在已命名GridView,然后在绑定中将GridView的名称用作ElementName。 I believe this should work. 我相信这应该可行。

You can just pass the Add method of PickedCards to the Card when you create it: 您可以在创建Card时将PickedCardsAdd方法PickedCardsCard

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);
    }
}

Then when you create the card: 然后,当您创建卡时:

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

You can bind your collection to the Command parameter. 您可以将集合绑定到Command参数。 Command parameter is currently bound to Item DataSource and not collection 命令参数当前绑定到Item DataSource而不是集合

CommandParameter="{Binding}"

Instead use RelativeBinding and bind to itemSource of grid 而是使用RelativeBinding并绑定到网格的itemSource

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM