15

我在创建 xaml 控件时遇到问题。我正在通用应用程序中的 VS 2015 中编写新项目。我想创建网格。在这个网格中,我想要一个按钮。在模型中,我指定列(级别)和行。这是我的代码:

<ItemsControl Grid.Row="1" ItemsSource="{Binding Path=TechnologyList}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="10*"/>
                    <RowDefinition Height="10*"/>
                    <RowDefinition Height="10*"/>
                    <RowDefinition Height="10*"/>
                    <RowDefinition Height="10*"/>
                    <RowDefinition Height="10*"/>
                    <RowDefinition Height="10*"/>
                    <RowDefinition Height="10*"/>
                    <RowDefinition Height="10*"/>
                    <RowDefinition Height="10*"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="14*"/>
                    <ColumnDefinition Width="14*"/>
                    <ColumnDefinition Width="14*"/>
                    <ColumnDefinition Width="14*"/>
                    <ColumnDefinition Width="14*"/>
                    <ColumnDefinition Width="14*"/>
                    <ColumnDefinition Width="14*"/>
                </Grid.ColumnDefinitions>
            </Grid>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="Control">
            <Setter Property="Grid.Column" Value="{Binding Level}" />
            <Setter Property="Grid.Row" Value="{Binding Row}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Content="{Binding Name}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

我在行中收到错误<Setter Property="Grid.Column" Value="{Binding Level}" /> 错误:HRESULT 异常:0x8000FFFF (E_UNEXPECTED) 在 edytor 中而不在运行代码中。怎么了?在“旧”WPF 中一切正常,但在适用于 Windows 10 的通用应用程序中出现错误。谁能帮我 ?

4

2 回答 2

27

如MSDN上Setter.Value 属性页上的迁移说明部分所述,UWP/Windows 运行时不支持样式设置器中的绑定。

Windows Presentation Foundation (WPF) 和 Microsoft Silverlight 支持使用绑定表达式为样式中的 Setter 提供值的能力。Windows 运行时不支持 Setter.Value 的 Binding 用法(Binding 不会计算并且 Setter 没有效果,您不会收到错误,但也不会获得所需的结果)。当您从 WPF 或 Silverlight XAML 转换 XAML 样式时,请将任何绑定表达式用法替换为设置值的字符串或对象,或者将值重构为共享的 {StaticResource} 标记扩展值而不是绑定获取的值。

一种解决方法可能是一个辅助类,它带有绑定源路径的附加属性。它在辅助属性的 PropertyChangedCallback 后面的代码中创建绑定:

public class BindingHelper
{
    public static readonly DependencyProperty GridColumnBindingPathProperty =
        DependencyProperty.RegisterAttached(
            "GridColumnBindingPath", typeof(string), typeof(BindingHelper),
            new PropertyMetadata(null, GridBindingPathPropertyChanged));

    public static readonly DependencyProperty GridRowBindingPathProperty =
        DependencyProperty.RegisterAttached(
            "GridRowBindingPath", typeof(string), typeof(BindingHelper),
            new PropertyMetadata(null, GridBindingPathPropertyChanged));

    public static string GetGridColumnBindingPath(DependencyObject obj)
    {
        return (string)obj.GetValue(GridColumnBindingPathProperty);
    }

    public static void SetGridColumnBindingPath(DependencyObject obj, string value)
    {
        obj.SetValue(GridColumnBindingPathProperty, value);
    }

    public static string GetGridRowBindingPath(DependencyObject obj)
    {
        return (string)obj.GetValue(GridRowBindingPathProperty);
    }

    public static void SetGridRowBindingPath(DependencyObject obj, string value)
    {
        obj.SetValue(GridRowBindingPathProperty, value);
    }

    private static void GridBindingPathPropertyChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var propertyPath = e.NewValue as string;

        if (propertyPath != null)
        {
            var gridProperty =
                e.Property == GridColumnBindingPathProperty
                ? Grid.ColumnProperty
                : Grid.RowProperty;

            BindingOperations.SetBinding(
                obj,
                gridProperty,
                new Binding { Path = new PropertyPath(propertyPath) });
        }
    }
}

您可以像这样在 XAML 中使用它们:

<ItemsControl.ItemContainerStyle>
    <Style TargetType="ContentPresenter">
        <Setter Property="local:BindingHelper.GridColumnBindingPath" Value="Level"/>
        <Setter Property="local:BindingHelper.GridRowBindingPath" Value="Row"/>
    </Style>
</ItemsControl.ItemContainerStyle>

有关绝对定位的简单解决方法(即绑定Canvas.Leftcanvas.Top属性),请参阅此答案

于 2015-11-07T11:48:18.057 回答
1

BindingHelper想从@clemens添加我对这个想法的体验。这是一个很好的解决方案,但我发现当ListViewItem以绑定为目标时,它不会访问底层视图模型。在调试它之后,我发现我需要确保绑定是相对于ListViewItem自身和关联的.Content属性,以使其能够正确链接到项目的视图模型。

我的特定用例是基于视图模型值设置的IsTabStop属性:ListViewItem

private static void BindingPathPropertyChanged(DependencyObject obj,
    DependencyPropertyChangedEventArgs e)
{
    if (e.NewValue is string propertyPath)
    {
        var binding = new Binding
        {  
            Path = new PropertyPath($"Content.{propertyPath}"),
            Mode = BindingMode.OneWay,
            RelativeSource = new RelativeSource
            {
                Mode = RelativeSourceMode.Self
            }
        };
        BindingOperations.SetBinding(obj, Control.IsTabStopProperty, binding);
    }
}

如果其他人有问题,希望这会有所帮助。

于 2018-01-12T18:23:00.973 回答