我有一个报告页面,显示我们报告的一组数据的视图。该视图有大约40个字段。用户可以查询和过滤数据以获得他们需要的数据,然后将其导出到excel报告,然后自动通过电子邮件发送给需要查看信息的管理人员。
由于并非每个报告都需要所有字段,因此视图旁边还有一个列表框,其中包含用于隐藏或显示任何字段的复选框。我一直试图通过选择标题中的复选框来弄清楚如何选中或取消选中所有复选框。列表框的xaml绑定到网格中字段的IsVisible属性,看起来像这样。
<ListView ItemsSource="{Binding Columns, ElementName=reportGrid}" SelectionMode="Multiple">
<ListView.View>
<GridView>
<GridViewColumn Width="50">
<GridViewColumn.HeaderTemplate>
<DataTemplate>
<CheckBox x:Name="checkall" IsChecked="{Binding IsMainSelected}" Tag="{Binding Source={StaticResource Spy}, Path=DataContext}" />
</DataTemplate>
</GridViewColumn.HeaderTemplate> <GridViewColumn.CellTemplate>
<DataTemplate >
<CheckBox IsChecked="{Binding IsVisible}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Field" DisplayMemberBinding="{Binding Header}" Width="100"></GridViewColumn>
</GridView>
</ListView.View>
Spy静态资源的引用来自本文。 http://www.codeproject.com/Articles/27432/Artificial-Inheritance-Contexts-in-WPF
但是,我遇到的每个解决方案的问题都是listview中的复选框绑定到数据集。在这种情况下,复选框绑定到网格中列的可见性(在页面上的对象上)。我尝试的一切都失败了。这可能是一个简单的解决方案,但如果我能弄清楚它就会变得更加困难。任何帮助,将不胜感激。
更新: 我使用后面的代码想出了解决这个问题的方法。如果有一种方法可以在不使用代码的情况下执行此操作,那么我听到了所有人的意见,但这很简单,直截了当的第一和第二,它并没有真正打破将逻辑排除在代码背后的规则。
xaml
<ListView x:Name="lv" ItemsSource="{Binding Columns, ElementName=reportGrid}" Grid.Column="0" Grid.Row="1"
Margin="5,160,25,30" SelectionMode="Multiple">
<ListView.View>
<GridView x:Name="gl">
<GridViewColumn Width="50">
<GridViewColumn.CellTemplate >
<DataTemplate x:Name="fieldChecked" >
<CheckBox IsChecked="{Binding IsVisible}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
<CheckBox Margin="0" x:Name="chkSelectAll" Click="chkSelectAll_Click" IsChecked="True" />
</GridViewColumn>
<GridViewColumn Header="Check/Uncheck All" DisplayMemberBinding="{Binding Header}" Width="110"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
背后的代码
private void chkSelectAll_Click(object sender, RoutedEventArgs e)
{
if (chkSelectAll.IsChecked.Value == true)
{
for (int i = 0; i < lv.Items.Count; i++)
{
ListViewItem lvi = (ListViewItem)lv.ItemContainerGenerator.ContainerFromItem(lv.Items[i]);
if (lvi != null)
{
CheckBox c = lvi.FindChildByType<CheckBox>();
c.IsChecked = true;
}
}
}
else
{
for (int i = 0; i < lv.Items.Count; i++)
{
ListViewItem lvi = (ListViewItem)lv.ItemContainerGenerator.ContainerFromItem(lv.Items[i]);
if (lvi != null)
{
CheckBox c = lvi.FindChildByType<CheckBox>();
c.IsChecked = false;
}
}
}
}
有一点需要注意的是列表视图我必须向下滚动到底部以查看所有字段。如果我不这样做,它将不会取消选中所有字段。我还必须加入代码行 如果(lvi!= null)也是如此,因为如果你没有向下滚动它会认为列表中的项目为null并且崩溃。
无论如何它并不完美,但这就是我修复它的方式。使用MVVM的任何更好的解决方案都没有那么复杂的实现请赐教。
由于
答案 0 :(得分:0)
哇..这是一个老问题,无论出于何种原因,它都没有得到答复。
使用VisualTreeHelper
类型的东西几乎不是WPF中的最佳方法。它甚至不比基于DataBinding的正确方法“更容易”。
在这种情况下,由于您正在处理特定于UI的问题(显示或隐藏DataGrid的列),因此没有ViewModel,因此MVVM不适用于此处,并且代码隐藏完美有效的。
但是,您正在查看问题的错误结束:尝试操纵CheckBoxes(绑定目标)而不是简单地操纵绑定源(列本身):
private void chkSelectAll_Click(object sender, RoutedEventArgs e)
{
var visible = chkSelectAll.IsChecked ?? false;
foreach (var column in reportGrid.Columns)
column.Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
}
通过修改Visibility
属性的值,将更新每列的只读IsVisible
属性,绑定将新值传递给每个属性的CheckBox.IsChecked
属性相应的CheckBox。
答案 1 :(得分:0)
如果有人像我一样偶然发现这个问题,那么有一种很好的方法可以解决Paul提到的滚动问题:只需滚动代码隐藏!
listView.ScrollIntoView(listView.Items[listView.Items.Count - 1]);
listView.ScrollIntoView(listView.Items[0]);
之后,您可以在不获取null的情况下执行ItemContainerGenerator。
如果您想优化响应性(特别是对于不经常更改的较大列表):只需在listView的源内容发生更改时查询ItemContainerGenerator。因此,如果将CheckBoxes放在单独的列表中,则只需在用户第一次单击(De)Select All复选框时查询ItemContainerGenerator ...
但是你应该在(De)Select All复选框的Event处理程序中执行此操作,因为如果在设置itemsSource并进行滚动后立即查询CheckBoxes的ItemContainerGenerator,你仍然会得到空值(我假设因为当时GUI还没有时间正确呈现ListView。)