非共享WPF行为

时间:2016-09-13 12:23:17

标签: wpf vb.net xaml blend wpf-style

我在Window上有两个DataGrids,我使用Blend行为在列标题中创建过滤器。

<DataGrid>
  <i:Interaction.Behaviors>
    <v:ColumnBehavior/>
  </i:Interaction.Behaviors>
</DataGrid>
<DataGrid>
  <i:Interaction.Behaviors>
    <v:ColumnBehavior/>
  </i:Interaction.Behaviors>
</DataGrid>  

问题是,这种行为的实例在某种程度上对于两个DataGrids都是常见的,所以如果你在第一个DataGrid上设置过滤器,它会在第二个DataGrid中自动设置,反之亦然。我需要让这些过滤器(行为)独立。从我读到的内容来看,不可能实现风格。

行为类:

Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
Imports System.IO
Imports System.Text
Imports System.Windows.Controls.Primitives
Imports System.Windows.Interactivity
Imports System.Windows.Markup
Namespace View
  Friend Class ColumnBehavior
    Inherits Behavior(Of DataGrid)
    Protected Overrides Sub OnAttached()
      MyBase.OnAttached()
      AddHandler AssociatedObject.AutoGeneratingColumn, AddressOf OnAutoGeneratingColumn
    End Sub
    Protected Sub OnAutoGeneratingColumn(sender As Object, e As DataGridAutoGeneratingColumnEventArgs)
      If e.PropertyDescriptor IsNot Nothing Then
        Dim descriptor = DirectCast(e.PropertyDescriptor, PropertyDescriptor)
        Dim customString = DirectCast(descriptor.Attributes(GetType(CustomStringAttribute)), CustomStringAttribute)
        If customString IsNot Nothing Then
          Dim unitType = DirectCast([Enum].Parse(GetType(DataGridLengthUnitType), customString.Value), DataGridLengthUnitType)
          e.Column.Width = New DataGridLength(1, unitType)
        End If
        Dim display = DirectCast(descriptor.Attributes(GetType(DisplayAttribute)), DisplayAttribute)
        If display IsNot Nothing Then
          e.Cancel = (Not display.GetAutoGenerateField().GetValueOrDefault(True))
          e.Column.Header = display.GetShortName()
          Dim headerStyle = e.Column.HeaderStyle
          If headerStyle Is Nothing Then headerStyle = New Style(GetType(DataGridColumnHeader))
          headerStyle.Setters.Add(New Setter(ToolTipService.ToolTipProperty, display.GetDescription()))
          e.Column.HeaderStyle = headerStyle
          If display.GetAutoGenerateFilter().GetValueOrDefault(False) Then
            Dim comboBoxBinding = DirectCast(descriptor.Attributes(GetType(ComboBoxBindingAttribute)), ComboBoxBindingAttribute)
            If comboBoxBinding IsNot Nothing Then
              Dim bindingString = "{{Binding {0}, RelativeSource={{RelativeSource FindAncestor, AncestorType={{x:Type Window}}}}}}"
              Dim dataTemplateXaml = <DataTemplate>
                                       <Grid>
                                         <Grid.ColumnDefinitions>
                                           <ColumnDefinition Width="*"/>
                                           <ColumnDefinition Width="Auto"/>
                                         </Grid.ColumnDefinitions>
                                         <TextBlock
                                           Text="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                           Margin="0,0,4,0"
                                           VerticalAlignment="Center"
                                           Grid.Column="0"/>
                                         <ComboBox
                                           IsReadOnly="True"
                                           ItemsSource=<%= String.Format(bindingString, comboBoxBinding.ItemsSource) %>
                                           SelectedItem=<%= String.Format(bindingString, comboBoxBinding.SelectedItem) %>
                                           Grid.Column="1"
                                           SelectedIndex="0"/>
                                       </Grid>
                                     </DataTemplate>
              Dim headerTemplate As DataTemplate
              Using dataTemplateReader As New MemoryStream(Encoding.UTF8.GetBytes(dataTemplateXaml.ToString()))
                Dim context As New ParserContext
                context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation")
                context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml")
                headerTemplate = DirectCast(XamlReader.Load(dataTemplateReader, context), DataTemplate)
              End Using
              e.Column.HeaderTemplate = headerTemplate
            End If
          End If
        End If
        Dim displayFormat = DirectCast(descriptor.Attributes(GetType(DisplayFormatAttribute)), DisplayFormatAttribute)
        If displayFormat IsNot Nothing Then
          DirectCast(e.Column, DataGridBoundColumn).Binding.StringFormat = displayFormat.DataFormatString
        End If
      End If
    End Sub
    Protected Overrides Sub OnDetaching()
      MyBase.OnDetaching()
      RemoveHandler AssociatedObject.AutoGeneratingColumn, AddressOf OnAutoGeneratingColumn
    End Sub
  End Class
End Namespace  

您可以使用模型中的属性自动创建DataGrid中的过滤器:

<Display(ShortName:="Meeting", Description:="Meeting code", AutoGenerateField:=True, AutoGenerateFilter:=True)>
    <ComboBoxBinding("DataContext.MeetingCodes", "DataContext.TasksMeetingCodeFilter")>
    <CustomString("SizeToCells")>
    Public Property TaskMeetingCode As String Implements ITaskView.TaskMeetingCode

1 个答案:

答案 0 :(得分:0)

问题解决了。行为类有两个实例,应该是这样,但是两个实例都绑定到viewmodel中的同一个属性...