首页 > 解决方案 > 绑定 Text 属性以在作为 DataTemplate 的一部分的弹出窗口中进行过滤不起作用

问题描述

我有一个显示数据网格的应用程序。但是数据已经变大了,我想将过滤器合并到一些行中。我已经为我的标题创建了一个 DataTemplate:

<DataGrid>
<DataGrid.Resources>
   ...
    <DataTemplate x:Key="HeaderTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
             <ColumnDefinition/>
             <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

                    <ContentControl Content="{Binding}" VerticalAlignment="Center"/>
                    <ToggleButton Name="FilterButton" Grid.Column="1" Content="▼" Margin="2, 1, 1, 1" Padding="1, 0"/>
                     <Popup IsOpen="{Binding ElementName=FilterButton, Path=IsChecked}" PlacementTarget="{Binding ElementName=FilterButton}" StaysOpen="False">
                     <Border Background="White" Padding="3">
                            <TextBox Text={Binding PetNameFilterSearchBox, Mode=TwoWay} Width="300"/> <!--The Text Box I want to bind-->
                     </Border>
                    </Popup>
             </Grid>
         </DataTemplate>
</DataGrid.Resources>
   <DataGrid.Columns>
    <DataGridTextColumn Width="6*" Header="Pet Name" Binding="{Binding PetName}" ElementStyle="{DynamicResource DataGridTextColumnWrap}" HeaderTemplate="{StaticResource HeaderTemplate}"/>
   </DataGrid.Columns>
</DataGrid>

到目前为止,它所做的是在标题文本旁边显示一个按钮,当您单击它时,会出现一个包含文本框的小弹出窗口。期望的效果是用户可以在文本框中键入,数据将根据键入的内容进行过滤。

在我的视图模型中,我已经有了要用于绑定的过滤器文本框属性:

public string PetNameFilterSearchBox
{
    get
    {
        return _petNameFilterSearchBox;
    }
    set
    {
        _petNameFilterSearchBox = value;
        RaisePropertyChanged(nameof(PetNameFilterSearchBox));

        FilterData(); //As you're writing
    }
}
private string _petNameFilterSearchBox = string.Empty;

public CollectionView PetDataFilterView { get; set; }

public bool OnFilterTriggered(object item)
{
    if (item is AvailablePetInfo petInfo)
    {
        var pet_name = PetNameFilterSearchBox;

        if (pet_name != string.Empty)
                return (petInfo.DisplayName.Contains(pet_name));
    }
    return true;
}

public void FilterData()
{
    CollectionViewSource.GetDefaultView(AvailablePetInfo).Refresh();
}  

//Constructor
public PetInfoViewModel()
{
   AvailablePetInfo = GetPetInfo();//gets the list
   ContactFilterView = (CollectionView)CollectionViewSource.GetDefaultView(AvailablePetInfo);
   ContactFilterView.Filter = OnFilterTriggered;
}

当我运行我的代码时,我看到标题旁边的小按钮,我单击它并看到文本框。但是当我开始打字时,我看不到我的数据网格更新。我在我的 PetNameFilterSearchBox 中设置了一些断点,我发现当我开始输入时它没有被击中。这告诉我绑定有问题。有人可以告诉我我做错了什么吗?

标签: c#wpfdatagrid

解决方案


您的问题是其中之一DataContext

我将假设PetNameFilterSearchBoxWindow托管的属性,并且在级别设置DataGrid了适当的属性。DataContextWindow

通常,DataContext由子元素继承,因此设置DataContextforWindow将为它的所有子元素设置它。但是一旦你开始使用DataTemplates,情况就会改变。

在 aDataTemplate中,根DataContext始终是正在显示的数据对象。在您的情况下,这就是 string "Pet Name"。这就是为什么你可以把它放在<ContentControl Content="{Binding}"/>里面DataTemplate并让它显示"Pet Name"

缺点是你不能把<TextBox Text="{Binding PetNameFilterSearchBox}"/>它绑定到Window,因为它DataContextDataTemplate.

通常,您可以使用 来解决DataTemplate DataContext问题RelativeSource,您可以使用它来遍历可视化树并找到另一个要绑定的源。但这在 a 中不起作用,Popup因为 aPopup实际上不是Window' 的可视化树的一部分。

什么起作用ElementName

<TextBox Text="{Binding PetNameFilterSearchBox, Mode=TwoWay, ElementName=W}" Width="300"/>

在上面的示例中,我设置了我的Window Name="W".


推荐阅读