C# UWP Xaml Textblock数据绑定-即使属性已更新,UI也不更新

C# UWP Xaml Textblock数据绑定-即使属性已更新,UI也不更新,c#,xaml,data-binding,uwp,inotifypropertychanged,C#,Xaml,Data Binding,Uwp,Inotifypropertychanged,首先是一个免责声明:我读了几十篇帖子,有数百个答案,但我还没有找到解决办法。我已经尝试用我能找到的每一种方法来解决这个问题,但是UI没有更新 我正在写一个UWP应用程序作为个人项目。在这个特定的场景中,我有一个网格,其中有一个指定的DataContext和一系列绑定到属性的TextBlock。我使用的是“绑定”而不是“x:Bind”,因为网格是ControlTemplate的一部分 我已使用INotifyPropertyChanged实现了属性 我有后备领域 我已完成调试,属性已更新并保留指定

首先是一个免责声明:我读了几十篇帖子,有数百个答案,但我还没有找到解决办法。我已经尝试用我能找到的每一种方法来解决这个问题,但是UI没有更新

我正在写一个UWP应用程序作为个人项目。在这个特定的场景中,我有一个网格,其中有一个指定的DataContext和一系列绑定到属性的TextBlock。我使用的是“绑定”而不是“x:Bind”,因为网格是ControlTemplate的一部分

  • 我已使用INotifyPropertyChanged实现了属性
  • 我有后备领域
  • 我已完成调试,属性已更新并保留指定的值
  • 我已尝试使用UpdateSourceTrigger=PropertyChanged
  • 我尝试过不同的模式-单向/双向等
问题是:UI完全忽略更改,从不更新

我已经在页面构造函数中设置了一个值来设置属性,这已经设置好了,但是此后没有应用任何更改。。。永远

请看下面的相关代码片段,也许有人可以看到我没有看到的东西

提前谢谢

网格XAML:

<Grid
    Grid.Row="1"
    BorderBrush="{StaticResource SystemControlChromeLowAcrylicElementBrush}"
    BorderThickness="2,0,2,2">
    <Grid.DataContext>
        <views:MenusPage />
    </Grid.DataContext>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="auto" />
        <ColumnDefinition Width="auto" />
        <ColumnDefinition Width="152" />
        <ColumnDefinition Width="152" />
        <ColumnDefinition Width="152" />
        <ColumnDefinition Width="152" />
        <ColumnDefinition Width="152" />
    </Grid.ColumnDefinitions>

    <TextBlock
        Grid.Row="0"
        Grid.Column="0"
        Grid.ColumnSpan="3"
        Padding="15,0,0,0"
        HorizontalAlignment="Left"
        VerticalAlignment="Center"
        FontWeight="Bold"
        Text="Totals" />

    <Border
        Grid.Row="0"
        Grid.Column="3"
        Margin="0,2,0,-2"
        BorderBrush="{StaticResource SystemControlChromeLowAcrylicElementBrush}"
        BorderThickness="2,0,0,0">
        <TextBlock
            Padding="10,0,0,0"
            VerticalAlignment="Center"
            FontWeight="Bold"
            Text="{Binding CaloriesTotal, Mode=OneWay}" />
    </Border>
    <Border
        Grid.Row="0"
        Grid.Column="4"
        Margin="0,2,0,-2"
        BorderBrush="{StaticResource SystemControlChromeLowAcrylicElementBrush}"
        BorderThickness="2,0,0,0">
        <TextBlock
            Padding="10,0,0,0"
            VerticalAlignment="Center"
            FontWeight="Bold"
            Text="{Binding ProteinTotal}" />
    </Border>
    <Border
        Grid.Row="0"
        Grid.Column="5"
        Margin="0,2,0,-2"
        BorderBrush="{StaticResource SystemControlChromeLowAcrylicElementBrush}"
        BorderThickness="2,0,0,0">
        <TextBlock
            Padding="10,0,0,0"
            VerticalAlignment="Center"
            FontWeight="Bold"
            Text="{Binding FatTotal}" />
    </Border>
    <Border
        Grid.Row="0"
        Grid.Column="6"
        Margin="0,2,0,-2"
        BorderBrush="{StaticResource SystemControlChromeLowAcrylicElementBrush}"
        BorderThickness="2,0,0,0">
        <TextBlock
            Padding="10,0,0,0"
            VerticalAlignment="Center"
            FontWeight="Bold"
            Text="{Binding CarbTotal}" />
    </Border>
    <Border
        Grid.Row="0"
        Grid.Column="7"
        Margin="0,2,0,-2"
        BorderBrush="{StaticResource SystemControlChromeLowAcrylicElementBrush}"
        BorderThickness="2,0,0,0">
        <TextBlock
            Padding="15,0,0,0"
            VerticalAlignment="Center"
            FontWeight="Bold"
            Text="{Binding SugarTotal}" />
    </Border>

</Grid>
财产变更:

public event PropertyChangedEventHandler PropertyChanged;

private void Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
    if (Equals(storage, value))
    {
        return;
    }

    storage = value;
    OnPropertyChanged(propertyName);
}

private void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

请将绑定DataContext用于主对象,而不是DataGrid:

<Window.DataContext>
    <views:MenusPage />
</Window.DataContext>

我找到了解决方案,虽然我对它的实际工作原理感到目瞪口呆,而其他本该工作的“正常”解决方案却没有,但我无法理解

无论如何,感谢@jsmyth886和@Alexey在故障排除方面提供的帮助和建议

发布此问题后,我尝试将属性分离到另一个类中,在
中引用
——失败

我尝试设置
页面的
DataContext
本身——失败

XAML是,
ControlTemplate
的一部分,我甚至将块移出了控制模板,移到了页面本身,以消除与其他数据源的冲突-请注意,所有命名结构和路径都不同,所以最终不应该发生冲突-这也不起作用,所以——失败了

是@Alexey的回应让我换了一条思路,我的搜索最终让我找到了这篇文章,它解决了我的问题

我从网格中删除了以下datacontext:

<Grid.DataContext>
    <views:MenusPage />
</Grid.DataContext>
最后将a Name属性添加到页面本身:

x:Name="_this"
成功了

我没有改变我设置属性的方式

我的属性仍然是根据问题定义的,我没有viewmodels或其他类,也没有在CodeBehind中设置DataContext

只需将
DataContext=“{Binding ElementName=\u this}”
网格和
x:Name=“\u this”
添加到页面中,就可以让UI每次反映对属性的更改

一个奇怪的简单解决方案

注意:尽管如此,当我尝试不同的事情时,当我在ContentTemplate之外的页面上有网格时,我在codebehind
DataContext=this中设置了页面的DataContext并开始填充,但仍然无法影响控件模板中的网格

所以,除非有我没有看到的冲突,或者因为我有其他不相关的数据源,并且直接分配给需要它的控件。。。我不明白为什么它现在可以使用这个简单的绑定


无论如何,感谢您的帮助,我希望这对以后的其他人有所帮助。

如果您想从NavigationCacheMode(已启用/必需)中获益以提高性能,您必须在数据上下文更改时更新绑定

 public MainPage()
 {
      this.InitializeComponent();

      this.DataContextChanged += (s, e) => this.Bindings.Update();
 }

对于每个属性上的
,这是一个非常有趣的实现。调用
Set
方法时,
propertyName
是什么,是null还是正确的属性名?@jsmyth886属性名传递正确,每次填充的值都正确。我甚至尝试过Microsoft文档中规定的相同配置,其中传递的字符串值仍然会更新属性,但不会更新UI,这毫无意义。单步执行代码显示属性上设置了值。嗯,我刚刚尝试了您的实现,它对我很有效。但是我使用的是Caliburn框架,它已经实现了
INotifyPropertyChanged
,所以我只是在
集合中调用了它。调试时,输出窗口中是否存在任何
绑定
错误?@jsmyth886只需运行调试以确保不会显示任何错误是否有可能创建了两次
菜单页
,但只将一次附加到
网格
,因此,看起来属性在代码中发生了更改,但实际上没有通知UI,因为
网格附加了不同的实例?如果看不到更多的代码,就很难理解更改
网格的
DataContext
应该没有问题。我还要指出标记
不是UWP的一部分。@jsmyth886根元素是什么?使用它而不是网格,并将这些线立即放在这个根中element@Alexey我又给了你一次机会,但也失败了,还是不行。
<Grid ... DataContext="{Binding ElementName=_this}">
    ...
    <TextBlock ... Text="{Binding CaloriesTotal}" />
    ...
</Grid>
x:Name="_this"
 public MainPage()
 {
      this.InitializeComponent();

      this.DataContextChanged += (s, e) => this.Bindings.Update();
 }