UWP XAML: Bindings.Update() 不会触发内部项目

UWP XAML: Bindings.Update() doesn't trigger inner items

如果我有带有 x:Bind 绑定的 GridView 项,调用 Bindings.Update() 无效。 None 的 Items 绑定属性被再次读取。它停留在第一次初始化的值上。

但是 Bindings.Update() 可以完美地触发绑定属性的顶级重新读取(如 Width="{x:Bind GridWidth}")。我在页面调整大小事件中调用 Bindings.Update()。

如何强制 Xaml 重新读取项目属性?项目列表本身没有改变(列表 count/content),只有 一些 的项目属性(如 Width="{x:Bind ItemWidth}")。

示例:

<!-- Working, re-read -->
<Grid Width="{x:Bind GridWidth}">
    <GridView x:Name="barGrid" ItemsSource="{x:Bind projects}" Background="Aqua" Grid.Row="0">
        <GridView.ItemTemplate>
            <DataTemplate x:Name="DoubleBars" x:DataType="local:Project">
                <!-- This isn't re-read !!! !!! !!! -->
                <StackPanel x:Name="projectItemStack" Width="{x:Bind ItemWidth}" Background="Orange">
                    <Grid>
                        <Rectangle x:Name="RedBar" Fill="Red"/>
                        <TextBlock Text="Test0"/>
                    </Grid>
                    <Grid Margin="0, 3, 0, 5">
                        <Rectangle x:Name="GreenBar" Fill="Lime"/>
                        <TextBlock Text="Test1"/>
                    </Grid>
                </StackPanel>
            </DataTemplate>
        </GridView.ItemTemplate>

        <GridView.ItemsPanel>
            <ItemsPanelTemplate/>
        </GridView.ItemsPanel>

    </GridView>
</Grid>

如果你想实现 属性 从绑定对象(项目 class)更改更新,你必须使对象(项目 class)实现 INotifyPropertyChanged Interface and make the Property subscribe the PropertyChanged event, meanwhile, you should also specific that the x:Bind mode to be OneWay or a TwoWay. More details about binding in UWP app, you can learn from Data binding主题。

为了澄清这一点,我根据您的 xaml 代码创建了一个示例。

这里是 Project class 实现了 INotifyPropertyChanged Interface.

public class Project:INotifyPropertyChanged
{
    private double itemWidth;
    public double ItemWidth
    {
        get
        {
            return itemWidth;
        }
        set
        {
            itemWidth = value;
            OnPropertyChanged("ItemWidth");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

在 xaml 中,我更改了您的代码以添加一个按钮来更改项目的 属性 并将 x:Bind 模式设置为 OneWay,更多区别请看BindingMode Enum.

<Grid Width="{x:Bind GridWidth}">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <GridView x:Name="barGrid" ItemsSource="{x:Bind projects,Mode=OneWay}" Background="Aqua" Grid.Row="0">
        <GridView.ItemTemplate>
            <DataTemplate x:Name="DoubleBars" x:DataType="local:Project">
                <!-- This isn't re-read !!! !!! !!! -->
                <StackPanel x:Name="projectItemStack" Width="{x:Bind ItemWidth,Mode=OneWay}" Background="Orange">
                    <Grid>
                        <Rectangle x:Name="RedBar" Fill="Red"/>
                        <TextBlock Text="Test0"/>
                    </Grid>
                    <Grid Margin="0, 3, 0, 5">
                        <Rectangle x:Name="GreenBar" Fill="Lime"/>
                        <TextBlock Text="Test1"/>
                    </Grid>
                </StackPanel>
            </DataTemplate>
        </GridView.ItemTemplate>

        <GridView.ItemsPanel>
            <ItemsPanelTemplate/>
        </GridView.ItemsPanel>
    </GridView>

    <Button Click="Button_Click" Content="Click me to change the Items width"/>
</Grid>

这是后面的page.xaml.cs代码,

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        projects = new ObservableCollection<Project>();
        projects.Add(new Project { ItemWidth = 300 });
        projects.Add(new Project { ItemWidth = 400 });
        projects.Add(new Project { ItemWidth = 500 });
        projects.Add(new Project { ItemWidth = 600 });
        projects.Add(new Project { ItemWidth = 700 });
    }

    ObservableCollection<Project> projects;
    public double GridWidth { get; set; } = 1000;

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        foreach(var item in projects)
        {
            item.ItemWidth += 100;
        }
    }
}

然后当你点击Button并改变ItemWidth 属性时你可以看到变化。