非共享 WPF 行为

Posted

技术标签:

【中文标题】非共享 WPF 行为【英文标题】:Nonshared WPF behavior 【发布时间】:2016-09-13 12:23:17 【问题描述】:

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

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

问题是,这种行为的实例在某种程度上对两个 DataGrid 来说都是常见的,所以如果你在第一个 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】:

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

【讨论】:

以上是关于非共享 WPF 行为的主要内容,如果未能解决你的问题,请参考以下文章

构建链接到其他非标准共享库的共享库

使 OpenJ9 类共享也共享非引导类

优胜美地文件共享非活动帐户[关闭]

c++ boost进程间交换(复制)非共享和共享字符串向量

加快非现有网络共享的 File.Exists

如何在片段转换中淡出非共享视图?