Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#-弹出窗口不显示在MVVM的第二个选项卡项中_C#_Wpf_Mvvm_Binding_Tabitem - Fatal编程技术网

C#-弹出窗口不显示在MVVM的第二个选项卡项中

C#-弹出窗口不显示在MVVM的第二个选项卡项中,c#,wpf,mvvm,binding,tabitem,C#,Wpf,Mvvm,Binding,Tabitem,我在MVVM中工作,我在XAML中创建了两个TabItem。在第一个窗口中,会显示弹出窗口,但在第二个窗口中,当我按下与列对应的按钮时,不会显示弹出窗口 以下是我的工作弹出窗口代码: <Viewbox> <Grid Height="359" Width="746"> <Popup Name="popupFilter" Placement="MousePoint" IsOpen="{Binding IsFilterOpen, Mode=OneW

我在MVVM中工作,我在XAML中创建了两个
TabItem
。在第一个窗口中,会显示弹出窗口,但在第二个窗口中,当我按下与列对应的按钮时,不会显示弹出窗口

以下是我的工作弹出窗口代码:

<Viewbox>
    <Grid Height="359" Width="746">
        <Popup Name="popupFilter" Placement="MousePoint" IsOpen="{Binding IsFilterOpen, Mode=OneWay}" StaysOpen="True" Width="200">
            <Border Background="White" BorderBrush="Gray" BorderThickness="1,1,1,1">
                <StackPanel Margin="5,5,5,15">
                    <ListBox x:Name="listBoxPopupContent" 
                             Height="250" 
                             ItemsSource="{Binding FilterItems}" 
                             BorderThickness="0" 
                             ScrollViewer.VerticalScrollBarVisibility="Auto">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding IsChecked}" 
                                          Content="{Binding Item}" 
                                          Command="{Binding DataContext.ApplyFiltersCommand, 
                                                RelativeSource={RelativeSource FindAncestor, 
                                                AncestorType={x:Type ListBox}}}"
                                          CommandParameter="{Binding IsChecked, 
                                                RelativeSource={RelativeSource Self}, 
                                                Mode=OneWay}"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </StackPanel>
            </Border>
        </Popup>

        <Grid HorizontalAlignment="Left" Height="261" Margin="0,63,0,0" VerticalAlignment="Top" Width="736">
            <TabControl HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="716" Margin="10,0,0,0">
                <TabItem Header="Class">
                    <DataGrid x:Name="ClassViewDataGrid" ItemsSource="{Binding FilteredClassViewItems}" 
                              AutoGenerateColumns="False"
                              IsReadOnly="True"
                              CanUserReorderColumns="True"
                              CanUserResizeColumns="True"
                              CanUserSortColumns="True">
                        <DataGrid.Columns>
                            <DataGridTextColumn Binding="{Binding ClassName}">
                                <DataGridTextColumn.Header>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="Class" />
                                        <Button Name="buttonClassViewClassFilter" Margin="10,0,0,0"                          
                                                Command="{Binding DataContext.ShowFilterCommand, 
                                                    RelativeSource={RelativeSource FindAncestor, 
                                                    AncestorType={x:Type DataGrid}}}"
                                                CommandParameter="{Binding Name, RelativeSource={RelativeSource Self}}">
                                            <Button.ContentTemplate>
                                                <DataTemplate>
                                                    <Image Source="/Images/filter.png" Width="10" Height="10" />
                                                </DataTemplate>
                                            </Button.ContentTemplate>
                                        </Button>
                                    </StackPanel>
                                </DataGridTextColumn.Header>

我做错了什么?

如果您交换两个选项卡项的顺序,或者在选项卡控件上设置
SelectedIndex=“1”
,您会发现最初可见的选项卡总是唯一有效的。我将
PresentationTraceSources.TraceLevel=High
添加到
命令
绑定中,发现启动时隐藏的TabItem中的绑定最初尝试解析其源属性,当该TabItem变为活动状态时不再重试

问题是,在第一次尝试解析隐藏选项卡项中的绑定时,该选项卡项的UI实际上还不存在。由于虚拟化,在需要之前不会创建它。所创建的只是它的标题内容,悬挂在空间中。DataGrid还不存在,所以AncestorType搜索永远找不到它。最终创建DataGrid时,似乎没有引发任何事件来通知绑定需要重复祖先搜索

解决方法很简单:通过DataTemplate创建标题内容。无论如何,这是正确的方法。当显示DataGrid时,DataTemplate将被实例化

我们将使用值转换器创建一个标识符,该标识符告诉命令用户单击了哪个网格和列。请注意,我们现在为每个列的Header属性提供一个普通字符串,模板中的
TextBlock
更改为

XAML

如果您想在两个不同数据网格中的列之间改变标题内容,可以通过绑定来实现,或者在必要时创建第二个模板


您也可以在
TabControl.Resources
中创建,但是绑定代理是我们在没有“正确”方法做某事时使用的最后一道难题。在这种情况下,“正确”的方法很简单、直接,而且非常令人满意。

我是否正确地理解您将XAML包含在有效的XAML中,而不是不起作用的XAML中?@EdPlunkett,感谢更新,我现在已将它们都包含在内。绑定到这两个项目的父项是否也有效,例如
选项卡控件
本身?在计算绑定时没有创建DataGrid,但是TabControl应该是无效的。从标题内容到TabControl的可视树链贯穿DataGrid——如果还不存在,那你就倒霉了
ElementName=MyTabControl
也不起作用(我没有忘记给TabControl起这个名字!),可能也是因为它们不在同一个可视树中。在OP的原始XAML中,
StackPanel
inside
DataGridTextColumn.Header
是绑定尝试解析时的事件范围。啊,好的,很高兴知道。我知道我过去在列标题中遇到过数据绑定问题,因为它们似乎不像其他控件那样继承DataContext。很高兴知道这个解决方案:)@EdPlunkett OK。谢谢你完整的回答。但是我希望每个弹出窗口都有不同的内容,这就是为什么我在C代码中使用了按钮的名称。。知道我点击了哪个按钮,并相应地填写列表。我现在可以获得这方面吗?这就是为什么我需要确定我点击了哪个按钮
<TabItem Header="Field">
    <DataGrid x:Name="FielsdViewDataGrid" ItemsSource="{Binding FilteredFieldViewItems}" 
              AutoGenerateColumns="False"
              IsReadOnly="True"
              CanUserReorderColumns="True"
              CanUserResizeColumns="True"
              CanUserSortColumns="True">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding ClassName}">
                <DataGridTextColumn.Header>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Class" />
                        <Button Name="buttonFieldViewClassFilter" Margin="10,0,0,0"                          
                                Command="{Binding DataContext.ShowFilterCommand, 
                                    RelativeSource={RelativeSource FindAncestor, 
                                    AncestorType={x:Type DataGrid}}}"
                                CommandParameter="{Binding Name, RelativeSource={RelativeSource Self}}">
                            <Button.ContentTemplate>
                                <DataTemplate>
                                    <Image Source="/Images/filter.png" Width="10" Height="10" />
                                </DataTemplate>
                            </Button.ContentTemplate>
                        </Button>
                    </StackPanel>
                </DataGridTextColumn.Header>
private void ShowFilterCommandRaised(object obj)
{
    IsFilterOpen = !IsFilterOpen;
    str = obj;
    if (IsFilterOpen)
    {
        if (str.Equals("buttonClassViewClassFilter"))
        {
            FilterItems.Clear();
            foreach (var classView in classViewItems)
            {
                FilterItems.Add(new CheckedListItem<string>(classView.ClassName, true));
            }
        }

        if (str.Equals("buttonClassViewExtendsFilter"))
        {
            FilterItems.Clear();
            foreach (var classView in classViewItems)
            {
                FilterItems.Add(new CheckedListItem<string>(classView.Category, true));
            }
        }

        if (str.Equals("buttonFieldViewClassFilter"))
        {
            FilterItems.Clear();
            foreach (var fieldView in fieldViewItems)
            {
                FilterItems.Add(new CheckedListItem<string>(fieldView.ClassName, true));
            }
        }
    }
<TabControl HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="716" Margin="10,0,0,0">
    <TabControl.Resources>
        <local:GetColumnIdentifier x:Key="GetColumnIdentifier" />
        
        <DataTemplate x:Key="FilterColumnHeaderTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding}" />
                <Button 
                    Margin="10,0,0,0"
                    Command="{Binding DataContext.ShowFilterCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" 
                    CommandParameter="{Binding Converter={StaticResource GetColumnIdentifier}, RelativeSource={RelativeSource Self}}"
                    >
                    <Button.ContentTemplate>
                        <DataTemplate>
                            <Image Source="/Images/filter.png" Width="10" Height="10" />
                        </DataTemplate>
                    </Button.ContentTemplate>
                </Button>
            </StackPanel>
        </DataTemplate>
    </TabControl.Resources>
    <TabItem Header="Class">
        <DataGrid 
            x:Name="ClassViewDataGrid" 
            ItemsSource="{Binding FilteredClassViewItems}" 
            AutoGenerateColumns="False"
            IsReadOnly="True"
            CanUserReorderColumns="True"
            CanUserResizeColumns="True"
            CanUserSortColumns="True"
            >
            <DataGrid.Columns>
                <DataGridTextColumn 
                    Header="Class"
                    Binding="{Binding ClassName}" 
                    HeaderTemplate="{StaticResource FilterColumnHeaderTemplate}"
                    />
            </DataGrid.Columns>
        </DataGrid>
    </TabItem>
    <TabItem Header="Field">
        <DataGrid 
            x:Name="FielsdViewDataGrid" 
            ItemsSource="{Binding FilteredFieldViewItems}" 
            AutoGenerateColumns="False"
            IsReadOnly="True"
            CanUserReorderColumns="True"
            CanUserResizeColumns="True"
            CanUserSortColumns="True"
            >
            <DataGrid.Columns>
                <DataGridTextColumn 
                    Header="Class"
                    Binding="{Binding ClassName}" 
                    HeaderTemplate="{StaticResource FilterColumnHeaderTemplate}"
                    />
            </DataGrid.Columns>
        </DataGrid>
    </TabItem>
</TabControl>
//using System.Windows.Markup.Primitives;
//using System.Windows.Controls.Primitives;

public class GetColumnIdentifier : IValueConverter
{
    private static T GetVisualAncestor<T>(DependencyObject obj)
        where T : DependencyObject
    {
        while (obj != null)
        {
            if (obj is T)
                return obj as T;
            else
                obj = VisualTreeHelper.GetParent(obj);
        }

        return null;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        //  Not all DataGridColumn subclasses have a Binding property. 
        var header = GetVisualAncestor<DataGridColumnHeader>((DependencyObject)value);
        var datagrid = GetVisualAncestor<DataGrid>(header);
        
        if (header?.Column != null)
        {
            MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(header.Column);
            var bindingProp = markupObject.Properties.FirstOrDefault(p => p.Name == "Binding");

            if (bindingProp?.Value is Binding binding)
            {
                return $"{datagrid?.Name}.{binding.Path.Path}";
            }
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}
<TabControl HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="716" Margin="10,0,0,0">
    <TabItem Header="Class">
        <DataGrid 
            x:Name="ClassViewDataGrid" 
            ItemsSource="{Binding FilteredClassViewItems}" 
            AutoGenerateColumns="False"
            IsReadOnly="True"
            CanUserReorderColumns="True"
            CanUserResizeColumns="True"
            CanUserSortColumns="True"
            >
            <DataGrid.Columns>
                <DataGridTextColumn 
                    Header="Class"
                    Binding="{Binding ClassName}" 
                    >
                    <DataGridTextColumn.HeaderTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding}" />
                                <Button 
                                    Name="buttonClassViewClassFilter" 
                                    Margin="10,0,0,0"
                                    Command="{Binding DataContext.ShowFilterCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" 
                                    CommandParameter="{Binding Name, RelativeSource={RelativeSource Self}}"
                                    >
                                    <Button.ContentTemplate>
                                        <DataTemplate>
                                            <Image Source="/Images/filter.png" Width="10" Height="10" />
                                        </DataTemplate>
                                    </Button.ContentTemplate>
                                </Button>
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTextColumn.HeaderTemplate>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </TabItem>
    <TabItem Header="Field">
        <DataGrid 
            x:Name="FielsdViewDataGrid" 
            ItemsSource="{Binding FilteredFieldViewItems}" 
            AutoGenerateColumns="False"
            IsReadOnly="True"
            CanUserReorderColumns="True"
            CanUserResizeColumns="True"
            CanUserSortColumns="True"
            >
            <DataGrid.Columns>
                <DataGridTextColumn 
                    Header="Class"
                    Binding="{Binding ClassName}" 
                    >
                    <DataGridTextColumn.HeaderTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding}" />
                                <Button 
                                    Name="buttonFieldViewClassFilter" 
                                    Margin="10,0,0,0"
                                    Command="{Binding DataContext.ShowFilterCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" 
                                    CommandParameter="{Binding Name, RelativeSource={RelativeSource Self}}"
                                    >
                                    <Button.ContentTemplate>
                                        <DataTemplate>
                                            <Image Source="/Images/filter.png" Width="10" Height="10" />
                                        </DataTemplate>
                                    </Button.ContentTemplate>
                                </Button>
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTextColumn.HeaderTemplate>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </TabItem>
</TabControl>
<TabControl HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="716" Margin="10,0,0,0">
    <TabControl.Resources>
        <DataTemplate x:Key="FilterColumnHeaderTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding}" />
                <Button 
                    Name="buttonClassFilter" 
                    Margin="10,0,0,0"
                    Command="{Binding DataContext.ShowFilterCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" 
                    CommandParameter="{Binding Name, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
                    >
                    <Button.ContentTemplate>
                        <DataTemplate>
                            <Rectangle Fill="DeepSkyBlue" Width="10" Height="10" />
                        </DataTemplate>
                    </Button.ContentTemplate>
                </Button>
            </StackPanel>
        </DataTemplate>
    </TabControl.Resources>
    <TabItem Header="Class">
        <DataGrid 
            x:Name="ClassViewDataGrid" 
            ItemsSource="{Binding FilteredClassViewItems}" 
            AutoGenerateColumns="False"
            IsReadOnly="True"
            CanUserReorderColumns="True"
            CanUserResizeColumns="True"
            CanUserSortColumns="True"
            >
            <DataGrid.Columns>
                <DataGridTextColumn 
                    Header="Class"
                    Binding="{Binding ClassName}" 
                    HeaderTemplate="{StaticResource FilterColumnHeaderTemplate}" 
                    />
            </DataGrid.Columns>
        </DataGrid>
    </TabItem>
    <TabItem Header="Field">
        <DataGrid 
            x:Name="FielsdViewDataGrid" 
            ItemsSource="{Binding FilteredFieldViewItems}" 
            AutoGenerateColumns="False"
            IsReadOnly="True"
            CanUserReorderColumns="True"
            CanUserResizeColumns="True"
            CanUserSortColumns="True"
            >
            <DataGrid.Columns>
                <DataGridTextColumn
                    Header="Class"
                    Binding="{Binding ClassName}" 
                    HeaderTemplate="{StaticResource FilterColumnHeaderTemplate}" 
                    />
            </DataGrid.Columns>
        </DataGrid>
    </TabItem>
</TabControl>