Реализация встроенного бинарного ввода для ListBox.SelectedItems?
Я пытался выяснить, есть ли простой/умный способ реализовать привязку к ListBox.SelectedItems. Если вы сами пробовали, вы узнаете, что привязка разметки с использованием BindingExtension не будет работать - свойство не поддерживает ее. Таким образом, вам остается подключить обработчик для SelectionChanged и попробовать этот маршрут. Самое близкое, что я получил, это сообщение:
http://alexshed.spaces.live.com/blog/cns!71C72270309CE838!149.entry
Обновление: вышеупомянутый блог больше не доступен, этот текущий блог автора находится здесь и ближайший я могу найти в упомянутом блоге post qaru.site/info/138637/....
который реализует все необходимые С# в удобном прикрепленном свойстве. Но он реализует "привязку" как одностороннюю, целевую к источнику. Я бы хотел, чтобы двусторонняя привязка.
Любые идеи?
Ответы
Ответ 1
Я нашел элегантное решение, и я только нашел время написать сообщение в блоге об этом.
Я сделал, чтобы создать прикрепленное свойство SynchronizedSelectedItems, которое вы можете установить в ListBox (или DataGrid на самом деле). Вы привязываете это к коллекции, а затем, с небольшим количеством магии, свойство SelectedItems в ListBox и вашей коллекции синхронизируется. Вы можете скачать весь код из моего сообщения в блоге.
"magic" - это класс, который прослушивает события CollectionChanged в любой коллекции и передает изменения другим.
Ответ 2
Я искал решение для этого, и предлагаемое казалось слишком сложным. Итак, вот новое двухстороннее связующее решение, которое ограничено только прикрепленным свойством и использует слабую обработку событий для просмотра изменений в определенном свойстве зависимостей. Я не тратил времени на создание этой пуленепробиваемой, но она действительно работает.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication2
{
public class ListBoxHelper
{
private static Dictionary<int, bool> SynchToDPInProcessDictionary = new Dictionary<int, bool>();
private static Dictionary<int, bool> SynchToLBInProcessDictionary = new Dictionary<int, bool>();
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.RegisterAttached("SelectedItems", typeof(IList), typeof(ListBoxHelper),
new FrameworkPropertyMetadata((IList)null,
new PropertyChangedCallback(OnSelectedItemsChanged)));
public static IList GetSelectedItems(DependencyObject d)
{
return (IList)d.GetValue(SelectedItemsProperty);
}
public static void SetSelectedItems(DependencyObject d, IList value)
{
d.SetValue(SelectedItemsProperty, value);
}
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var listBox = d as ListBox;
if (listBox == null)
throw new InvalidOperationException("ListBoxHelper should only be used with ListBox or ListBox derived classes (like ListView).");
int hashcode = listBox.GetHashCode();
// Gets set on the initial binding.
if (!SynchToDPInProcessDictionary.ContainsKey(hashcode))
{
SynchToDPInProcessDictionary[hashcode] = false;
SynchToLBInProcessDictionary[hashcode] = false;
var observableCollection = GetSelectedItems(listBox) as INotifyCollectionChanged;
if (observableCollection != null)
{
// Create a weak CollectionChanged event handler on the SelectedItems property
// that synchronizes the collection back to the listbox.
CollectionChangedEventManager.AddHandler(observableCollection,
delegate(object sender, NotifyCollectionChangedEventArgs e2)
{
SyncToLBSelectedItems(GetSelectedItems(d), (ListBox)d);
});
}
}
SynchToDPSelectedItems(listBox);
listBox.SelectionChanged += delegate
{
SynchToDPSelectedItems(listBox);
};
}
private static void SynchToDPSelectedItems(ListBox listBox)
{
int hashcode = listBox.GetHashCode();
if (SynchToLBInProcessDictionary[hashcode]) return;
SynchToDPInProcessDictionary[hashcode] = true;
try
{
IList dpSelectedItems = GetSelectedItems(listBox);
dpSelectedItems.Clear();
if (listBox.SelectedItems != null)
{
foreach (var item in listBox.SelectedItems)
dpSelectedItems.Add(item);
}
}
finally
{
SynchToDPInProcessDictionary[hashcode] = false;
}
}
private static void SyncToLBSelectedItems(IList dpSelectedItems, ListBox listBox)
{
int hashcode = listBox.GetHashCode();
if (SynchToDPInProcessDictionary[hashcode]) return;
SynchToLBInProcessDictionary[hashcode] = true;
try
{
listBox.SelectedItems.Clear();
if (dpSelectedItems != null)
{
foreach (var item in dpSelectedItems)
listBox.SelectedItems.Add(item);
}
}
finally
{
SynchToLBInProcessDictionary[hashcode] = false;
}
}
}
}