Alright, so I was originally just going to post this as an issue of why the binding was not working. However, as soon as I tried to minimise the code to post on SO it created yet another issue.
So, essentially, the Extensions
class is meant to hook onto the ListBox
and make a bindable version of SelectedItems
. This feature of grabbing the SelectedItems
and placing them in the Selected
attached property works in my program (in my real program it does not seem to bind?), but not in this minimised version. I have no clue why however, the code seems to do all it needs to do.
The code I used to test it:
.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>
Any ideas would be excellent! Thanks :)
Alright, so all it was was me missing two things:
INotifyPropertyChanged
in my test Binding
s did not default to TwoWay
all of the time. So all that needed to be done was this:
.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);
}
}
and it worked brilliantly.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.