样式内行为中的数据绑定

Databinding in Behavior inside a style

我创建了一个自定义控件(自​​动完成查找),它根据我在底层弹出窗口的文本框中键入的关键字显示搜索结果。

我可以为查找部分定义模板,即代表所选项目的文本框和建议部分,即显示临时结果的弹出窗口。

图片显示了建议模板的外观。

在xaml中你可以像这样定义模板

<controls:AutoCompleteLookup
    Watermark="Tank"
    Provider={Binding TankProvider}
    SelectedItem={Binding SelectedCustomer}>
    <controls:AutoCompleteLookup.LookupTemplate>
        <DataTemplate DataType="{x:Type providers:TankLookupResult}">
            <TextBlock Text="{Binding TankName}"/>
        </DataTemplate>
    </controls:AutoCompleteLookup.LookupTemplate>
    <controls:AutoCompleteLookup.SuggestionsView>
       <GridView x:Key="ContractStorageDetailGridView" x:Shared="False">
          <GridViewColumn Header="Tank" Width="Auto" HeaderContainerStyle="{StaticResource GridViewHeaderStyle}">
            <GridViewColumn.CellTemplate>
              <DataTemplate>
                <mubctrls:SuggestionTextBlock Suggestion="{Binding TankName}" Foreground="Red"/>
              </DataTemplate>
             </GridViewColumn.CellTemplate>
          </GridViewColumn>
          <GridViewColumn Header="Int. Reference" Width="Auto" HeaderContainerStyle="{StaticResource GridViewHeaderStyle}">
            <GridViewColumn.CellTemplate>
              <DataTemplate>
                <TextBlock Text="{Binding InternalReference}"/>
              </DataTemplate>
            </GridViewColumn.CellTemplate>
          </GridViewColumn>
          <GridViewColumn Header="Customer" Width="Auto" HeaderContainerStyle="{StaticResource GridViewHeaderStyle}">
            <GridViewColumn.CellTemplate>
              <DataTemplate>
                  <TextBlock Text="{Binding CustomerName}"/>
              </DataTemplate>
            </GridViewColumn.CellTemplate>
          </GridViewColumn>
       </GridView>
    </controls:AutoCompleteLookup.SuggestionTemplate>
</controls:AutoCompleteLookup>

这很好用。现在我想在网格视图中显示动态列。为此,我做了一个获取动态数据并根据需要显示列的行为(以下代码放在上面)

<i:Interaction.Behaviors>
<mubctrls:DynamicColumnsBehavior GroupColumnsByKey="False">
    <mubctrls:DynamicColumnsBehavior.DynamicColumns>
        <mubctrls:DynamicGridViewColumn 
        Width="Auto"
        DetailSelector="{Binding Path=Data.SuggestionsViewDynamicColumnSelector, Source={StaticResource Proxy}}">

            <mubctrls:DynamicGridViewColumn.HeaderTemplate>
                <DataTemplate>
                    <!-- The DataContext for the header is represented by the TDynamicColumnKey type. In this case it is UOMLookupResult. -->
                    <TextBlock Text="{Binding UOMName}"/>
                </DataTemplate>
            </mubctrls:DynamicGridViewColumn.HeaderTemplate>

            <mubctrls:DynamicGridViewColumn.CellTemplate>
                <DataTemplate>
                    <!-- The DataContext for the cells is an instance that has a Root and a Detail property.
                        The Root property refers to the TankSuggestion while the Detail property refers to an instance of TDynamicColumnCellData
                        which in this case is TankUOMQuantity.
                -->
                    <TextBlock Text="{Binding Detail.DisplayQuantity}"/>
                </DataTemplate>
            </mubctrls:DynamicGridViewColumn.CellTemplate>

        </mubctrls:DynamicGridViewColumn>
    </mubctrls:DynamicColumnsBehavior.DynamicColumns>
</mubctrls:DynamicColumnsBehavior>

起初我很挣扎,因为行为似乎不是可视化树的一部分,因此很难获得 DataContext。对于这个问题,我发现 this article。 在提到的 BindingProxy 的帮助下,我可以传递数据上下文并绑定到动态数据。到目前为止,一切都很好。不幸的是,每次我想使用这个控件时,xaml 中都需要很多代码,而且模板大部分时间都是相同的,所以我试图为控件制作一个样式。大多数项目都有效,但动态列部分除外。我将 "Proxy" 放在该部分内,但似乎这不起作用,因为没有显示动态列(我猜 Data.SuggestionsViewDynamicColumnSelector 未找到,因为缺少 DataContext)。有谁知道如何将上面的代码放在样式中,以使其正常工作?这是我的尝试:

<Style x:Key="CustomsDetailWithDynamicColumnsStyle" TargetType="{x:Type mubctrls:AutoCompleteLookup}" BasedOn="{StaticResource AutoCompleteLookupBaseStyle}">
    <Style.Resources>
        <mubctrls:BindingProxy x:Key="Proxy" Data="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type mubctrls:AutoCompleteLookup}}}"/>
    </Style.Resources>
    <Setter Property="Watermark" Value="{x:Static resources:LabelResources.CustomsDetail}"/>
    <Setter Property="NoSuggestionsErrorText" 
            Value="{Binding Converter={StaticResource FormatStringConverter}, 
                            ConverterParameter={x:Static resources:LabelResources.CustomsDetail}}"/>
    <Setter Property="LookupTemplate">
        <Setter.Value>
            <DataTemplate DataType="{x:Type customsDetail:CustomsDetailLookupResult}">
                <TextBlock>
                    <TextBlock.Text>
                        <MultiBinding StringFormat=" {0} ({1})">
                            <Binding Path="DocumentNumber"/>
                        </MultiBinding>
                    </TextBlock.Text>
                </TextBlock>
            </DataTemplate>
        </Setter.Value>
    </Setter>

    <Setter Property="SuggestionsView">
        <Setter.Value>
            <GridView x:Name="Test">
                <GridViewColumn Header="{x:Static resources:LabelResources.Id}">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <mubctrls:SuggestionTextBlock Suggestion="{Binding Id}" Foreground="Red" Width="30"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="{x:Static resources:LabelResources.CustomsLicensePermit}" Width="120">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <mubctrls:SuggestionTextBlock Suggestion="{Binding PermitName}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="{x:Static resources:LabelResources.Customer}" Width="150">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <mubctrls:SuggestionTextBlock Suggestion="{Binding CustomerName}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="{x:Static resources:LabelResources.ProductClassification}" Width="120">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <mubctrls:SuggestionTextBlock Suggestion="{Binding ProductClassificationName}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="{x:Static resources:LabelResources.Tank}" Width="120">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <mubctrls:SuggestionTextBlock Suggestion="{Binding TankName}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="{x:Static resources:LabelResources.Origin}" Width="120">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <mubctrls:SuggestionTextBlock Suggestion="{Binding CountryOfOrigin}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="{x:Static resources:LabelResources.Date}" Width="120">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <mubctrls:SuggestionTextBlock Suggestion="{Binding DocumentDate, StringFormat={}{0:MM/dd/yyyy}}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="{x:Static resources:LabelResources.DocumentNumber}" Width="150">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <mubctrls:SuggestionTextBlock Suggestion="{Binding DocumentNumber}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <!-- Definition of the dynamic columns -->
                <i:Interaction.Behaviors>
                    <mubctrls:DynamicColumnsBehavior GroupColumnsByKey="False">
                        <mubctrls:DynamicColumnsBehavior.DynamicColumns>
                            <mubctrls:DynamicGridViewColumn 
                            Width="Auto"
                            DetailSelector="{Binding Path=Data.SuggestionsViewDynamicColumnSelector, Source={StaticResource Proxy}}">

                                <mubctrls:DynamicGridViewColumn.HeaderTemplate>
                                    <DataTemplate>
                                        <!-- The DataContext for the header is represented by the TDynamicColumnKey type. In this case it is UOMLookupResult. -->
                                        <TextBlock Text="{Binding UOMName}"/>
                                    </DataTemplate>
                                </mubctrls:DynamicGridViewColumn.HeaderTemplate>

                                <mubctrls:DynamicGridViewColumn.CellTemplate>
                                    <DataTemplate>
                                        <!-- The DataContext for the cells is an instance that has a Root and a Detail property.
                                            The Root property refers to the TankSuggestion while the Detail property refers to an instance of TDynamicColumnCellData
                                            which in this case is TankUOMQuantity.
                                    -->
                                        <TextBlock Text="{Binding Detail.DisplayQuantity}"/>
                                    </DataTemplate>
                                </mubctrls:DynamicGridViewColumn.CellTemplate>

                            </mubctrls:DynamicGridViewColumn>
                        </mubctrls:DynamicColumnsBehavior.DynamicColumns>
                    </mubctrls:DynamicColumnsBehavior>
                </i:Interaction.Behaviors>
            </GridView>
        </Setter.Value>
    </Setter>                  
</Style>

我还尝试将 DetailSelector 的绑定更改为

DetailSelector={Binding Path=SuggestionsViewDynamicColumnSelector, RelativeSource={RelativeSource TemplatedParent}}"

但是也没用。

抱歉这么久 post。欢迎提问

将此 <mubctrls:BindingProxy x:Key="Proxy" Data="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type mubctrls:AutoCompleteLookup}}}"/> 更改为 <mubctrls:BindingProxy x:Key="Proxy" Data="{Binding}"/>

您还必须从 Style 中取出资源并将其直接放入目标元素中,如下所示:

<Window.Resources>
        <Style TargetType="Grid">
            <Setter Property="Background" Value="AliceBlue"/>
        </Style>
    </Window.Resources>

    <Grid x:Name="MyGrid">
        <Grid.Resources>
            <local:BindingProxy x:Key="Proxy1" Data="{Binding}" />
        </Grid.Resources>

        <Button  Content="{Binding Data.Name, Source={StaticResource Proxy1}}" Margin="45,135,26,136"/>
    </Grid>

这一切都按预期正确执行。

这里的问题有两个:

  1. 如何访问嵌入在 Style 元素中的资源。这可以像这样完成:

     <Style x:Key="Style1">
            <Style.Resources>
                <SolidColorBrush x:Key="MyColor" Color="Aquamarine"/>
            </Style.Resources>
     </Style>
    

    ...

    <StackPanel Style="{StaticResource Style1}" x:Name="StkPnl">
            <Button Width="75" Height="25" Background="{Binding Style.Resources[MyColor], 
                           ElementName=StkPnl}"/>            
    </StackPanel>
    
  2. 以及现在如何将资源以样式绑定到 BindingProxy。例如,我想在资源字典 / window.resources 中这样做:

    <Style x:Key="MyStyle">
        <Style.Resources>
        <local:BindingProxy x:Key="Proxy" Data="{Binding}"/>
        <SolidColorBrush x:Key="Brush2" Color="{Binding Data.Color ,Source={StaticResource Proxy}}"/>
        </Style.Resources>
    </Style>
    

这样我就可以绑定一些内容了:<Button Content="{Binding Data.Name}" Height="25"/>

但我不能这样做,因为绑定在 Style 成为我们的 StackPanel 的一部分之前就已解决。而 BindingProxy 的 Data 属性 将为空,因为 Style 是在外部定义的。解决此问题的一种方法是将所有内容都置于您的主要数据显示控制之下。

如果你想把事情分开,解决方法:

<Window ...>    
    <Window.Resources>
    <!-- Employee placeholder to allow for declarative binding. It's properties will be filled in code -->
    <local:Employee x:Key="Emp"/>

    <!-- Binding proxy to Employee / Viewmodel -->
    <local:BindingProxy x:Key="Proxy" Data="{Binding (Window.Resources)[Emp], RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>

        <Style x:Key="MyStyle">
            <Style.Resources>
                <!-- Here Color property is bound using BindingProxy -->
                <SolidColorBrush x:Key="Brush2" Color="{Binding Data.Color ,Source={StaticResource Proxy}}"/>
            </Style.Resources>
        </Style>
    </Window.Resources>    

        <StackPanel x:Name="Pnl1" Style="{StaticResource MyStyle}">
            <Button Content="{Binding Data.Name, Source={StaticResource Proxy}}" Background="{Binding Style.Resources[Brush2], ElementName=Pnl1}" Height="25" Width="75"/>
        </StackPanel>
</Window>

MainWindow.xaml.cs

namespace ...
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {

            InitializeComponent();

            Employee emp = (Employee)this.Resources["Emp"];
            emp.Name = "Whosebug";
            emp.Address = "USA";
            emp.Color = "Orange";

            //Pnl1.DataContext = emp;

        }        
    }
    public class Employee
    {
        public String Name { get; set; }
        public String Address { get; set; }
        public String Color { get; set; }
    }
}