【问题标题】:How to "inherit" from base xaml如何从基本 xaml “继承”
【发布时间】:2019-01-14 05:20:48
【问题描述】:

我有一个PageViewModelBase,孩子们需要实现 3 种方法并且一切都按预期工作,因此,我想创建 PageViewBase 并让其孩子实现两个简单的非通用事物(即:数据上下文绑定和数据网格列)。

我遇到了this post 并尝试相应地创建基本 xaml(代码如下),但尽管我采用不同的方法,但我无法创建子视图。我尝试将<baseView:PageViewBase> 作为 xaml 中的唯一元素并将其嵌入到另一个 UserControl 中,但两种方法都失败了。

基本视图(省略了很多干扰代码,添加了子视图必须实现的示例部分以进行可视化):

<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>

子视图:

<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>

上述孩子的 xaml 代码是迄今为止我管理过的最好的,但它最终只显示列(例如,因此没有来自基础的工具栏)并且它没有从基础视图中看到 UserControl.Resources。如何让它发挥作用?

【问题讨论】:

  • DataGrid 不继承自ContentControl,因此在DataGrid 中包含ContentPresenter 不会产生您想要的效果。
  • 您能解释一下为什么要在另一个视图中定义DataGrid 列吗?也许您的问题还有其他解决方案。
  • 好吧,视图是我的模型的可视化,我有 6 个不同的模型,其处理逻辑 (viewModel) 具有相同的核心(因此它们都继承自 PageViewModelBase)+ 一些每个的自定义实现。一些模型具有枚举,一些具有 DateTimes,一些具有其他类作为它们的属性。我需要使用各种转换器在各种设置中显示它们。这些模型中的每一个都以单独的视图呈现,但它们的处理(即热键)和样式与其他模型一致。这就是为什么我只需要指定列(和数据绑定)。
  • 不确定你想在这里做什么。也许您可以将常用的东西作为模板应用到内容控件。然后,您将数据网格放在每个“子”视图的内容控件中。定义它们的列等。共同点在应用于该内容控件的模板中。您也可以说服用户控件获取内容并再次将您的数据网格作为内容粘贴在其中。
  • 我不想在 6 个以及未来更多的视图中重复数十行代码,它们之间的唯一区别是它们的数据网格列。据我所知,模板不支持InputBindgins 以及我指定的代码中的许多其他内容。

标签: c# wpf xaml inheritance


【解决方案1】:

这是一个使用代码隐藏将正确的列动态添加到DataGrid 的解决方案。您只需要 PageViewBase 视图,因此您可能需要重命名它,因为它不是任何东西的“基础”。

UserControl.Resources 中,添加您可以在所有不同模型中拥有的所有可能的DataGrid 列。例如,

<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>

确保将列放在转换器之后,以便您可以在数据绑定中使用它们。现在,修改DataGrid 使其在加载时运行代码隐藏。另外,删除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>

在代码隐藏中,根据绑定到特定视图的视图模型类型添加正确的DataGrid 列(通过视图的DataContext 获得):

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
        }
    }
}

最后,创建PageViewBase 的人需要将其绑定到您想要的特定类型的所需视图模型。例如,

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

我已经针对一个简单的案例测试了这个解决方案,并且我正确地在两个 DataGrids 中获得了不同的列集。但是,我还没有尝试过更复杂的案例,所以如果它不能解决您的具体问题,我提前道歉。

【讨论】:

  • 好吧,这不是理想的解决方案,但它有助于避免重复代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多