【问题标题】:How to use a Binding of the ViewModel instead of the DataType of a ListView?如何使用 ViewModel 的 Binding 而不是 ListView 的 DataType?
【发布时间】:2016-09-28 15:00:32
【问题描述】:

首先让我为这个可能有点模糊的标题道歉,我很难解释我的问题!也许这就是为什么我几乎没有得到任何谷歌结果的原因,这篇文章最接近我的问题(我认为):How to bind to a property of the ViewModel from within a GridView

无论如何,我有一个动态生成的新闻文章列表。用户可以选择按下“星号”按钮以将文章添加到他/她的收藏夹列表中。因此,这个“星”按钮应该只在用户登录时可见。

我试图通过在我的 ViewModel 中将 Button 的 Visibility 设置为一个名为 IsLoggedIn 的属性来实现这一点。但是,因为这发生在我的 ListView 中,所以它试图在 Article 中而不是 ViewModel 中找到属性 IsLoggedIn。

所以我想我的问题归结为:如何绑定到 Databound ListView 内的 ViewModel 属性?

<ListView ItemsSource="{x:Bind VM.Articles, Mode=OneWay}" ItemClick="DebuggableListView_ItemClick" IsItemClickEnabled="True" SelectionMode="None" Grid.Row="1" VerticalAlignment="Top">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="models:Article">
            <Grid Margin="0,10,10,10">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*"/>
                    <ColumnDefinition Width="4*"/>
                </Grid.ColumnDefinitions>

                <Image Source="{Binding Image}" Margin="0,0,10,0" Grid.Column="0" VerticalAlignment="Top" ImageFailed="Image_ImageFailed"/>
                <Button Visibility="{x:Bind VM.IsLoggedIn, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}" FontFamily="Segoe MDL2 Assets" Content="&#xE734;" FontSize="30" Background="Transparent" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
                <StackPanel Grid.Column="1">
                    <TextBlock TextWrapping="Wrap" FontWeight="Bold" Text="{Binding Title}"/>
                    <TextBlock TextWrapping="Wrap" Text="{Binding Summary}"/>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

请求的文章类别:

public sealed class Article
{
    public int Id { get; set; }
    public int Feed { get; set; }
    public string Title { get; set; }
    public string Summary { get; set; }
    public DateTime PublishDate { get; set; }
    public string Image { get; set; }
    public string Url { get; set; }
    public string[] Related { get; set; }
    public Category[] Categories { get; set; }
    public bool IsLiked { get; set; }
}

好的,所以目前我通过拥有一个获取我的 VM 的单例的属性来使其工作,但是我确信必须有一种更简洁的方法来让像这样简单的东西工作。我添加了一个示例 rar(OneDrive 链接:https://1drv.ms/u/s!Ar4fOTiwmGYnyWbwRY6rM0eFsL9x),其中包含一个列表、一个 ViewModel、一些虚拟数据和 VM 内的 Visibility 属性。如果您可以在没有我肮脏的方法的情况下使其正常工作,请随时提交作为答案。

【问题讨论】:

  • 你看this answer了吗?
  • 你能用Articles Class更新你的问题吗
  • @EdPlunkett 我猜您指的是该答案中的最后一段代码?试图让那部分在我的案例 atm 中工作。
  • @AVKNaidu 我添加了 Article 类,认为模型没有多大帮助。
  • 是的,我这里没有用于编译 UWP 项目的设置,但我认为他是说您应该能够在代码隐藏中将 DataContext 公开为 VM 属性并使用x:Bind 你有绑定——除非我误解了。

标签: c# xaml listview mvvm uwp


【解决方案1】:

这种类型问题可以最好地使用相对绑定来解决。您可以绑定到任何祖先元素的属性,而不是直接绑定到当前 DataContext,即在这种情况下是 ListView 的 ItemsSource 中的单个项目。

给定一个简单的 ViewModel 类

public class ViewModel: ViewModelBase
{
    private bool _isLoggedIn;
    public bool IsLoggedIn
    {
        get { return _isLoggedIn; }
        set
        {
            _isLoggedIn = value;
            RaisePropertyChanged(() => IsLoggedIn);
        }
    }

    public IEnumerable<string> Items
    { get { return new[] {"One", "Two", "Theee", "Four", "Five"}; } }
}

View 可以定义为

<Window x:Class="ParentBindingTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ParentBindingTest"
        Title="MainWindow"
        Width="300" Height="400">

    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>

    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <CheckBox Margin="16,8" HorizontalAlignment="Left" Content="Logged In?" IsChecked="{Binding IsLoggedIn, Mode=TwoWay}" />

        <ListView Grid.Row="1" Margin="16,8" ItemsSource="{Binding Items}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Button Visibility="{Binding Path=DataContext.IsLoggedIn, RelativeSource={RelativeSource AncestorType={x:Type ListView}}, Converter={StaticResource BooleanToVisibilityConverter}}">
                            <Image Source="Images\remove.png" />
                        </Button>

                        <TextBlock Text="{Binding}" />
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Window>

注意在项目 DataTemplate 中,TextBlock 的 Text 属性如何直接绑定到项目。

但是,Button 的 Visibility 不是绑定到它自己的 DataContext 的属性,而是使用相对绑定绑定到 ListView 本身的属性。

【讨论】:

  • 这对非原始类型列表有效吗? (在我的情况下是文章而不是字符串)
  • “成员 AncestorType 未被识别为或不可访问”,我猜这仅适用于 WPF,但不适用于 UWP
  • 我现在没有 Windows 10,所以我无法测试它,但这个问题的接受答案stackoverflow.com/questions/32861612 似乎有 UWP 的答案 - 命名 ListView通过 ElementName 控制和绑定
  • 所以事实证明 x:Bind 是我需要的问题。使用传统绑定以及使用 ListView ElementName 修复它。如果您更新答案以反映这一点,我可以接受它作为答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-23
  • 1970-01-01
  • 1970-01-01
  • 2014-07-08
  • 2012-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多