UWP Xaml 文本块数据绑定 - UI 即使 属性 已更新也未更新
UWP Xaml Textblock Data Binding - UI not updating even though the property is updated
首先免责声明:我已经阅读了数十篇帖子和数百个答案,但我还没有找到解决方案。我已经尝试用我能找到的所有方法解决这个问题,但 UI 没有更新。
我正在编写一个 UWP 应用作为个人项目。在这个特定的场景中,我有一个网格,其中分配了 DataContext,其中包含一系列绑定到属性的 TextBlock。我使用的是 "Binding" 而不是 "x:Bind",因为网格是 ControlTemplate 的一部分。
- 我已经使用 INotifyPropertyChanged 实现了属性。
- 我有支持字段。
- 我已完成调试,属性已更新并保留分配的值。
- 我试过使用 UpdateSourceTrigger=PropertyChanged。
- 我尝试了不同的模式 - OneWay/TwoWay 等等
问题: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>
属性:
private double _caloriesTotal;
public double CaloriesTotal
{
get { return _caloriesTotal; }
set { Set(ref _caloriesTotal, value); }
}
private double _proteinTotal;
public double ProteinTotal
{
get { return _proteinTotal; }
set { Set(ref _proteinTotal, value); }
}
private double _fatTotal;
public double FatTotal
{
get { return _fatTotal; }
set { Set(ref _fatTotal, value); }
}
private double _carbTotal;
public double CarbTotal
{
get { return _carbTotal; }
set { Set(ref _carbTotal, value); }
}
private double _sugarTotal;
public double SugarTotal
{
get { return _sugarTotal; }
set { Set(ref _sugarTotal, value); }
}
属性已更改:
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));
代码设置值:
(注意:这是缩短的版本,但同样的效果适用,在构造函数中设置值应用值和 UI 更新但在页面上其他任何地方设置值,在任何执行的方法中,它们将被忽略UI 显示零。)
CaloriesTotal = 10;
ProteinTotal = 20;
FatTotal = 30;
CarbTotal = 40;
SugarTotal = 50;
请为您的主要对象使用绑定 DataContext,而不是为 DataGrid:
<Window.DataContext>
<views:MenusPage />
</Window.DataContext>
我找到了解决方案,虽然我对它的实际工作方式感到目瞪口呆,而其他 'normal' 本应有效的解决方案却没有,但我无法理解。
无论如何感谢@jsmyth886 和@Alexey 在故障排除方面的帮助和建议。
自从 post 提出这个问题后,我尝试将属性分离到另一个 class,在 <Page.Resources>
块 中引用 <Models:MenuTypesModel x:Key="MenuTotals" />
--失败
我尝试设置 Page
本身的 DataContext
-- 失败
如前所述,我问题中的 <Grid> ... </Grid>
XAML 是 ControlTemplate
的一部分,我什至将块从控制模板移到页面本身以消除任何与其他数据源冲突 - 请注意所有不同的命名结构和路径,所以最终不应该发生冲突 - 这也不起作用,所以 -- 失败
@Alexey 的回应让我换了思路,我的搜索最终让我找到了这个 post Binding to Self/'this' in XAML,它解决了我的问题。
我从网格中删除了以下数据上下文:
<Grid.DataContext>
<views:MenusPage />
</Grid.DataContext>
并用 DataContext="{Binding ElementName=_this}"
替换它并确保我的文本块绑定,最终结果(非常短的版本):
<Grid ... DataContext="{Binding ElementName=_this}">
...
<TextBlock ... Text="{Binding CaloriesTotal}" />
...
</Grid>
最后将名称属性添加到页面本身:
x:Name="_this"
成功了!!!!
我设置属性的方式没有任何变化。
我的属性仍然按照问题定义,我没有视图模型或其他 classes,我也没有在 CodeBehind 中设置 DataContext。
只需将 DataContext="{Binding ElementName=_this}"
网格和 x:Name="_this"
添加到页面就可以让 UI 每次都反映对属性的更改。
一个非常简单的解决方案。
注意:虽然,虽然我尝试了不同的事情,但当我在 ContentTemplate 之外的页面本身上有网格时,我在代码隐藏 DataContext = this;
中设置了页面的 DataContext 并开始填充但还是没能影响到Control模板中的Grid。
所以除非有我没有看到的冲突,或者因为我有其他不相关的数据源以及直接分配给需要它的控件......我无法理解为什么它现在可以使用这个简单的绑定。
无论如何,感谢您的帮助,我希望这对以后的其他人有所帮助。
如果您想从 NavigationCacheMode (Enabled/Required) 中受益以提高性能,则必须在数据上下文更改时更新绑定。
public MainPage()
{
this.InitializeComponent();
this.DataContextChanged += (s, e) => this.Bindings.Update();
}
首先免责声明:我已经阅读了数十篇帖子和数百个答案,但我还没有找到解决方案。我已经尝试用我能找到的所有方法解决这个问题,但 UI 没有更新。
我正在编写一个 UWP 应用作为个人项目。在这个特定的场景中,我有一个网格,其中分配了 DataContext,其中包含一系列绑定到属性的 TextBlock。我使用的是 "Binding" 而不是 "x:Bind",因为网格是 ControlTemplate 的一部分。
- 我已经使用 INotifyPropertyChanged 实现了属性。
- 我有支持字段。
- 我已完成调试,属性已更新并保留分配的值。
- 我试过使用 UpdateSourceTrigger=PropertyChanged。
- 我尝试了不同的模式 - OneWay/TwoWay 等等
问题: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>
属性:
private double _caloriesTotal;
public double CaloriesTotal
{
get { return _caloriesTotal; }
set { Set(ref _caloriesTotal, value); }
}
private double _proteinTotal;
public double ProteinTotal
{
get { return _proteinTotal; }
set { Set(ref _proteinTotal, value); }
}
private double _fatTotal;
public double FatTotal
{
get { return _fatTotal; }
set { Set(ref _fatTotal, value); }
}
private double _carbTotal;
public double CarbTotal
{
get { return _carbTotal; }
set { Set(ref _carbTotal, value); }
}
private double _sugarTotal;
public double SugarTotal
{
get { return _sugarTotal; }
set { Set(ref _sugarTotal, value); }
}
属性已更改:
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));
代码设置值: (注意:这是缩短的版本,但同样的效果适用,在构造函数中设置值应用值和 UI 更新但在页面上其他任何地方设置值,在任何执行的方法中,它们将被忽略UI 显示零。)
CaloriesTotal = 10;
ProteinTotal = 20;
FatTotal = 30;
CarbTotal = 40;
SugarTotal = 50;
请为您的主要对象使用绑定 DataContext,而不是为 DataGrid:
<Window.DataContext>
<views:MenusPage />
</Window.DataContext>
我找到了解决方案,虽然我对它的实际工作方式感到目瞪口呆,而其他 'normal' 本应有效的解决方案却没有,但我无法理解。
无论如何感谢@jsmyth886 和@Alexey 在故障排除方面的帮助和建议。
自从 post 提出这个问题后,我尝试将属性分离到另一个 class,在 <Page.Resources>
块 中引用 <Models:MenuTypesModel x:Key="MenuTotals" />
--失败
我尝试设置 Page
本身的 DataContext
-- 失败
如前所述,我问题中的 <Grid> ... </Grid>
XAML 是 ControlTemplate
的一部分,我什至将块从控制模板移到页面本身以消除任何与其他数据源冲突 - 请注意所有不同的命名结构和路径,所以最终不应该发生冲突 - 这也不起作用,所以 -- 失败
@Alexey 的回应让我换了思路,我的搜索最终让我找到了这个 post Binding to Self/'this' in XAML,它解决了我的问题。
我从网格中删除了以下数据上下文:
<Grid.DataContext>
<views:MenusPage />
</Grid.DataContext>
并用 DataContext="{Binding ElementName=_this}"
替换它并确保我的文本块绑定,最终结果(非常短的版本):
<Grid ... DataContext="{Binding ElementName=_this}">
...
<TextBlock ... Text="{Binding CaloriesTotal}" />
...
</Grid>
最后将名称属性添加到页面本身:
x:Name="_this"
成功了!!!!
我设置属性的方式没有任何变化。
我的属性仍然按照问题定义,我没有视图模型或其他 classes,我也没有在 CodeBehind 中设置 DataContext。
只需将 DataContext="{Binding ElementName=_this}"
网格和 x:Name="_this"
添加到页面就可以让 UI 每次都反映对属性的更改。
一个非常简单的解决方案。
注意:虽然,虽然我尝试了不同的事情,但当我在 ContentTemplate 之外的页面本身上有网格时,我在代码隐藏 DataContext = this;
中设置了页面的 DataContext 并开始填充但还是没能影响到Control模板中的Grid。
所以除非有我没有看到的冲突,或者因为我有其他不相关的数据源以及直接分配给需要它的控件......我无法理解为什么它现在可以使用这个简单的绑定。
无论如何,感谢您的帮助,我希望这对以后的其他人有所帮助。
如果您想从 NavigationCacheMode (Enabled/Required) 中受益以提高性能,则必须在数据上下文更改时更新绑定。
public MainPage()
{
this.InitializeComponent();
this.DataContextChanged += (s, e) => this.Bindings.Update();
}