【问题标题】:x:Bind Item in ListView to ViewModelx:将ListView中的项目绑定到ViewModel
【发布时间】:2017-04-11 10:08:52
【问题描述】:

您知道,当您盯着某物看足够长的时间时,它就不再有意义了……我正在尝试将列表视图项的背景属性绑定到它是否是视图模型中集合的一部分。这是我正在使用的简化版本:

<Grid>

    <ListView x:Name="AirportListView"
              SelectionMode="None"
              IsItemClickEnabled="True"
              ItemClick="AirportListView_ItemClick">

        <ListView.ItemTemplate>

            <DataTemplate x:DataType="x:String">

                <Grid Padding="16">

                    <TextBlock Text="{x:Bind}" />

                </Grid>

            </DataTemplate>

        </ListView.ItemTemplate>            

    </ListView>

</Grid>

和:

public sealed partial class MainPage : Page
{
    public ObservableCollection<string> MyAirports { get; set; } = new ObservableCollection<string>();

    public MainPage()
    {
        this.InitializeComponent();

        AirportListView.ItemsSource = new List<string>()
        {
            "EDDB",
            "LGIR",
            "EHAM",
            "LFPO",
            "EGKK"
        };
    }

    private void AirportListView_ItemClick(object sender, ItemClickEventArgs e)
    {
        if (e.ClickedItem is string clickedAirport)
        {
            if (MyAirports.Contains(clickedAirport))
                MyAirports.Remove(clickedAirport);
            else
                MyAirports.Add(clickedAirport);
        }
    }
}

理想情况下,我想要实现的是在数据模板中绑定网格的背景,以便当项目是 MyAirports 的一部分时它是不同的颜色。我只是无法弄清楚如何使用 x:Bind 或 Binding 来做到这一点。我可以想出一些更冗长的方法来实现相同的目标,但想知道是否有更优雅的数据绑定解决方案。

任何想法将不胜感激!

【问题讨论】:

    标签: c# listview uwp


    【解决方案1】:

    您需要使转到 ItemsSource 的集合成为比字符串更丰富的类。它应该包含属性 IsMyAirport,然后它可以绑定到每个 ListViewItem 以及更新其背景。

    <Page ...
        xmlns:local="using:UwpQuestions.Views"
        xmlns:common="using:UwpQuestions.Common">
        <Page.Resources>
            <common:MyBgConverter x:Key="myBgConverter"/>
        </Page.Resources>
    
    <Grid>
        <ListView x:Name="AirportList"
              SelectionMode="None"
              IsItemClickEnabled="True"
              HorizontalContentAlignment="Stretch"
              ItemsSource="{x:Bind Airports}"
              ItemClick="AirportListView_ItemClick">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:AirportItem">
                    <Grid Padding="16" Width="150" Background="{x:Bind IsMyAirport, Mode=OneWay, Converter={StaticResource myBgConverter}}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{x:Bind Name}" />
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
    </Page>
    

    后面有以下代码:

    public sealed partial class AirportListView : Page
    {
        public ObservableCollection<string> MyAirports { get; set; } = new ObservableCollection<string>();
        public ObservableCollection<AirportItem> Airports { get; set; }
    
        public AirportListView()
        {
            this.InitializeComponent();
            Airports = new ObservableCollection<AirportItem>
            {
                new AirportItem {Name = "EDDB"},
                new AirportItem {Name = "LGIR"},
                new AirportItem {Name = "LFPO"},
                new AirportItem {Name = "EGKK"}
            };
        }
    
        private void AirportListView_ItemClick(object sender, ItemClickEventArgs e)
        {
            if (e.ClickedItem is AirportItem clickedAirport)
            {
                if (MyAirports.Contains(clickedAirport.Name))
                {
                    MyAirports.Remove(clickedAirport.Name);
                    clickedAirport.IsMyAirport = false;
                }
                else
                {
                    MyAirports.Add(clickedAirport.Name);
                    clickedAirport.IsMyAirport = true;
                }
            }
        }
    }
    
    public class AirportItem : BindableBase
    {
        private string _name;
        public string Name
        {
            get { return _name; }
            set { SetProperty<string>(ref _name, value); }
        }
    
        private bool _isMyAirport = false;
        public bool IsMyAirport
        {
            get { return _isMyAirport; }
            set { SetProperty<bool>(ref _isMyAirport, value); }
        }
    }
    

    AirportItem 使用 BindableBase 来通知 ListView 类中的属性何时发生变化。它实现了 INotifyPropertyChanged。如果您不熟悉它,您应该阅读 XAML 数据绑定。

    而且,它还使用 MyBgConverter(Laith 定义的)将布尔值更改为不同的背景颜色。

    最后,使用类的 IsMyAirport 属性,您可能不需要单独的 MyAirports 字符串列表。我没有删除它,因为我不确定您是否将它用于其他用途。但是您在 AirportListView_ItemClick 中的逻辑可以更改为仅使用 IsMyAirport 布尔而不是 MyAirports 列表。

    【讨论】:

    • 谢谢佩德罗,是的,这是我实际尝试做的简化版本,但我已经设法做到了,正如你所说的那样,将一个名为 IsMyAirport 的属性“烘焙”到原始类中,并且确保随着对集合的更改而保持更新。现在将尝试让它在我的应用程序中运行。非常感谢!
    【解决方案2】:

    创建一个转换器,将bool 转换为SolidColorBrush 并在绑定中使用它。

    <ListView Background="{x:Bind IsPartOfMyAirports, Converter={StaticResource MyBgConverter}}">
    ...
    </ListView>
    

    您的视图模型将负责通知 IsPartOfMyAirports 的更改。

    您的转换器将如下所示:

    public class MyBgConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            var b = (bool)value;
            var color = b ? Colors.Yellow : Colors.Green;
    
            return new SolidColorBrush(color);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
    

    【讨论】:

    • 嗨,Laith,感谢您的建议。这个想法是绑定每个单独项目的背景,所以我不确定在哪里创建 IsPartOfMyAirports 以便它可以被每个项目更新。
    猜你喜欢
    • 2019-11-09
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 2018-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多