2016-04-12 15 views
-1

Alles klar, also wollte ich das ursprünglich nur als Problem darlegen, warum die Bindung nicht funktionierte. Sobald ich jedoch versucht habe, den Code zu minimieren, der auf SO hochgeladen werden soll, hat sich ein weiteres Problem ergeben.Warum wird diese angehängte Eigenschaft nicht aktualisiert?

Also, im Wesentlichen ist die Extensions Klasse gemeint, auf die ListBox Haken und machen eine bindbare Version von SelectedItems. Diese Funktion, die SelectedItems zu greifen und sie in die angefügte Eigenschaft Selected zu platzieren, funktioniert in meinem Programm (in meinem echten Programm scheint es nicht zu binden?), Aber nicht in dieser minimierten Version. Ich habe keine Ahnung, warum der Code jedoch alles zu tun scheint.

Der Code, den ich verwendet, um es zu testen:

.xaml.cs

namespace MyNamespace 
{ 
    public partial class MainWindow 
    { 
     public IList Selected { get; set; } 
     public MainWindow() 
     { 
      InitializeComponent(); 
      Selected = new List<object>(); 
      Why.ItemsSource = new[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     } 
     private void Click(object sender, RoutedEventArgs e) 
     { 
      MessageBox.Show(Selected.Cast<object>().Aggregate("", (s, info) => $"{s}{info}, ").TrimEnd(',', ' ')); 
      MessageBox.Show(Extensions.GetSelected(Why).Cast<object>().Aggregate("", (s, o) => $"{s}{o}, ").TrimEnd(',', ' ')); 
     } 
    } 
    public static class Extensions 
    { 
     public static readonly DependencyProperty SelectedProperty = DependencyProperty.RegisterAttached(
      "Selected", typeof(IList), typeof(Extensions), new PropertyMetadata(default(IList), HookSelectionChanged)); 

     private static void HookSelectionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
     { 
      ListBox lb = sender as ListBox; 
      if (lb == null) 
       throw new ArgumentException("This property currently only supports DependencyObjects inheriting from Selector.", nameof(sender)); 
      lb.SelectionChanged += SelectionChanged; 
     } 

     private static void SelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs) 
      => SetSelected((ListBox)sender, ((ListBox)sender).SelectedItems.Cast<object>().ToList()); 

     public static void SetSelected(DependencyObject element, IList value) => element.SetValue(SelectedProperty, value); 

     public static IList GetSelected(DependencyObject element) => (IList)element.GetValue(SelectedProperty); 
    } 
} 

.xaml

<Window x:Class="MyNamespace.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:lcl="clr-namespace:MyNamespace" 
     DataContext="{Binding RelativeSource={RelativeSource Self}}" 
     Title="My title." Height="350" Width="425" MaxHeight="350" MaxWidth="425" MinHeight="350" MinWidth="425"> 
    <StackPanel> 
     <ListBox lcl:Extensions.Selected="{Binding Selected}" x:Name="Why" SelectionMode="Extended"/> 
     <Button Click="Click" Content="blah"/> 
    </StackPanel> 
</Window> 

Irgendwelche Ideen wäre sehr gut! Thanks :)

+1

Dies kann helfen: https://spin.atomicobject.com/2013/12/11/wpf-data-binding-debug/ Diese PresentationTraceSources.TraceLevel Sache ist ein Lebensretter für mich jeden Tag (hoppla, verpasst Ihre DataContext-Bindung) –

+1

Sollte '{Binding Selected}' nicht '{Binding Selected, Mode = TwoWay}' sein? – Quantic

+0

@Quantic hat Recht - Sie können auch ['FrameworkPropertyMetadata'] (https://msdn.microsoft.com/en-us/library/ms557295 (v = vs.110) .aspx) anstelle von' PropertyMetadata' verwenden, Damit können Sie "FrameworkPropertyMetadataOptions.BindsTwoWayByDefault" übergeben, was Ihren Kunden die Mühe erspart, sich daran zu erinnern, 'Mode = TwoWay' hinzuzufügen. –

Antwort

0

In Ordnung, so dass alle es war, fehlt mir zwei Dinge:

  • ich nicht umgesetzt INotifyPropertyChanged in meinem Test
  • ich nicht wusste, dass Binding s nicht zu TwoWay Standard haben alle der ganzen Zeit.

Also alles, was getan war dies werden musste:

.xaml.cs

namespace MyNamespace 
{ 
    public partial class MainWindow : INotifyPropertyChanged 
    { 
     private IList _selected; 

     public IList Selected 
     { 
      get { return _selected; } 
      set 
      { 
       if (Equals(value, _selected)) return; 
       _selected = value; 
       OnPropertyChanged(); 
      } 
     } 

     public MainWindow() 
     { 
      InitializeComponent(); 
      Selected = new List<object>(); 
      Why.ItemsSource = new[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     } 
     private void Click(object sender, RoutedEventArgs e) 
     { 
      MessageBox.Show(Selected.Cast<object>().Aggregate("", (s, info) => $"{s}{info}, ").TrimEnd(',', ' ')); 
      MessageBox.Show(Extensions.GetSelected(Why).Cast<object>().Aggregate("", (s, o) => $"{s}{o}, ").TrimEnd(',', ' ')); 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     [NotifyPropertyChangedInvocator] 
     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    public class Extensions 
    { 
     public static readonly DependencyProperty SelectedProperty = DependencyProperty.RegisterAttached(
      "Selected", typeof(IList), typeof(Extensions), new FrameworkPropertyMetadata(default(IList), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, HookSelectionChanged)); 

     private static void HookSelectionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
     { 
      ListBox lb = sender as ListBox; 
      if (lb == null) 
       throw new ArgumentException("This property currently only supports DependencyObjects inheriting from Selector.", nameof(sender)); 
      lb.SelectionChanged += SelectionChanged; 
     } 

     private static void SelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs) 
      => SetSelected((ListBox)sender, ((ListBox)sender).SelectedItems.Cast<object>().ToList()); 

     public static void SetSelected(DependencyObject element, IList value) => element.SetValue(SelectedProperty, value); 

     public static IList GetSelected(DependencyObject element) => (IList)element.GetValue(SelectedProperty); 
    } 
} 

und es hat hervorragend funktioniert.