2015-11-06 61 views
12

我有創建xaml控件的問題。我正在通用應用程序中編寫VS 2015中的新項目。我想創建網格。在這個網格中,我想要一個按鈕。在模型中,我指定了列(Level)和行。 這是我的代碼:UWP綁定風格安裝程序不起作用

<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我有一個錯誤。 任何人都可以幫助我嗎?

+1

我該怎麼做這樣的事情?UWP? – Babel

回答

21

如上節提到遷移的Setter.Value property頁面上MSDN,UWP/Windows運行時的注意事項不支持綁定風格二傳手。

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 WPF or 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.

解決方法可能是爲綁定的源路徑附加屬性的助手類。它創建於代碼綁定背後的幫手財產的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屬性),請參閱this answer

+0

嗯不適合我。 ItemContainerStyle中的Targettype是否始終爲ContentPresenter?如果我將它設置爲我的ViewModel,我會遇到一個災難性的失敗異常。 –

+0

@MatthiasMüller,我認爲這是正確的。我有類似的問題。 ContentPresenter是整個模板的父代,所以我相信它是正確的目標類型。 – rbwhitaker

+0

ItemsControl的項目容器類型是ContentPresenter,因此ItemContainerStyle的TargetType必須是ContentPresenter。 – Clemens

0

想通過@clemens添加我對BindingHelper創意的體驗。這是一個很好的解決方案,但是我發現在定位ListViewItem時,綁定不會訪問底層視圖模型。調試完成後,我發現我需要確保綁定是相對於ListViewItem本身以及相關的.Content屬性,以使其能夠正確鏈接到項目的視圖模型。

我的具體使用情況是制定基於視圖模型值ListViewItemIsTabStop屬性:

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); 
    } 
} 

希望這會幫助,如果任何人有這個問題。