基于datacontext

时间:2017-09-08 17:49:55

标签: c# wpf xaml mvvm

我有一大块xaml,它复制相同的模式六次,并希望通过消除重复来减少这种占用空间。我遇到了一个需要帮助的障碍。

背景:我有一个类,它实例化另一个类六次(项目的各个阶段)。

   public ECN(string ecnNumber) {
        _ECNNumber = ecnNumber;

        //instantiate each phase to be populated or not
        _PurchaseParts = new ECNPhase();
        _PieceParts = new ECNPhase();
        _Weldments = new ECNPhase();
        _BOMCfg = new ECNPhase();
        _Cleanup = new ECNPhase();
        _PRAF = new ECNPhase();   
    }

每个阶段内部都是ECNPhase类中引用的Changes(另一个类)的集合。每个阶段都有一个独特的数据,每个阶段都以独特的视图显示,这是我稍后会展示的障碍。

重复xaml代码的示例,主要区别在于每个扩展器内的不同视图:

<StackPanel Margin="0">

    <!--Section for Purchase parts-->
    <StackPanel Orientation="Horizontal" >
        <CheckBox Margin="0,5,5,5" IsChecked="{Binding Path=MyWorkspace.CurrentSelectedItem.PurchaseParts.HasPhase,Mode=TwoWay}"/>
        <StackPanel Orientation="Horizontal">
            <StackPanel.Style>
                <Style TargetType="{x:Type StackPanel}">
                    <Setter Property="IsEnabled" Value="False"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=MyWorkspace.CurrentSelectedItem.PurchaseParts.HasPhase}" Value="True">
                            <Setter Property="IsEnabled" Value="True"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </StackPanel.Style>
            <Expander Header="Purchase Parts" Margin="0,0,10,0" Width="110">
                <view:PurchasePartsView/>
            </Expander>
            <CheckBox Content="Submit" Margin="10,5,0,5"/> <!--add a command to handle the submit checkbox event-->
            <Label Content="Status:" Margin="10,0,0,0" HorizontalContentAlignment="Right" Width="60"/>
            <Label Content="{Binding Path=MyWorkspace.CurrentSelectedItem.PurchaseParts.Status}"/>
        </StackPanel>
    </StackPanel>

    <!--Section for Piece Parts-->
    <StackPanel Orientation="Horizontal">
        <CheckBox  Margin="0,5,5,5" IsChecked="{Binding Path=MyWorkspace.CurrentSelectedItem.PieceParts.HasPhase,Mode=TwoWay}"/>
        <StackPanel Orientation="Horizontal">
            <StackPanel.Style>
                <Style TargetType="{x:Type StackPanel}">
                    <Setter Property="IsEnabled" Value="False"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=MyWorkspace.CurrentSelectedItem.PieceParts.HasPhase}" Value="True">
                            <Setter Property="IsEnabled" Value="True"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </StackPanel.Style>
            <Expander Header="Piece Parts"  Margin="0,0,10,0" Width="110">
                <view:PiecePartsView/>
            </Expander>
            <CheckBox Content="Submit" Margin="10,5,0,5"/> <!--add a command to handle the submit checkbox event-->
            <Label Content="Status:" Margin="10,0,0,0" HorizontalContentAlignment="Right" Width="60"/>
            <Label Content="{Binding Path=MyWorkspace.CurrentSelectedItem.PieceParts.Status}"/>
        </StackPanel>
    </StackPanel>
    <!--duplicated four more times-->
</StackPanel>

我想做的是:

<StackPanel>
    <view:PhaseView DataContext="{Binding Path=MyWorkspace.CurrentSelectedItem.PurchaseParts}"/>
    <view:PhaseView DataContext="{Binding Path=MyWorkspace.CurrentSelectedItem.PieceParts}"/>
    <!--four more phases-->
</StackPanel>

PhaseView将成为处理复制的模板,这就是我遇到麻烦的地方。每个阶段都需要一个基于PhaseView的datacontext选择的唯一视图(userControl)。

<StackPanel Orientation="Horizontal" >
    <CheckBox Margin="0,5,5,5" IsChecked="{Binding Path=HasPhase,Mode=TwoWay}"/>
    <StackPanel Orientation="Horizontal">
        <StackPanel.Style>
            <Style TargetType="{x:Type StackPanel}">
                <Setter Property="IsEnabled" Value="False"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=HasPhase}" Value="True">
                        <Setter Property="IsEnabled" Value="True"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </StackPanel.Style>
        <Expander Header="DisplayName" Margin="0,0,10,0" Width="110">
            <!--add somthing here to select the correct view based on the datacontext-->
            <!--<local:PurchasePartsView/>  This user control adds a datagrid that is unique to each phase-->
        </Expander>
        <CheckBox Content="Submit" Margin="10,5,0,5"/> <!--add a command to handle the submit checkbox event-->
        <Label Content="Status:" Margin="10,0,0,0" HorizontalContentAlignment="Right" Width="60"/>
        <Label Content="{Binding Path=Status}"/>
    </StackPanel>
</StackPanel>

我正在考虑使用数据触发器以某种方式显示如下,但我没有任何运气搞清楚。我知道必须有办法做到这一点,这可能是简单而愚蠢的事情。任何帮助将不胜感激。

<DataTrigger Binding="{Binding Path=DisplayName}" Value="Purchase Parts">
   <Setter Property="DataContext" Value="{Binding }"/> <!--Don't know how to bind the DataContext-->
</DataTrigger>

谢谢,

1 个答案:

答案 0 :(得分:0)

好的,感谢Bradley,我查看了DataTemplateSelector,这就是我想出来的。

在我的UserControl资源中,我设置了几个DataTemplates和一个覆盖DataTemplateSelector类的TemplateSelector类的引用。

XAML资源:

<UserControl.Resources>

    <local:TemplateSelector x:Key="myTemplateSelector"/>

    <DataTemplate x:Key="PurchasePartsTemplate">
        <view:PurchasePartsView/>
    </DataTemplate>
    <DataTemplate x:Key="PiecePartsTemplate">
        <view:PiecePartsView/>
    </DataTemplate>
    <!--Four more templates-->        
</UserControl.Resources>

DataTemplateSelector覆盖的代码隐藏。注意:我无法找到绑定到ECNPhase类的方法,因此我绑定到类中的DisplayName属性以提取正确的实例。

class TemplateSelector : DataTemplateSelector {

    public override DataTemplate SelectTemplate(object item, DependencyObject container) {

        FrameworkElement element = container as FrameworkElement;

        if(element != null && item != null && item is string) {
            string phase = (string)item;

            if(phase == "Purchase Parts") {
                return element.FindResource("PurchasePartsTemplate") as DataTemplate;
            }else if(phase == "Piece Parts") {
                return element.FindResource("PiecePartsTemplate") as DataTemplate;
            }
        }
        return null;
    }
}

我在我的UserContol中调用此类,如下所示:

<Expander Header="{Binding Path=DisplayName}" Margin="0,0,10,0" Content="{Binding Path=DisplayName}" 
                  ContentTemplateSelector="{StaticResource myTemplateSelector}"/>

没有与扩展器关联的项控件,因此我使用了内容控件。我将DisplayName传递给control属性,contentTemplateSelector使用myTemplateSelector资源进入代码隐藏,并根据DisplayName选择要使用的相应datatemplate。

现在我可以这样调用我的可重用模板:

<StackPanel Margin="0">
    <view:ChangePhaseView DataContext="{Binding Path=MyWorkspace.CurrentSelectedItem.PurchaseParts}"/>
    <view:ChangePhaseView DataContext="{Binding Path=MyWorkspace.CurrentSelectedItem.PieceParts}"/>
</StackPanel>

@Bradley,谢谢你指出我正确的方向。