简体   繁体   English

如何从基础xaml“继承”

[英]How to “inherit” from base xaml

I have a PageViewModelBase where children need to implement 3 methods and everything works as intended, and as such, I'd like to create PageViewBase and have its children implement two simple non-generic things (namely: data context binding and data grid columns). 我有一个PageViewModelBase ,孩子需要实现3种方法,一切都按预期工作,因此,我想创建PageViewBase并让其孩子实现两个简单的非泛型事物(即:数据上下文绑定和数据网格列) 。

I've come across this post and tried to create the base xaml accordingly (code below), but despite my different approaches, I'm unable to create the child view. 我遇到过这篇文章,并尝试相应地创建基本xaml(下面的代码),但是尽管方法不同,但我无法创建子视图。 I've tried <baseView:PageViewBase> being the only element in xaml as well as embedding it into another UserControl, but both approaches fail. 我试过<baseView:PageViewBase>是xaml中的唯一元素,并将其嵌入到另一个UserControl中,但是两种方法都失败了。

Base view (a lot of noise code omitted, added example parts which child view has to implement for visualization): 基本视图(省略了很多噪声代码,添加了子视图必须实现以实现可视化的示例部分):

<UserControl x:Class="WPFapp.Views.Base.PageViewBase">
    <UserControl.Resources>
        <!--<DataTemplate DataType="{x:Type localVM:HardwareViewModel}">
            <local:HardwareView/>
        </DataTemplate>-->
        <localHelpers:DateTimeConverter x:Key="dateTimeConverter" />
        <localHelpers:StatusColorConverter x:Key="statusColorConverter" />
    </UserControl.Resources>
    <UserControl.InputBindings> </UserControl.InputBindings>
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" MinHeight="25" />
            <RowDefinition Height="15*" />
        </Grid.RowDefinitions>
        <ToolBarPanel Grid.Row="0" Orientation="Horizontal">
        </ToolBarPanel>

        <DataGrid ItemsSource="{Binding ItemsList}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" Grid.Row="1" AutoGenerateColumns="False" SelectionMode="Single">
            <DataGrid.ContextMenu> </DataGrid.ContextMenu>
            <DataGrid.InputBindings> </DataGrid.InputBindings>
            <DataGrid.Resources> </DataGrid.Resources>
            <DataGrid.RowStyle> </DataGrid.RowStyle>
            <ContentPresenter ContentSource="Content"/>
            <!--<DataGrid.Columns>
                <DataGridTextColumn Header="LastModifiedBy" Binding="{Binding LastModifiedBy}" />
            </DataGrid.Columns>-->
        </DataGrid>
    </Grid>
</UserControl>

Child view: 子视图:

<UserControl x:Class="WPFapp.Views.HardwareView">
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type localVM:HardwareViewModel}">
            <local:HardwareView/>
        </DataTemplate>
    </UserControl.Resources>
    <baseView:PageViewBase>
        <DataGrid>
            <DataGrid.Columns>
                <DataGridTextColumn Header="Id" Binding="{Binding Id}" />
                <DataGridTextColumn Header="Type" Binding="{Binding Type}" />
                <DataGridTextColumn Header="Label" Binding="{Binding Label}" />
                <DataGridTextColumn Header="Description" Binding="{Binding Description}" />
                <DataGridTextColumn Header="LastModifiedBy" Binding="{Binding LastModifiedBy}" />
                <DataGridTextColumn Header="LastModifiedAt" Binding="{Binding LastModifiedAt, Converter={StaticResource dateTimeConverter}}" />
            </DataGrid.Columns>
        </DataGrid>
    </baseView:PageViewBase>
</UserControl>

The above child's xaml code is the best I've managed so far, but it ends up displaying columns only (so no toolbar from base, for example) and it does not see UserControl.Resources from base view. 上面的孩子的xaml代码是我到目前为止所管理的最好的代码,但是它最终仅显示列(例如,没有显示基础工具栏),并且从基础视图中看不到UserControl.Resources How do I make it work? 我该如何运作?

Here's a solution that uses code-behind to dynamically add the correct columns to the DataGrid . 这是一种使用后台代码将正确的列动态添加到DataGrid的解决方案。 You'll only need the PageViewBase view, so you'll probably want to rename it since it won't be the "base" to anything. 您只需要PageViewBase视图,因此您可能要重命名它,因为它不会成为任何内容的“基础”。

In UserControl.Resources , add all the possible DataGrid columns you can have across all your different models. UserControl.Resources ,添加所有不同模型中可能具有的所有可能的DataGrid列。 For example, 例如,

<UserControl.Resources>
    <!-- Converters -->
    <localHelpers:DateTimeConverter x:Key="dateTimeConverter" />
    <localHelpers:StatusColorConverter x:Key="statusColorConverter" />

    <!-- DataGrid Columns -->
    <DataGridTextColumn x:Key="IdColumn" Header="Id" Binding="{Binding Id}" />
    <DataGridTextColumn x:Key="TypeColumn" Header="Type" Binding="{Binding Type}" />
    <DataGridTextColumn x:Key="LabelColumn" Header="Number" Binding="{Binding Label}" />
    <DataGridTextColumn x:Key="LastModifiedColumn" Header="LastModifiedAt" Binding="{Binding LastModifiedAt, Converter={StaticResource dateTimeConverter}}" />
    <!-- More column definitions go here for all model types -->
</UserControl.Resources>

Make sure to put the columns after the converters, so that you can use them in data-binding. 确保将列放在转换器之后,以便可以在数据绑定中使用它们。 Now, modify the DataGrid so that it runs the code-behind when it loads. 现在,修改DataGrid ,使其在加载时运行后台代码。 Also, remove the ContentPresenter : 另外,删除ContentPresenter

<DataGrid
    ItemsSource="{Binding ItemsList}"
    SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
    Grid.Row="1"
    AutoGenerateColumns="False"
    SelectionMode="Single"
    Loaded="DataGrid_OnLoaded"
    >
    <DataGrid.ContextMenu> </DataGrid.ContextMenu>
    <DataGrid.InputBindings> </DataGrid.InputBindings>
    <DataGrid.Resources> </DataGrid.Resources>
    <DataGrid.RowStyle> </DataGrid.RowStyle>
    <!-- Columns are loaded in code-behind -->
</DataGrid>

In the code-behind, add the correct DataGrid columns depending on the type of view model bound to the specific view (obtained via the view's DataContext ): 在后面的代码中,根据绑定到特定视图的视图模型的类型(通过视图的DataContext )添加正确的DataGrid列:

private void DataGrid_OnLoaded(object sender, RoutedEventArgs e)
{
    if (sender is DataGrid dataGrid)
    {
        if (DataContext is HardwareViewModel)
        {
            dataGrid.Columns.Add(Resources["IdColumn"] as DataGridColumn);
            dataGrid.Columns.Add(Resources["TypeColumn"] as DataGridColumn);
            // More columns added here
        }
        else if (DataContext is AnotherHardwareViewModel)
        {
            dataGrid.Columns.Add(Resources["IdColumn"] as DataGridColumn);
            dataGrid.Columns.Add(Resources["LabelColumn"] as DataGridColumn);
            dataGrid.Columns.Add(Resources["LastModifiedColumn"] as DataGridColumn);
            // More columns added here
        }
    }
}

Finally, whoever is creating the PageViewBase needs to bind it to the desired view model for the specific type you want. 最后,无论创建PageViewBase需要将其绑定到所需的视图模型以用于所需的特定类型。 For example, 例如,

<StackPanel>
    <local:PageViewBase DataContext="{Binding HardwareViewModel}" />
    <local:PageViewBase DataContext="{Binding AnotherHardwareViewModel}" />
</StackPanel>

I've tested this solution for a simple case, and I correctly get different sets of columns in the two DataGrid s. 我已经针对一种简单的情况测试了该解决方案,并且在两个DataGrid正确地获得了不同的列集。 However, I haven't tried this with a more complex case, so I apologize in advance if it doesn't solve your specific problem. 但是,我还没有在更复杂的情况下尝试过此操作,因此如果无法解决您的特定问题,我会向您道歉。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM