2015-11-06 29 views
12

Ho problemi con la creazione di controllo xaml. Sto scrivendo un nuovo progetto in VS 2015 in app universale. Voglio creare una griglia. In questa griglia voglio avere un pulsante. Nel modello I specifica la colonna (Livello) e Riga. questo è il mio codice:Rilegatura UWP in setter stile non funzionante

<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> 

ottengo un errore in linea <Setter Property="Grid.Column" Value="{Binding Level}" /> L'errore: Eccezione da HRESULT: 0x8000FFFF (E_UNEXPECTED) era in edytor non in esecuzione di codice. Cosa c'è che non va? Nel "vecchio" WPF tutto andava bene, ma in Universal App per Windows 10 ho un errore. Qualcuno può aiutarmi?

+1

Come posso fare qualcosa di simile a questo UWP? – Babel

risposta

21

Come indicato nella sezione Note sulla migrazione nella pagina Setter.Value property su MSDN, UWP/Windows Runtime non supporta i binding in Style Setter.

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.

Una soluzione potrebbe essere una classe di supporto con proprietà associate per i percorsi di source delle legature. Esso crea le associazioni nel codice dietro in un PropertyChangedCallback della proprietà aiutante:

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

Tu li userebbe in XAML come questo:

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

Per una semplice soluzione per il posizionamento assoluto (cioè vincolante delle proprietà Canvas.Left e canvas.Top), vedere this answer.

+0

Hm non funziona per me. Il Targettype in ItemContainerStyle è sempre ContentPresenter? Se lo metto sul mio ViewModel, ottengo un'eccezione catrastrophic failure. –

+0

@ MatthiasMüller, penso sia corretto. Ho avuto un problema simile. ContentPresenter è il genitore dell'intero modello, quindi credo che sia il tipo di target corretto. – rbwhitaker

+0

Il tipo di contenitore dell'articolo di un oggetto ItemsControl è ContentPresenter, quindi il TargetType di ItemContainerStyle deve essere ContentPresenter. – Clemens

0

Volevo aggiungere la mia esperienza di questa idea BindingHelper da @clemens. È una soluzione chiara, ma ho scoperto che quando si targetizza un ListViewItem l'associazione non accedeva al modello di vista sottostante. Dopo aver eseguito il debug, ho scoperto che dovevo assicurarmi che il binding fosse relativo allo ListViewItem e alla proprietà associata .Content per consentirgli di collegarsi correttamente al modello di visualizzazione dell'articolo.

mio particolare caso d'uso è stato quello di impostare la proprietà IsTabStop del ListViewItem sulla base di un valore di vista del modello:

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

Spero che questo aiuti se qualcun altro ha il problema.