UWP 中使用多个 DataTemplate

2019/03/05

175

UWP软件开发中,如果在 DataTemplate 中显示指定模型的数据类型为一个接口,使用代码更改了属性值后,界面将不会收到值被改变的通知,于是看起来x:Bind似乎无法工作。

解决办法

使用多个 DataTemplate ,在渲染时,根据某些参数动态选择 DataTemplate,这时候 DataTemplate 的 DataType 指定的就是具体的类型,而不是接口,继而绑定就能正常工作了。

c#

public sealed partial class TestPage : Page
{
    public TestPage()
    {
        InitializeComponent();
        Persons = new ObservableCollection<IPerson>
        {
            new APerson { Name = "Actor" },
            new BPerson { Name = "Bctor" }
        };
    }

    ObservableCollection<IPerson> Persons { get; }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        foreach (var item in Persons)
        {
            item.Name = "foreach";
        }
    }
}

public interface IPerson
{
    string Name { get; set; }
}

public class APerson : IPerson, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

public class BPerson : IPerson, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

public class PersonDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate APersonTemplate { get; set; }
    public DataTemplate BPersonTemplate { get; set; }

    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        if (item.GetType() == typeof(APerson))
        {
            return APersonTemplate;
        }
        else
        {
            return BPersonTemplate;
        }
    }
}

xaml

<ListView ItemsSource="{x:Bind Persons}">
    <ListView.Resources>
        <DataTemplate x:Key="APersonTemplate" x:DataType="local:APerson">
            <TextBlock Text="{x:Bind Name, Mode=OneWay}" Foreground="Red"/>
        </DataTemplate>
        <DataTemplate x:Key="BPersonTemplate" x:DataType="local:BPerson">
            <TextBlock Text="{x:Bind Name, Mode=OneWay}" Foreground="Blue"/>
        </DataTemplate>
    </ListView.Resources>

    <ListView.ItemTemplateSelector>
        <local:PersonDataTemplateSelector APersonTemplate="{StaticResource APersonTemplate}" BPersonTemplate="{StaticResource BPersonTemplate}"/>
    </ListView.ItemTemplateSelector>
</ListView>
评论