【问题标题】:WPF: How to change value and keep bindingWPF:如何更改值并保持绑定
【发布时间】:2017-09-25 05:55:48
【问题描述】:

我正在寻找一种方法来突出显示 TextBlock 内容的某些部分。

由于我发现的大多数解决方案都建议编写自己的控件,该控件继承自 TextBlock,并且由于我不喜欢为每一点额外功能编写自己的控件,因此我尝试将这种功能性放在附加的行为,我成功了(所以我想)。

这是我的行为代码:

Public NotInheritable Class TextBlockHighlighting

    Private Sub New()
    End Sub

#Region " HighlightTextProperty "

    Public Shared HighlightTextProperty As DependencyProperty = DependencyProperty.RegisterAttached("HighlightText", GetType(String), GetType(TextBlockHighlighting), New FrameworkPropertyMetadata(Nothing, New PropertyChangedCallback(AddressOf TextBlockHighlighting.OnHighlightTextPropertyChanged)))

    <AttachedPropertyBrowsableForType(GetType(TextBlock))>
    Public Shared Function GetHighlightText(ByVal obj As TextBlock) As String
        Return obj.GetValue(TextBlockHighlighting.HighlightTextProperty)
    End Function

    <AttachedPropertyBrowsableForType(GetType(TextBlock))>
    Public Shared Sub SetHighlightText(ByVal obj As TextBlock, ByVal value As String)
        obj.SetValue(TextBlockHighlighting.HighlightTextProperty, value)
    End Sub

    Private Shared Sub OnHighlightTextPropertyChanged(ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs)
        Dim tb As TextBlock

        tb = TryCast(sender, TextBlock)

        If (tb Is Nothing) Then
            Throw New InvalidOperationException("Error")
        End If

        Call TextBlockHighlighting.Refresh(tb)
    End Sub

#End Region

#Region " HighlightStyleProperty "

    Public Shared HighlightStyleProperty As DependencyProperty = DependencyProperty.RegisterAttached("HighlightStyle", GetType(Style), GetType(TextBlockHighlighting), New FrameworkPropertyMetadata(Nothing, New PropertyChangedCallback(AddressOf TextBlockHighlighting.OnHighlightStylePropertyChanged)))

    <AttachedPropertyBrowsableForType(GetType(TextBlock))>
    Public Shared Function GetHighlightStyle(ByVal obj As TextBlock) As Style
        Return obj.GetValue(TextBlockHighlighting.HighlightStyleProperty)
    End Function

    <AttachedPropertyBrowsableForType(GetType(TextBlock))>
    Public Shared Sub SetHighlightStyle(ByVal obj As TextBlock, ByVal value As Style)
        obj.SetValue(TextBlockHighlighting.HighlightStyleProperty, value)
    End Sub

    Private Shared Sub OnHighlightStylePropertyChanged(ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs)
        Dim tb As TextBlock

        tb = TryCast(sender, TextBlock)

        If (tb Is Nothing) Then
            Throw New InvalidOperationException("Error")
        End If

        Call TextBlockHighlighting.Refresh(tb)
    End Sub

#End Region

    Private Shared Sub Refresh(ByVal sender As TextBlock)
        Dim highlight As String
        Dim style As Style
        Dim oldValue As String

        oldValue = sender.Text

        If String.IsNullOrEmpty(sender.Text) Then
            Exit Sub
        End If

        sender.Inlines.Clear()
        highlight = TextBlockHighlighting.GetHighlightText(sender)
        style = TextBlockHighlighting.GetHighlightStyle(sender)

        If (style Is Nothing) Then
            style = New Style(GetType(Run))
            style.Setters.Add(New Setter(Run.BackgroundProperty, Brushes.Green))
            style.Setters.Add(New Setter(Run.ForegroundProperty, Brushes.White))
        End If

        If String.IsNullOrEmpty(highlight) OrElse (oldValue.IndexOf(highlight, StringComparison.InvariantCultureIgnoreCase) < 0) Then
            sender.Text = oldValue
        Else
            Dim index As Integer = oldValue.IndexOf(highlight, StringComparison.InvariantCultureIgnoreCase)
            Dim pos As Integer = 0

            Do While (index >= 0)
                Dim t As String

                t = oldValue.Substring(pos, index - pos)
                sender.Inlines.Add(t)
                pos = index

                t = oldValue.Substring(pos, highlight.Length)
                sender.Inlines.Add(New Run(t) With {.Style = style})
                pos += highlight.Length
                index = oldValue.IndexOf(highlight, pos, StringComparison.InvariantCultureIgnoreCase)
            Loop

            sender.Inlines.Add(New Run(oldValue.Substring(pos)))
        End If
    End Sub

End Class

这是我的视图模型代码(我将 RelayCommand 类的代码留给你填写,我想每个人都有它的实现)。您甚至可以摆脱它并在后面的代码中调用函数ChangeText

Imports System.ComponentModel

Public Class MainViewModel
    Implements INotifyPropertyChanged

    Private _highlightText As String
    Private _text As String
    Private _changeTextCommand As ICommand = New RelayCommand(AddressOf Me.ChangeText)

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Public Sub New()
        Me.HighlightText = "lo"
        _text = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
    End Sub

    Private Sub OnPropertyChanged(propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    Public Property HighlightText As String
        Get
            Return _highlightText
        End Get
        Set(value As String)
            _highlightText = value
            Me.OnPropertyChanged("HighlightText")
        End Set
    End Property

    Public ReadOnly Property Text As String
        Get
            Return _text
        End Get
    End Property

    Public ReadOnly Property ChangeTextCommand As ICommand
        Get
            Return _changeTextCommand
        End Get
    End Property

    Private Sub ChangeText()
        _text = "This is another text containing the default highlight text ""lo""."
        Me.OnPropertyChanged("Text")
    End Sub

End Class

最后,这是我的主窗口 Xaml:

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>

    <Window.Resources>
        <Style x:Key="HightlightStyle" TargetType="Run">
            <Setter Property="Background" Value="LightGreen" />
            <Setter Property="Foreground" Value="Yellow" />
        </Style>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="Hightlight text:" />
        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding HighlightText, UpdateSourceTrigger=PropertyChanged}" />

        <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Text}" TextWrapping="Wrap"
                   local:TextBlockHighlighting.HighlightText="{Binding HighlightText}"
                   local:TextBlockHighlighting.HighlightStyle="{StaticResource HightlightStyle}" />

        <Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Content="Change text" Margin="100,5" Command="{Binding ChangeTextCommand}" />
    </Grid>
</Window>

这是我的问题。当我启动这个程序并点击“更改文本”按钮之前没有做任何其他事情时,文本会被更改(如预期的那样)。

但是当我启动程序时,更改高亮文本(以及因此突出显示)并在此之后点击“更改文本”按钮,没有任何反应。

经过大量搜索、调试和尝试,我认为原因是,在我的附加行为中,我更改了TextBlockInlines 集合,这破坏了与Text 属性的绑定。

那么,如何在不破坏与Text 属性的绑定的情况下更改TextBlockInlines 集合(它本身不可绑定)? 或者我怎样才能通过其他方式实现我的目标?

感谢您的帮助。

【问题讨论】:

  • 在 C# 中,我们正在做类似的事情:myTextbox.SetCurrentValue(TextProperty, anyValueHere),这不应该破坏绑定。
  • 另外,您可以添加带有绑定切换的文本框样式,例如:
  • 还有一个:您可以保存 Binding,然后再次分配它,就像在 C# 中一样:BindingExpression bindingExpression = myTextbox.GetBindingExpression(TextBox.TextProperty);Binding parentBinding = bindingExpression.ParentBinding; .. 一些代码要更改为突出显示,然后:myTextbox.SetBinding(TextBox.TextProperty, parentBinding);
  • 使用SetCurrentValue 我将设置TextBlockText 属性,但我需要使用Inlines 属性才能仅突出显示@987654341 的部分文本@。您的样式建议我不能使用,因为我只想突出显示TextBlock 的部分文本,而不是所有文本。在我更改值后重新设置绑定会强制绑定执行,这会删除我刚刚所做的所有突出显示。
  • 您能给我们提供您想要达到的目标的样本吗?也许这将有助于内联可以保存 的集合,其中 Text 属性是可绑定的。

标签: wpf vb.net data-binding attachedbehaviors


【解决方案1】:

由于更改 Text 属性的值并没有重新突出显示,并且由于我无法摆脱提到的问题,我创建了自己的附加 Text 属性来更改 Text 属性TextBlock 并触发重新突出显示。如果我绑定到该属性而不是 TextBlock 中提供的属性,现在一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-17
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多