WINUI——Microsoft.UI.Xaml.Markup.XamlParseException:“无法找到与此错误代码关联的文本。

开发环境

VS2022

.net core6

问题现象

在Canvas内的子控件要绑定Canvas的兄弟控件的一个属性,在运行时出现了下述报错。

可能原因

在 WinUI(特别是用于 UWP 或 Windows App SDK 的版本)中,如果你尝试在 XAML 中将 Canvas 内的子控件绑定到 Canvas 的兄弟控件(即与 Canvas 同级但在不同父容器下的控件),你可能会遇到 XamlParseException 或类似的错误,因为标准的数据绑定通常基于父子关系或特定的数据源上下文(如 DataContext)。

原因分析

  1. 上下文不匹配:Canvas 内的控件默认尝试在其父级或更高级别的 DataContext 中查找绑定的源。如果绑定的目标控件(兄弟控件)不在相同的 DataContext 路径上,则无法直接访问。

  2. XAML 绑定限制:XAML 绑定通常不直接支持跨树(跨不同父容器)的绑定。这意味着你不能直接从一个控件绑定到另一个在 XAML 视觉树中不相邻的控件。

解决方案

  1. 使用中介数据源
    • 创建一个在更高级别(如页面或用户控件的 DataContext)可访问的数据源(如 ViewModel)。
    • 将需要共享的数据放入这个数据源中。
    • 然后,从 Canvas 内的子控件和兄弟控件都绑定到这个数据源。
  2. 使用代码后置
    • 在代码后置(C# 或 C++/WinRT)中,你可以更灵活地处理控件之间的交互和数据传递。
    • 例如,你可以在页面加载时,通过代码将兄弟控件的值传递给 Canvas 内的子控件。
  3. 使用附加属性
    • 如果适用,你可以创建一个附加属性,该属性可以在多个控件之间共享数据。
    • 然后,你可以在 XAML 中为这些控件设置这个附加属性,或者在代码后置中处理它。
  4. 重构 UI 结构
    • 考虑重新设计你的 UI 结构,以便需要交互的控件位于相同的父容器中。
    • 这可能涉及将 Canvas 嵌入到一个能够容纳所有相关控件的容器中。

以上为AI给出的一些分析,解决方案中的1和2本质一样的,使用1或2都一定要实现INotifyProperty接口,如果这个属性变化时需要通知UI的话。

原因验证

按AI给出的原因2,尝试将Canvas的兄弟控件ViewBox的HorizontalAlignment先绑定到Canvas的Tag上,再在Canvas的子控件上获取Canvas的Tag属性。结果仍还报Microsoft.UI.Xaml.Markup.XamlParseException错误。

开始以为是Tag是object,需要转化为HorizontalAlignment或字符串,但使用Converter转化后仍报XamlParseException错误。

这就说明这应该不是跨树的问题了,因为Canvas绑定的ViewBox的属性没有任何问题,但在将Canvas的Tag绑定到Canvas的子控件时才出了XamlParseException,也就是说Canvas与它的子控件肯定是在同一可视树上的,且肯定是同树枝的。

但同树且同枝时还出现了XamlParseException这是为何?此还有待进一步深究。

那么原因1就正确吗?

至于原因1,先看一下下述常见的Slider值绑定TextBox。下述的TextBox与Slider肯定拥有相同父控件的,在相同的父DataContext路径上,这种绑定是没有问题的。

        <StackPanel
            Width="400"
            Height="100"
            HorizontalAlignment="Right"
            Background="Green">
            <TextBox Text="{Binding ElementName=slider, Path=Value, Mode=TwoWay}" />
            <Slider
                x:Name="slider"
                Width="300"
                Maximum="50"
                Minimum="0" />
        </StackPanel>

再看下边的xaml,在Canvas中的TextBlock也绑定了Canvas的兄弟控件Slider。

        <StackPanel
            Width="400"
            Height="200"
            HorizontalAlignment="Right"
            Background="Green">
            <TextBox Text="{Binding ElementName=slider, Path=Value, Mode=TwoWay}" />
            <Slider
                x:Name="slider"
                Width="300"
                Maximum="50"
                Minimum="0" />
            <Canvas
                x:Name="canvas"
                Height="50"
                Background="Red">
                <TextBlock
                    Canvas.Left="10"
                    Canvas.Top="10"
                    Text="{Binding ElementName=slider, Path=Value}" />
            </Canvas>
        </StackPanel>

但Canvas的子控件却能绑定成功,如下所示,红色Canvas内数字的变化是完全没有问题的。

但xaml如下时,将TextBlock的属性绑定到Canvas的子控件的HorizontalAlignment时,就会失效(不会报错XamlParseException;本次报错的是要绑定到自定义的依赖属性)

   <StackPanel
       Width="400"
       Height="200"
       HorizontalAlignment="Right"
       Background="Green">
       <TextBox Text="{Binding ElementName=slider, Path=Value, Mode=TwoWay}" />
       <Slider
           x:Name="slider"
           Width="300"
           Maximum="50"
           Minimum="0" />
       <TextBlock
           x:Name="textBlock"
           Height="20"
           Tapped="TextBlock_Tapped"
           Text="Test" />
       <Canvas
           x:Name="canvas"
           Height="50"
           Background="Red"
           Tag="{Binding ElementName=textBlock, Path=HorizontalAlignment}">
           <TextBlock
               Canvas.Left="10"
               Canvas.Top="10"
               HorizontalAlignment="{Binding ElementName=canvas, Path=Tag}"
               Text="{Binding ElementName=slider, Path=Value}" />
       </Canvas>
   </StackPanel>

后台代码如下:

 private void TextBlock_Tapped(object sender, TappedRoutedEventArgs e)
 {
     var textblock = sender as TextBlock;
     if (textblock.HorizontalAlignment == HorizontalAlignment.Left)
     {
         textblock.HorizontalAlignment = HorizontalAlignment.Right;
     }
     else
     {
         textblock.HorizontalAlignment = HorizontalAlignment.Left;
     }
 }

运行时如下,红色Canvas内的TextBlock完全没有响应,但是没有报错XamlParseException。

综上两个例子,可以看出,AI给出的原因1也并不靠谱。

解决办法验证

前边已经将AI给出的原因验证了一遍,两个原因都经不起推敲。这节来验证一下它给出的方法,这是由于AI的原因和结果并没有一定的必然联系,于是原因验证后结果也可以进行相应的验证。

对于它给出的4个方法,愚以为仅两个方法:一个是代码的方式作为中介数据,一个是UI的重构。

至于UI的重构,愚在验证原因的时候已经进行过一些操作,各位可以再进行其它的一些尝试,此处仅说明一下使用代码作为中介数据。

经验证使用中介数据的方法是有效的,愚在VM中申明horizontal,

        [ObservableProperty]
        private string horizontal= "Right";

TextBlock的HorizontalAlignment绑定如下(ViewModel申明在xaml中或后台代码中)

HorizontalAlignment="{x:Bind ViewModel.Horizontal, Mode=TwoWay}"

然后再在Canvas中子控件绑定如下:

 HorizontalAlignment="{x:Bind ViewModel.Horizontal, Mode=OneWay}"

总结

对于本次问题,AI给出的原因并不正确,但给出的解决方案是有效的,至于产生XamlParseException的原因,后续弄清楚了,再做补充。

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值