UWP 样式 X:binding 的函数边距抛出 System.AccessViolationException。任何想法,为什么,如果在内联 xaml 中设置,这会正常工作?

UWP Style X:binding of margin to a function throws a System.AccessViolationException. Any ideas why, when this works fine if set in inline xaml?

我有一些方法 x:bind 可以根据宿主控件的大小设置元素大小。一切正常,除非将函数绑定到我的用户控件(来自样式字典)中的边距 属性 我得到一个 System.AccessViolationException.

如果直接绑定到元素,我不会得到异常 - 只是在样式中使用 setter。显然可以通过在对象的 xaml 上设置 属性 来解决这个问题,但想知道这是一个错误还是我遗漏了什么?字典中的函数绑定适用于我正在使用的所有其他属性(只是不在保证金上)。任何建议或指导将不胜感激。

XAML 片段:

 <UserControl.Resources>
    <ResourceDictionary>
    <Style TargetType="Path" x:Key="Ball.Shadow">
       <Setter Property="Height" Value="{x:Bind DimensionAsFraction(0.5)}" />
        ...
    </Style>

    <Style TargetType="TextBlock" x:Key="Ball.Letter" BasedOn="{StaticResource Ball.Text}">
       <Setter Property="Margin" Value="{x:Bind MarginAsFraction(0.075), Mode=OneWay}" />
    ...
 </style>

object.Height is the height of the host control - this has been set before the component is initialised and works fine when referenced from other code and style setters.

代码段:

public sealed partial class Example : UserControl
{
     private void SetDefaults()
     {
        Height = 200;
        Width = 200;
     }

     private int calculateAsInt(double fraction) => (int)(object.Height * fraction);
 
     private double DimensionAsFraction(double fraction) => calculateAsInt(fraction);

     private Thickness MarginAsFraction(double fraction) => new Thickness(0, calculateAsInt(fraction), 0, 0);

     private Thickness BorderAsFraction(double fraction) => new Thickness(calculateAsInt(fraction));

    public Example()
    {
        SetDefaults();
        this.InitializeComponent();
    }
}

谢谢 :D

UWP Style X:binding of margin to a function throws a System.AccessViolationException. Any ideas why, when this works fine if set in inline xaml?

恐怕你不能在样式 setter 中使用绑定或 x:bind,派生自 official document

Windows Presentation Foundation (WPF) and Microsoft Silverlight supported the ability to use a Binding expression to supply the Value for a Setter in a Style. The Windows Runtime doesn't support a Binding usage for Setter.Value (the Binding won't evaluate and the Setter has no effect, you won't get errors, but you won't get the desired result either). When you convert XAML styles from Windows Presentation Foundation (WPF) or Microsoft Silverlight XAML, replace any Binding expression usages with strings or objects that set values, or refactor the values as shared {StaticResource} markup extension values rather than Binding -obtained values.

对于这种场景,建议直接在控件中设置margin

<TextBlock Text="Hello World" Margin="{x:Bind MarginAsFraction(0.75)}" />

我偶然发现了这个试图解决导致堆栈溢出错误的类似问题的线程:

<Style TargetType="GridViewItem">
    <Setter Property="Margin" Value="{x:Bind MyMargin, Mode=OneWay"/>
</Style>

对于我的用例,我不觉得设置控件的边距是合适的,因为这样做意味着选择框(当使用当时的键盘时)不是在控件周围,而是控件和边距。因为我有 non-uniform 边距,它看起来不对。

我的解决方案是在 Page SizeChanged 事件后面的代码中设置(因为那是我更改边距的时间和原因)。

Dim Width As Integer = SomeFunctionOf(WindowSize.Width)
Dim NewMargin As New Thickness(Width, 0, Width, 0)
Dim MarginStyle As New Style(GetType(GridViewItem)) 
MarginStyle.Setters.Add(New Setter(MarginProperty, NewMargin))
MyGridView.ItemContainerStyle = MarginStyle

不是最理想的,但它对我有用。也许这对将来的人有帮助。

---更新---

在我发布这个之后,我开始思考它并意识到我可以使用上面的相同代码,但是我可以在代码中设置 MyGridView.ItemContainerStyle 而不是而是在我的 ViewModel 中设置 属性,例如 MyViewModel.MarignStyle = MarginStyle。然后,使用绑定:

<GridView x:Name="MyGridView" ItemsSource="{x:Bind MyViewModel.ItemsView, Mode=OneTime}" ItemContainerStyle="{x:Bind MyViewModel.MarginStyle,Mode=OneWay}">

无论如何,这两个版本都适合我。