如何在ListViewItem的DataTemplate中绑定IsSelected属性

时间:2016-10-30 10:03:12

标签: xaml uwp

好吧,我想在UWP中制作ListViewItem,这将改变他对选择的看法。所以我需要在选择时更改Visibility的某些元素的ListViewItem属性。

我找到了一些方法来制作自定义样式的ListViewItem和绑定IsSelected属性,如下所示:

<Style x:Key="VehicleListViewItemStyle" TargetType="ListViewItem" >
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListViewItem">
                        <Grid Background="Gray" Margin="1">
                            <Border Margin="2" Padding="10" Background="Gray" >
                                <StackPanel>
                                    <ContentPresenter x:Name="Presenter1" />
                                    <StackPanel Orientation="Horizontal" Background="Transparent" Margin="-10,0,-9,-9" VerticalAlignment="Center" x:Name="infoPanel"
                                        Visibility="{Binding IsSelected, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}">
                                        <TextBlock Text="{Binding  DeviceID}/>                                                                            </StackPanel>
                                </StackPanel>
                            </Border>
                            <Border BorderThickness="1" BorderBrush="Orange" Visibility="{Binding IsSelected, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>  

它运作良好,但通过这种方式我无法绑定DeviceID文本。

另一种方法是像这样创建DataTemplate

<DataTemplate x:Key="monitoringListViewItem" x:Name="item">
            <Grid Background="Gray" Margin="1" Width="300" >
                <StackPanel>
                    <ContentPresenter x:Name="Presenter"/>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="/Assets/14th_crane_stop.png" Height="50" Width="50" Stretch="Uniform"/>
                        <StackPanel Orientation="Vertical" Margin="25,0,0,0 " 
                                    Visibility="{Binding IsSelected, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}"
                                    >
                            <TextBlock Text="{Binding DeviceID}" Style="{StaticResource VehicleTextStyle}"/>
                            <TextBlock Text="{Binding Mark}" Style="{StaticResource VehicleTextStyle}"/>
                        </StackPanel>
                    </StackPanel>
                </StackPanel >
            </Grid>
        </DataTemplate>

现在我可以正确绑定文本,但无法绑定IsSelected属性。我尝试使用不同的模式执行此操作,但它仍然无法正常工作,因为我无法使用DataTemplate中的TemplatedParent键。

所以我需要一些答案:

- 我可以用第一种方式绑定文本,我该怎么做? - 我可以用第二种方式绑定IsSelected属性吗?

2 个答案:

答案 0 :(得分:2)

我不建议更改ListViewItem模板,因为它会丢失它提供的所有铃声和哨声(选择外观,检查能力等)。

在第二个代码段中使用Mode=TemplatedParent将不起作用,因为来自该上下文的模板化父级是ListViewItemPresenter,而不是ListViewItem(它是演示者的父级)。

看起来你要做的就是在选择列表项时显示其他信息。

单一选择

C#类

public class NotifyPropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetProperty<T>(ref T property, T value, [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<T>.Default.Equals(property, value))
        {
            return false;
        }

        property = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

public class Item : NotifyPropertyChangedBase
{
    private string text;
    public string Text
    {
        get { return text; }
        set { SetProperty(ref text, value); }
    }

    private bool isSelected;
    public bool IsSelected
    {
        get { return isSelected; }
        set { SetProperty(ref isSelected, value); }
    }
}

public class MainPageViewModel : NotifyPropertyChangedBase
{
    public List<Item> Items { get; set; }

    private Item selectedItem;
    public Item SelectedItem
    {
        get { return selectedItem; }
        set
        {
            if (selectedItem != value)
            {
                if (selectedItem != null)
                {
                    selectedItem.IsSelected = false;
                }

                SetProperty(ref selectedItem, value);

                if (selectedItem != null)
                {
                    selectedItem.IsSelected = true;
                }
            }
        }
    }

    public MainPageViewModel()
    {
        Items = new List<Item>()
        {
            new Item() { Text = "Apple" },
            new Item() { Text = "Banana" },
        };
    }
}

<强> MainPage.xaml中

<ListView ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Item">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>

                <TextBlock Text="{Binding Text}"/>

                <!-- x:Bind doesn't require visibility converter if min SDK is targeting Anniversary update -->
                <TextBlock Text="I'm selected!" Grid.Column="1" Visibility="{x:Bind IsSelected, Mode=OneWay}"/>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

<强> MainPage.xaml.cs中

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        DataContext = new MainPageViewModel();
    }
}

Screenshot

多项选择

与单一选择相同,但有以下更改:

<强> MainPageViewModel

public class MainPageViewModel : NotifyPropertyChangedBase
{
    public List<Item> Items { get; set; }

    public MainPageViewModel()
    {
        Items = new List<Item>()
        {
            new Item() { Text = "Apple" },
            new Item() { Text = "Banana" },
        };
    }

    public void SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        foreach (Item item in e.RemovedItems)
        {
            item.IsSelected = false;
        }

        foreach (Item item in e.AddedItems)
        {
            item.IsSelected = true;
        }
    }
}

<强> MainPage.xaml中

<ListView ItemsSource="{Binding Items}" SelectionChanged="{x:Bind ViewModel.SelectionChanged}" SelectionMode="Extended">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Item">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>

                <TextBlock Text="{Binding Text}"/>
                <TextBlock Text="I'm selected!" Grid.Column="1" Visibility="{x:Bind IsSelected, Mode=OneWay}"/>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

<强> MainPage.xaml.cs中

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        DataContext = new MainPageViewModel();
    }

    public MainPageViewModel ViewModel => (MainPageViewModel)DataContext;
}

Screenshot

答案 1 :(得分:0)

要回答该主题中的实际问题:是,可以很容易地绑定ListViewItem.IsSelected。确保您的DataTemplate内容包装在ListViewItem中。

<ListView.ItemTemplate>
    <DataTemplate x:DataType="local:MyItemViewModel">
        <ListViewItem IsSelected="{Binding IsSelected, Mode=TwoWay}">
            <Grid>
                // template content
            </Grid>
        </ListViewItem>
    </DataTemplate>
</ListView.ItemTemplate>

请注意,这里有许多有关WPF的问答,说这是行不通的。它确实适用于UWP(至少从SDK 10.0.19041开始)。 WPF的答案建议将其绑定在ItemsPanelTemplate或ResourceDictionary中。由于某些原因,这在UWP中不起作用。