WPF:如何更改值并保持绑定
WPF: How to change value and keep binding
我正在寻找一种方法来突出 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-class的代码我留给你填写,我想每个人都在实现它)。您甚至可以摆脱它并在代码后面调用函数 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:
<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>
这是我的问题。当我启动这个程序并点击按钮 "Change text" 之前没有做任何其他事情时,文本被更改(如预期的那样)。
但是当我启动程序时,更改高亮文本(以及因此突出显示)并点击按钮 "Change text" 之后,没有任何反应。
经过大量搜索、调试和尝试后,我认为原因是,在我的附加行为中,我更改了 TextBlock
的 Inlines
集合,这打破了与Text
属性.
那么,如何在不破坏 Text
属性 的绑定的情况下更改 TextBlock
的 Inlines
集合(它本身不可绑定)?
或者我怎样才能通过其他方式实现我的目标?
感谢您的帮助。
由于更改了 Text
属性 的值,无论如何都没有重新突出显示,并且由于我无法解决上述问题,所以我创建了自己的附件 Text
属性 更改 Text
属性 的 TextBlock
并触发重新突出显示。如果我绑定到 属性 而不是 TextBlock
中提供的那个,现在一切正常。
我正在寻找一种方法来突出 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-class的代码我留给你填写,我想每个人都在实现它)。您甚至可以摆脱它并在代码后面调用函数 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:
<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>
这是我的问题。当我启动这个程序并点击按钮 "Change text" 之前没有做任何其他事情时,文本被更改(如预期的那样)。
但是当我启动程序时,更改高亮文本(以及因此突出显示)并点击按钮 "Change text" 之后,没有任何反应。
经过大量搜索、调试和尝试后,我认为原因是,在我的附加行为中,我更改了 TextBlock
的 Inlines
集合,这打破了与Text
属性.
那么,如何在不破坏 Text
属性 的绑定的情况下更改 TextBlock
的 Inlines
集合(它本身不可绑定)?
或者我怎样才能通过其他方式实现我的目标?
感谢您的帮助。
由于更改了 Text
属性 的值,无论如何都没有重新突出显示,并且由于我无法解决上述问题,所以我创建了自己的附件 Text
属性 更改 Text
属性 的 TextBlock
并触发重新突出显示。如果我绑定到 属性 而不是 TextBlock
中提供的那个,现在一切正常。