#wpf #silverlight
#wpf #silverlight
Вопрос:
Я определяю этот простой класс
public class SimpleClass
{
public string Val1 {get;set;};
public string Val2 {get;set;}
public string Res
{
get
{
string.Format("{0}_{1}", Val1, Val2 );
}
}
public SimpleClass(string v1, string v2)
{
Val1 = v1;
Val2 = v2;
}
public SimpleClass(string v1, int i)
{
if(i == 0)
{
Val1 = v1;
val2 = "";
}
if(i == 0)
{
Val2 = v1;
val1 = "";
}
}
}
Теперь я определяю в коде это
List< SimpleClass > myList = new List<SimpleClass>();
myList.Add(new SimpleClass("a1", "b1");
myList.Add(new SimpleClass("a2", "b2");
myList.Add(new SimpleClass("a3", "b3");
myList.Add(new SimpleClass("a4", "b4");
И я определяю в списке xaml 2 —
Сначала отображаются все элементы a1 … a4
Второй, который показывает все элементы b1 … b4
Каждый элемент в списке является флажком, а содержимое — строкой элемента.
Теперь я хочу определить фильтр, который будет отображать в каком-либо другом списке только SimpleClass.Res, который был отмечен в списке.
==> это означает, что если в списке отмеченные элементы являются b1 и a3, то единственный текст в третьем списке будет содержать
a1_b1
a3_b3
Как я могу это сделать?
Я пытаюсь использовать CollectionViewSource, но в этом случае я не могу определить мультифильтр.
Комментарии:
1. К чему привязан пользователь
CheckBox
?2. Ничего. просто отфильтруйте текст, который отображается на флажке
3. Вы пытаетесь добиться множественного выбора? Если это так, то флажок должен быть привязан к чему-то, не так ли?
4. допустим, у меня уже есть метод, который преобразует флажок, привязанный к некоторой строке. и теперь мне нужно отфильтровать элементы представления
Ответ №1:
В пользовательском интерфейсе вам нужно будет привязать флажок к чему-либо, чтобы вы были осведомлены о статусе отмеченных элементов из обоих списков.
Следовательно, мы привязываем его TwoWay
к свойству ListBoxItem
предка IsSelected
. Таким образом, когда флажки установлены, они автоматически регистрируют отмеченный элемент в ListBox.SelectedItems
свойстве.
На основе этого мы выполняем множественную привязку ListBox3.ItemsSource
к ListBox1.SelectedItems
и ListBox2.SelectedItems
. Вызываемый многозначный конвертер MergeSelectedItemsHelper
просто выполняет объединение двух списков выбранных элементов.
Я использовал Array
of TextBlock
вместо List
of SimpleClass
для привязки ко всем этим спискам.
XAML:
<StackPanel Orientation="Vertical">
<StackPanel.Resources>
<x:ArrayExtension x:Key="MyArraySource" Type="{x:Type TextBlock}">
<TextBlock Text="A" Tag="A1" DataContext="A_A1"/>
<TextBlock Text="B" Tag="B1" DataContext="B_B1"/>
<TextBlock Text="C" Tag="C1" DataContext="C_C1"/>
<TextBlock Text="D" Tag="D1" DataContext="D_D1"/>
</x:ArrayExtension>
<local:MergeSelectedItemsHelper
x:Key="MergeSelectedItemsHelper"/>
<DataTemplate x:Key="ListBox1ItemTemplate">
<CheckBox
IsChecked="{Binding IsSelected,
RelativeSource={RelativeSource
AncestorType={x:Type ListBoxItem}},
Mode=TwoWay}"
Content="{Binding Text}"/>
</DataTemplate>
<DataTemplate x:Key="ListBox2ItemTemplate">
<CheckBox
IsChecked="{Binding IsSelected,
RelativeSource={RelativeSource
AncestorType={x:Type ListBoxItem}},
Mode=TwoWay}"
Content="{Binding Tag}"/>
</DataTemplate>
</StackPanel.Resources>
<ListBox x:Name="ListBox1"
SelectionMode="Extended"
Margin="10"
ItemsSource="{StaticResource MyArraySource}"
ItemTemplate="{StaticResource ListBox1ItemTemplate}"
SelectionChanged="ListBox1_SelectionChanged">
</ListBox>
<ListBox x:Name="ListBox2"
SelectionMode="Extended"
Margin="10"
ItemsSource="{StaticResource MyArraySource}"
ItemTemplate="{StaticResource ListBox2ItemTemplate}"
SelectionChanged="ListBox1_SelectionChanged">
</ListBox>
<ListBox x:Name="ListBox3" Margin="10" DisplayMemberPath="DataContext">
<ListBox.ItemsSource>
<MultiBinding Converter="{StaticResource MergeSelectedItemsHelper}">
<Binding Path="SelectedItems" ElementName="ListBox1"/>
<Binding Path="SelectedItems" ElementName="ListBox2"/>
</MultiBinding>
</ListBox.ItemsSource>
</ListBox>
</StackPanel>
</StackPanel>
Код, лежащий в основе:
Теперь as ListBox.SelectedItems
property — это просто свойство, не зависящее от зависимостей, а также ненаблюдаемое, поэтому привязки не будут автоматически обновляться. В приведенном ниже коде мы попытаемся обновить привязку при изменении выбора в ListBox1
и ListBox2
.
private void ListBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var bndexp = BindingOperations.GetMultiBindingExpression(
ListBox3, ItemsControl.ItemsSourceProperty);
if (bndexp != null)
{
bndexp.UpdateTarget();
}
}
Как говорилось ранее, преобразователь нескольких значений просто объединяет выбранные элементы вместе и вызывается при обновлении множественной привязки…
public class MergeSelectedItemsHelper : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(
object[] values,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
var list1 = values[0] as IList;
var list2 = values[1] as IList;
var validList2 = list2 ?? new List<object>();
return list1 != null
? list1.Cast<object>().Union(validList2.Cast<object>())
: validList2.Cast<object>();
}
public object[] ConvertBack(
object value,
Type[] targetTypes,
object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Надеюсь, это поможет.
Ответ №2:
Поместите логическое общедоступное свойство в SimpleClass и привяжите его к флажку. Затем во втором списке привязать видимость к свойству.
<DataTrigger Binding="{Binding Path=DispDetail, Mode=OneWay}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger
Ответ №3:
Если ваши отмеченные элементы находятся в вашей ViewModel, вы можете просто отфильтровать источник представления коллекции с помощью делегата
ICollectionView view = CollectionViewSource.GetDefaultView(this.myList);
view.Filter = obj =>
{
var sc = obj as SimpleClass;
// Do your checks to see if this object is valid, and return a bool
// For example,
return SelectedOptions.Contains(sc.Val1) ||
SelectedOptions.Contains(sc.Val2);
};
return view;