在WinUI 3中设置样式时的绑定

3
WinUI 3是否支持在Style Setter中进行绑定?我已经为NavigationView定义了一个样式,第三行是:
<Setter Property="CompactPaneLength" Value="{Binding CurrentCompactPaneLength}" />

这会在运行时产生一个“指定的转换无效”异常。包含 NavigationView 的页面的 DataContext 是页面的 ViewModel。NavigationView.CompactPaneLength 和 CurrentCompactPaneLength 都是公共的 double 类型,而 CurrentCompactPaneLength 是一个可观察对象(来自 CommunityToolkit.Mvvm.ComponentModel)。

WinUI 3(SDK 1.1.2)的源代码包括各种 Setter,例如

<Setter Target="PaneContentGrid.Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CompactPaneLength}" />

如果必要的话,使用代码进行绑定是可行的。但是 XAML 也应该能够工作,不是吗?


你真的找到了WinUI 3的源代码?我可以问一下在哪里找到的吗?微软的代码库都像迷宫一样。 - Emperor Eto
我觉得你可能正在看WinUI2的代码。据我所知,WinUI3的代码仍然不是开源的(而且以这个速度可能永远也不会开源)。 - Emperor Eto
2个回答

1

显然,在WinUI 3中尚不支持Setter中的通用绑定,尽管这是一个备受请求的功能。一种解决方法是创建一个带有DependencyProperty的辅助类,每当属性被更改/设置时调用更改处理程序。然后,更改处理程序可以在代码中创建所需的绑定。感谢clemens很久以前为UWP建议了这样的东西。以下是一个示例辅助类:

internal class BindingHelper
{
    #region CompactPaneLengthBindingPath
    public static readonly DependencyProperty CompactPaneLengthBindingPathProperty = DependencyProperty.RegisterAttached(
            "CompactPaneLengthBindingPath", typeof(string), typeof(BindingHelper), new PropertyMetadata(null, BindingPathChanged));
            
    public static string GetCompactPaneLengthBindingPath(DependencyObject obj)
    {
        return (string)obj.GetValue(CompactPaneLengthBindingPathProperty);
    }
    
    public static void SetCompactPaneLengthBindingPath(DependencyObject obj, string value)
    {
        obj.SetValue(CompactPaneLengthBindingPathProperty, value);
    }
    #endregion
        
    #region HeightBindingPath
    // another DP is defined here (all of them are strings)
        
    #region ForegroundBindingPath
    // and a third one, etc.
        

    // ===================== Change Handler: Creates the actual binding

    private static void BindingPathChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue is string source)                                                                // source property (could add DataContext by setting Value="source@datacontext" for example)
        {
            DependencyProperty target;                                                                  // which property is the target of the binding?
            if (e.Property == CompactPaneLengthBindingPathProperty) target = NavigationView.CompactPaneLengthProperty;
            else if (e.Property == HeightBindingPathProperty) target = FrameworkElement.HeightProperty;
            else if (e.Property == ForegroundBindingPathProperty) target = Control.ForegroundProperty;
            else throw new System.Exception($"BindingHelper: Unknown target ({nameof(e.Property)}");    // don't know this property
        
            obj.ClearValue(target);                                                                     // clear previous bindings (and value)
            BindingOperations.SetBinding(obj, target,                                                   // set new binding (and value)
               new Binding { Path = new PropertyPath(source), Mode = BindingMode.OneWay });
        }
    }

请注意,所有的DependencyProperties都是字符串类型,并且目标类型可以是您正在使用的控件的任何祖先类型。例如,HeightBindingPathProperty绑定可以与任何FrameworkElement一起使用。
在样式中使用助手与使用任何Setter一样,如下所示:
<Style x:Key="MyNavigationView" TargetType="controls:NavigationView" >
    <Setter Property="local:BindingHelper.CompactPaneLengthBindingPath" Value="CurrentCompactPaneLength" />
</Style>

希望这能有所帮助。


0
这对我有效,但是尝试对一个文本框做同样的操作会导致程序崩溃。
<Page.Resources>
    <Style TargetType="TextBlock">
        <Setter Property="FontSize" Value="{x:Bind FontSizeProperty, Mode=OneWay}" />
    </Style>
</Page.Resources>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接