多重绑定多重选择ListView
好吧,我这里有一个奇怪的。我想要弄清楚的是如何拥有一个由 ObservableCollection 填充的列表视图,根据第一个列表视图的选择更新另一个由另一个 ObservableCollection 填充的 ListView,然后使用 valueconverter 根据组合的选择来选中或取消选中复选框与第二个列表视图中的当前项目。这部分我在某种程度上通过使用多重绑定来工作,但让我困惑的部分是当我检查或取消选中第二个列表视图中的项目时,我需要能够捕获该事件以及该列表视图中当前检查的所有项目更新以此为基础的数据库领域。
我知道这可能没有多大意义,并且我正在努力如何使其更清晰,但下面是两个列表视图的 xaml 和转换器的代码。我可以看到,当我选中或取消选中第二个列表视图中的一个框时,转换器会尝试执行 ConvertBack 方法,该方法会爆炸,但如果我将其设置为仅返回 null,则代码不再爆炸,但复选框会突出显示呈红色,就像发生了验证错误。
我什至不确定多重绑定是这里的方法,我已经查看了 Josh Smith 的多重选择列表视图内容,但由于需要转换,我也看不到如何成功实现它。
如果有人有任何想法,我将不胜感激。如果我没有非常清楚地解释我的需求,我也表示歉意,但我希望通过混乱的描述和代码,您可以看到我要做什么。
提前致谢!
第一个 ListView 提供第二个列表
<Grid>
<ListView x:Name="listRule" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="3,3,3,3" ItemsSource="{Binding RuleListing}" exts:Selected.Command="{Binding RuleSelectedCommand}" SelectedIndex="0">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=DisplayName}" ToolTip="{Binding Path=Expression}" FontWeight="Bold"/>
<TextBlock Text=" ( "/>
<TextBlock Text="{Binding Description}" FontStyle="Italic" />
<TextBlock Text=" )"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
第二个 ListView 带有转换器和多重绑定
<Grid HorizontalAlignment="Stretch">
<Grid.Resources>
<converters:RuleToRoleBooleanConverter x:Key='RuleRoleConverter' />
<DataTemplate x:Key="RoleTemplate">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MinWidth="200"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding RoleName}" HorizontalAlignment="Left" Margin="3,0,0,0" Grid.Column="0" />
<CheckBox HorizontalAlignment="Right" Margin="0,0,3,0" Grid.Column="1">
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource RuleRoleConverter}">
<Binding ElementName="listRule" Path="SelectedItem" />
<Binding Path="RoleName"/>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</Grid>
</DataTemplate>
</Grid.Resources>
<ListView Name="listRoles" ItemsSource="{Binding RoleListing}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
SelectionMode="Multiple" ItemTemplate="{StaticResource ResourceKey=RoleTemplate}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsRoleSelected}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
值转换器
public class RuleToRoleBooleanConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values[0] != null && values[1] != null)
{
string expression = ((EliteExtenderRule)values[0]).Expression;
string role = values[1].ToString();
if (expression.Contains("R:*") || expression.Contains("R:" + role))
{
return true;
}
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;// new object[] { (bool)value, null };
}}
OK I have a weird one here. What I am trying to figure out is how to have one listview, populated by an ObservableCollection, update another ListView, populated by another ObservableCollection, based on the first listview's selection and then use a valueconverter to check or uncheck a checkbox based on the selection combined with the current item in the second listview. This part I somewhat have working by using multibinding, but the part that has me stumped is when I check or uncheck an item in the second listview I need to be able to grab that event and all the currently checked items in that listview an update a database field based on that.
I know this may not make a lot of sense and I'm struggling on how to make it clearer, but below is the xaml for the two listviews and the code for the converter. I can see that when I check or uncheck a box in the secodn listview that the converter tries to do the ConvertBack method which blows up, but if I set it to just return null then the code no longer blows up, but the checkbox is highlighted in red like a validation error has occured.
I am not even sure that multibinding is the way to go here and I have looked at Josh Smith's multiselection listview stuff, but with the conversion needed I can not see how to implement that successfully either.
If anyone has any ideas I would greatly appreciate it. Also my apologies if I didn't explain my need very clearly, but I am hoping with the chaotic description and the code you can kind of see where I am going with it.
Thanks in advance!
First ListView that feeds the second one
<Grid>
<ListView x:Name="listRule" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="3,3,3,3" ItemsSource="{Binding RuleListing}" exts:Selected.Command="{Binding RuleSelectedCommand}" SelectedIndex="0">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=DisplayName}" ToolTip="{Binding Path=Expression}" FontWeight="Bold"/>
<TextBlock Text=" ( "/>
<TextBlock Text="{Binding Description}" FontStyle="Italic" />
<TextBlock Text=" )"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Second ListView with converter and multibinding
<Grid HorizontalAlignment="Stretch">
<Grid.Resources>
<converters:RuleToRoleBooleanConverter x:Key='RuleRoleConverter' />
<DataTemplate x:Key="RoleTemplate">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MinWidth="200"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding RoleName}" HorizontalAlignment="Left" Margin="3,0,0,0" Grid.Column="0" />
<CheckBox HorizontalAlignment="Right" Margin="0,0,3,0" Grid.Column="1">
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource RuleRoleConverter}">
<Binding ElementName="listRule" Path="SelectedItem" />
<Binding Path="RoleName"/>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</Grid>
</DataTemplate>
</Grid.Resources>
<ListView Name="listRoles" ItemsSource="{Binding RoleListing}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
SelectionMode="Multiple" ItemTemplate="{StaticResource ResourceKey=RoleTemplate}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsRoleSelected}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
Value Converter
public class RuleToRoleBooleanConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values[0] != null && values[1] != null)
{
string expression = ((EliteExtenderRule)values[0]).Expression;
string role = values[1].ToString();
if (expression.Contains("R:*") || expression.Contains("R:" + role))
{
return true;
}
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;// new object[] { (bool)value, null };
}}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我可能对你的问题的第一部分有一个解决方案,即“弄清楚如何拥有一个由 ObservableCollection 填充的列表视图,根据第一个列表视图的选择更新另一个由另一个 ObservableCollection 填充的列表视图”。
但在此之前,对于这部分问题,dit 只需将目标 ListView 绑定到源 ListView 的 selected items 属性上就可以满足您的需求吗?
如果没有,我在最近的项目中遇到了类似的问题,并且我提出了应用于源列表的行为。
假设您有一个像视图的 DataContext 这样的视图模型:
并且在您的视图中您有类似的东西:
然后您可以将此行为附加到源列表框并将目标视图模型源传递给它。
==>行为:
它的作用基本上是在初始化时,检索目标列表项并填充源列表(一种方式),并订阅列表框源选择更改事件以填充目标列表(另一种方式)。然后,当在行为中添加项目时,目标列表框会更新。
新的 XAML 看起来就像这样:
对于问题的第二部分,我现在没有想到什么......抱歉:/
I might have a solution for the first part of your problem, i.e "to figure out is how to have one listview, populated by an ObservableCollection, update another ListView, populated by another ObservableCollection, based on the first listview's selection".
But before, for this part of the problem dit does just bind the target ListView on he selected items property of the source ListView would satisfy your needs ?
If not, I had a similar problem on recent project and I came up with a behavior applied to source list.
Saying that you have a view model like that as the DataContext of your view :
And in your view you have something like that :
Then you can attach this behavior on the source listbox and pass the target view model source to it.
==> the behavior:
What it does basically is that when initializing, he retreive the target list items and populates the source list (one way), and subscribe to list box source selection changed event to populate target list (the other way). Then, the target listbox gest updated when items are added in the bahavior.
The new XAML looks just like that :
For the second part of your problem, I don't have something that come to my mind right now... sorry :/