如何使用x:使用与数据模板不同的数据类型绑定

时间:2017-10-23 16:00:14

标签: xaml mvvm data-binding uwp prism

我正在处理一个视图(称为“Familify'”),该视图向用户显示资产列表,并允许他们从列表中删除资产。资产存储在ViewModel中的ObservableCollection中,因此删除命令只需获取资产对象并将其从集合中删除。我在删除'删除'功能工作。这是XAML和代码隐藏:

Familify.xaml

<ListView
    ItemsSource="{Binding Assets}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="80px" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="150px" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="60px" />
                </Grid.ColumnDefinitions>
                <TextBlock
                    Grid.Column="0"
                    Text="{Binding number}" FontFamily="Consolas"/>
                <TextBlock 
                    Grid.Column="1"
                    Text="{Binding type}"/>
                <TextBlock
                    Grid.Column="2"
                    Text="add binding here"/>
                <TextBlock
                    Grid.Column="3"
                    Text="add binding here"/>
                <Button
                    Command="{x:Bind ViewModel.RemoveAssetCommand}"
                    CommandParameter="{Binding}"
                    Content="&#xE894;"
                    FontFamily="Segoe MDL2 Assets"
                    Grid.Column="4">
                </Button>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Familify.xaml.cs

namespace asset_manager.Views
{
    public sealed partial class Familify : UserControl
    {
        FamilifyViewModel ViewModel { get; set; }

        public Familify()
        {
            this.InitializeComponent();
            DataContextChanged += (s, e) =>
            {
                ViewModel = DataContext as FamilifyViewModel;
            };
        }
    }
}

想法是单击该按钮可从列表中删除资产。 (请注意,显示numbertype等的正常绑定工作正常。)到目前为止我的想法:

  1. 尝试使用binding访问页面视图模型中存储的RemoveAssetCommand。但是,我无法获得祖先绑定工作(即尝试在XAML层次结构中找到更高元素的数据上下文并不起作用,因为findAncestor在UWP中不是什么事情。)
  2. x:Bind看起来是一个很好的解决方案,因为它使用了属性的显式路径。所以,如果我在我的代码中声明ViewModel,我可以使用x:Bind ViewModel.property。一切都很好。我这样做了,intellisense允许我在输入时访问ViewModel.RemoveAssetCommand。
  3. 但是,这不起作用,因为我收到错误no DataType defined for DataTemplate。这是有道理的,所以我尝试了两件事。
  4. x:DataType="Models:Asset"(放在上面的DataTemplate标签中)是数据模板中显示的模型,所以我先尝试了。当然,该命令未在模型中声明,它在视图模型中声明,因此无法正常工作。
  5. 我改为尝试x:DataType="ViewModels:FamilifyViewModel",认为我可以使用x:Bind。但是,我得到一个错误,它无法将Asset类型的对象强制转换为FamilifyViewModel。这是有道理的,因为传递给此数据模板的对象属于Asset
  6. 类型

    这很痛苦,因为我认为x:Bind可以工作的全部原因是我可以直接从代码隐藏中的ViewModel访问该属性。

    明确说明,1)是否可以在数据模板中使用x:Bind来访问ViewModel上的基本级别属性(在本例中为Prism命令)? 2)有没有更好的方法来实现这个功能?

1 个答案:

答案 0 :(得分:1)

  

是否可以在数据模板中使用x:Bind来访问ViewModel上的基本级别属性(在本例中为Prism命令)?

是的,如果要访问基本级别,可以重新分配按钮的DataContext,如下所示:

<Button DataContext="{Binding ElementName=Familily, Path=DataContext}"/>

FamilyUserControl的名称。

  

有没有更好的方法来实现此功能?

当您将commad放入ViewModel并按上述方式绑定按钮时。按钮的绑定项将成为系列DataContext。因此,您无法直接在ViewModel

中调用删除操作

实现此功能的最佳做法是将RemoveAssetCommand放入Asset类。并使用ItemsSource ListView作为Button CommandParameter

<Button 
    Command="{Binding RemoveAssetCommand}"
    CommandParameter="{Binding ElementName=MyListView, Path=ItemsSource}"
    Content="&#xE894;"
    FontFamily="Segoe MDL2 Assets"
    Grid.Column="4">
</Button>

<强> Asset.cs

public class Asset
{
    public string number { get; set; }
    public string type { get; set; }
    public ICommand RemoveAssetCommand
    {
        get
        {
            return new CommandHandler<ObservableCollection<Asset>>((item) => this.RemoveAction(item));
        }
    }
    private void RemoveAction(ObservableCollection<Asset> items)
    {
        items.Remove(this);
    }
}

<强> ViewModel.cs

public class FamilifyViewModel
{
    public ObservableCollection<Asset> Assets = new ObservableCollection<Asset>();
    public FamilifyViewModel()
    {
        Assets.Add(new Asset { number = "100001", type = "hello" });
        Assets.Add(new Asset { number = "100001", type = "hello" });
        Assets.Add(new Asset { number = "100001", type = "hello" });
        Assets.Add(new Asset { number = "100001", type = "hello" });
    }        
}

enter image description here