1

我有一个简单ListView的对象列表绑定。在ListView.ItemTemplate我想格式化每个对象并将其绑定到TextBlock使用 x:Bind 函数绑定,如下所示<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget(???)}" />:但是,我不确定如何将对当前项目的引用传递给函数。

如果我需要将项目的属性传递给函数,甚至是多个属性,例如 ,这很好用<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget(Name, Model)}" />,但我不知道如何传递整个对象。

我已经尝试了所有这些都无济于事:

<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget(this)}" />
<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget(self)}" />
<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget({x:Bind})}" />
<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget({Binding})}" />
<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget(Item)}" />
<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget(DataContext)}" />
<TextBlock Name="Root" Text="{x:Bind local:MainViewModel.FormatWidget(Root.DataContext)}" />

作为一种解决方法,我可以创建并绑定到返回自身的数据项上的属性,如下所示:

        public Widget MeMyselfAndI { get => this; }
<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget(MeMyselfAndI)}" />

但是,这是一个 hack,在我的真实项目中,我无法修改数据项类的源以添加属性。

如何将当前项目的引用传递给函数?

这是一个复制品:

主页.xaml

<Page
    x:Class="ListItemFunctionBinding.MainPage"
    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:local="using:ListItemFunctionBinding"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">
    <Grid>
        <ListView ItemsSource="{x:Bind ViewModel.Widgets}" SelectedItem="{x:Bind ViewModel.SelectedItem}">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:Widget">
                    <TextBlock Text="{x:Bind local:MainViewModel.FormatWidget(MeMyselfAndI)}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>

MainPage.xaml.cs

using Windows.UI.Xaml.Controls;

namespace ListItemFunctionBinding
{
    public sealed partial class MainPage : Page
    {
        public MainViewModel ViewModel { get; } = new MainViewModel();

        public MainPage()
        {
            InitializeComponent();
        }
    }
}

主视图模型.cs

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace ListItemFunctionBinding
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private Widget _selectedItem;

        public Widget SelectedItem
        {
            get => _selectedItem;
            set
            {
                if (_selectedItem != value)
                {
                    _selectedItem = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedItem)));
                }
            }
        }

        public ObservableCollection<Widget> Widgets { get; } = new ObservableCollection<Widget>()
        {
            new Widget
            {
                Id = Guid.NewGuid(),
                Name = "Regular Widget",
                Model = "WX2020-01",
                Description = "Your typical everyday widget."
            },
            new Widget
            {
                Id = Guid.NewGuid(),
                Name = "Super Widget",
                Model = "WX2020-02",
                Description = "An extra special upgraded widget."
            },
            new Widget
            {
                Id = Guid.NewGuid(),
                Name = "Broken Widget",
                Model = "WX2020-03",
                Description = "A widget that has been used and abused."
            },
            new Widget
            {
                Id = Guid.NewGuid(),
                Name = "Fake Widget",
                Model = "WX2020-04",
                Description = "It's not really a widget at all!"
            },
            new Widget
            {
                Id = Guid.NewGuid(),
                Name = "Surprise Widget",
                Model = "WX2020-05",
                Description = "What kind of widget will it be?"
            },
            new Widget
            {
                Id = Guid.NewGuid(),
                Name = "Invisible Widget",
                Model = "WX2020-06",
                Description = "Our most inexpensive widget."
            },
            new Widget
            {
                Id = Guid.NewGuid(),
                Name = "Backwards Widget",
                Model = "WX2020-07",
                Description = "Really more of a tegdiw, come to think of it."
            }
        };

        public static string FormatWidget(Widget widget)
        {
            if (widget == null)
                return "No widget selected";
            else
                return $"{widget.Name} [{widget.Model}] {widget.Description}";
        }
    }
}

小部件.cs

using System;
using System.ComponentModel;

namespace ListItemFunctionBinding
{
    public class Widget : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private Guid _id;
        private string _name;
        private string _model;
        private string _description;

        public Widget MeMyselfAndI { get => this; }

        public Guid Id
        {
            get => _id;
            set
            {
                if (_id != value)
                {
                    _id = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Id)));
                }
            }
        }

        public string Name
        {
            get => _name;
            set
            {
                if (_name != value)
                {
                    _name = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
                }
            }
        }

        public string Model
        {
            get => _model;
            set
            {
                if (_model != value)
                {
                    _model = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Model)));
                }
            }
        }

        public string Description
        {
            get => _description;
            set
            {
                if (_description != value)
                {
                    _description = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Description)));
                }
            }
        }
    }
}
4

2 回答 2

1

我在这里找到了解决方案:

无路铸造

本机绑定解析器不提供关键字来表示this为函数参数,但它确实支持无路径转换(例如,{x:Bind (x:String)}),它可以用作函数参数。因此,{x:Bind MethodName((namespace:TypeOfThis))}是执行概念上等效于 的有效方法{x:Bind MethodName(this)}

所以在我原来的例子中,我可以使用<TextBlock Text="{x:Bind local:MainViewModel.FormatWidget((local:Widget))}" />绑定当前列表项。

这完美!耶!

于 2020-03-24T15:30:57.703 回答
0

在这种情况下,您可以使用Converter方法来传递您当前的项目(例如 Widget),然后在 Converter 中调用 MainViewModel.FormatWidget 方法。

.xaml:

<Page.Resources>
    <local:MyConverter x:Key="MyConverter"/>
</Page.Resources>

<Grid>
    <ListView ItemsSource="{x:Bind ViewModel.Widgets}" SelectedItem="{x:Bind ViewModel.SelectedItem}">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:Widget">
                <TextBlock Text="{x:Bind Converter={StaticResource MyConverter}}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

。CS:

public class MyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var widget = value as Widget;
        return MainViewModel.FormatWidget(widget);
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
于 2020-03-20T02:50:01.780 回答