194 lines
6.3 KiB
C#
194 lines
6.3 KiB
C#
using Microsoft.Xaml.Behaviors;
|
|
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Controls.Primitives;
|
|
|
|
namespace Szmedi.RvKits.Behaviors;
|
|
|
|
//public class MyObjectListBoxSelectionBehavior : ListBoxSelectionBehavior<MyObject>
|
|
//{
|
|
//}
|
|
// <i:Interaction.Behaviors>
|
|
// <behaviors:MyObjectListBoxSelectionBehavior BindableSelectedItems = "{Binding SelectedItems}" BindableSelectedValues="{Binding SelectedValues}"/>
|
|
// </ i:Interaction.Behaviors>
|
|
internal class SelectedItemsBehavior<T> : Behavior<MultiSelector>
|
|
{
|
|
// Using a DependencyProperty as the backing store for BindableSelectedItems. This enables animation, styling, binding, etc...
|
|
public static readonly DependencyProperty BindableSelectedItemsProperty =
|
|
DependencyProperty.Register(
|
|
nameof(BindableSelectedItems),
|
|
typeof(IList),
|
|
typeof(SelectedItemsBehavior<T>),
|
|
new FrameworkPropertyMetadata(
|
|
null,
|
|
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
|
OnSelectedItemsChanged));
|
|
public static readonly DependencyProperty BindableSelectedValuesProperty =
|
|
DependencyProperty.Register(
|
|
nameof(BindableSelectedValues),
|
|
typeof(IList),
|
|
typeof(SelectedItemsBehavior<T>),
|
|
new FrameworkPropertyMetadata(
|
|
null,
|
|
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
|
OnSelectedItemsChanged
|
|
)
|
|
);
|
|
private bool modelHandled;
|
|
private bool viewHandled;
|
|
|
|
public IList BindableSelectedItems
|
|
{
|
|
get => (IList)GetValue(BindableSelectedItemsProperty);
|
|
set => SetValue(BindableSelectedItemsProperty, value);
|
|
}
|
|
|
|
protected override void OnAttached()
|
|
{
|
|
base.OnAttached();
|
|
AssociatedObject.SelectionChanged += OnSelectionChanged;
|
|
((INotifyCollectionChanged)AssociatedObject.Items).CollectionChanged += OnItemsChanged;
|
|
}
|
|
|
|
protected override void OnDetaching()
|
|
{
|
|
base.OnDetaching();
|
|
if (AssociatedObject != null)
|
|
{
|
|
AssociatedObject.SelectionChanged -= OnSelectionChanged;
|
|
((INotifyCollectionChanged)AssociatedObject.Items).CollectionChanged -= OnItemsChanged;
|
|
}
|
|
}
|
|
|
|
// Propagate selected items from view to model
|
|
private void SelectItems()
|
|
{
|
|
viewHandled = true;
|
|
AssociatedObject.SelectedItems.Clear();
|
|
if (BindableSelectedItems != null)
|
|
{
|
|
foreach (var item in BindableSelectedItems)
|
|
{
|
|
AssociatedObject.SelectedItems.Add(item);
|
|
}
|
|
}
|
|
viewHandled = false;
|
|
}
|
|
private static void OnSelectedItemsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
|
|
{
|
|
var behavior = (SelectedItemsBehavior<T>)sender;
|
|
if (behavior.modelHandled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (behavior.AssociatedObject == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
behavior.modelHandled = true;
|
|
behavior.SelectItems();
|
|
behavior.modelHandled = false;
|
|
}
|
|
// Re-select items when the set of items changes
|
|
private void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs args)
|
|
{
|
|
if (viewHandled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (AssociatedObject.Items.SourceCollection == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SelectItems();
|
|
}
|
|
|
|
private void OnSelectionChanged(object sender, SelectionChangedEventArgs args)
|
|
{
|
|
if (viewHandled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (AssociatedObject.Items.SourceCollection == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
BindableSelectedItems = AssociatedObject.SelectedItems.Cast<T>().ToArray();
|
|
}
|
|
private static object GetDeepPropertyValue(object obj, string path)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(path))
|
|
{
|
|
return obj;
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
if (path.Contains('.'))
|
|
{
|
|
string[] split = path.Split('.');
|
|
string remainingProperty = path.Substring(path.IndexOf('.') + 1);
|
|
obj = obj.GetType().GetProperty(split[0]).GetValue(obj, null);
|
|
path = remainingProperty;
|
|
continue;
|
|
}
|
|
return obj.GetType().GetProperty(path).GetValue(obj, null);
|
|
}
|
|
}
|
|
public IList BindableSelectedValues
|
|
{
|
|
get => (IList)GetValue(BindableSelectedValuesProperty);
|
|
set => SetValue(BindableSelectedValuesProperty, value);
|
|
}
|
|
// Update SelectedItems based on SelectedValues
|
|
private void SelectedValuesToItems()
|
|
{
|
|
BindableSelectedItems = BindableSelectedValues == null
|
|
? null
|
|
: (IList)AssociatedObject.Items.Cast<T>()
|
|
.Where(i => BindableSelectedValues.Contains(GetDeepPropertyValue(i, AssociatedObject.SelectedValuePath)))
|
|
.ToArray();
|
|
}
|
|
|
|
// Update SelectedValues based on SelectedItems
|
|
private void SelectedItemsToValues()
|
|
{
|
|
BindableSelectedValues = BindableSelectedItems == null
|
|
? null
|
|
: (IList)BindableSelectedItems.Cast<T>()
|
|
.Select(i => GetDeepPropertyValue(i, AssociatedObject.SelectedValuePath))
|
|
.ToArray();
|
|
}
|
|
|
|
//private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
//{
|
|
// var selector = (MultiSelector)sender;
|
|
// BindableSelectedItems = selector.BindableSelectedItems;
|
|
// selector.GetBindingExpression(BindableSelectedItemsProperty)?.UpdateSource();
|
|
//}
|
|
|
|
|
|
//public static IList GetBindableSelectedItems(DependencyObject obj)
|
|
//{
|
|
// return (IList)obj.GetValue(BindableSelectedItemsProperty);
|
|
//}
|
|
|
|
//public static void SetBindableSelectedItems(DependencyObject obj, IList value)
|
|
//{
|
|
// obj.SetValue(BindableSelectedItemsProperty, value);
|
|
//}
|
|
|
|
//// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
|
|
//public static readonly DependencyProperty BindableSelectedItemsProperty =
|
|
// DependencyProperty.RegisterAttached("BindableSelectedItems", typeof(IList), typeof(SelectedItemsBehavior), new PropertyMetadata(null));
|
|
} |