我正在学习wpf并且我正在尝试根据我的RichTextBox中的字符数来更改标签值我以为我可以在我的richTextBox_TextChanged()
方法中执行此操作,其中当前逻辑将删除所有输入的文字传递140个字符。
private void richTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextRange range = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
var text = range.Text.Trim();
label.Content = text.Length;
if (text.Length > 140)
{
int split = 0;
while (richTextBox.CaretPosition.DeleteTextInRun(-1) == 0)
{
richTextBox.CaretPosition.GetPositionAtOffset(--split);
}
}
}
由于这一行label.Content = text.Length;
,我在运行时崩溃了,我在这里使用这一行来查看我是否可以在开始时获得一个零长度,看它是否可以正常工作。错误是:“ApplicationName.exe中发生了'System.NullReferenceException'类型的异常,但未在用户代码中处理”。
仅允许140个字符的逻辑工作正常,名称'label'也是我的标签UI元素的名称。
我需要做什么才能将标签的值更改为text
字段的长度,并在用户输入时更改它。
答案 0 :(得分:0)
如果没有好Minimal, Complete, and Verifiable code example,就不可能确定问题是什么。您可以在此处找到有关如何调试,诊断和修复NullReferenceException
的许多有用建议:What is a NullReferenceException, and how do I fix it?
也就是说,我认为这个问题可能是由TextChanged
字段初始化之前提出的label
事件引起的,可能是InitializeComponent()
的一部分方法执行。只是事情的顺序错误。
您可以在尝试使用label
之前检查null
字段,从而解决问题。但是a)这增加了代码的复杂性,并且b)可能会使您的Label
控件保持未初始化状态,直到您明确设置它,或者文本稍后更改。
RichTextBox
如何维护其内容,特别是因为没有方便,简单string
- 只能跟踪的属性,您可能仍然需要代码-behind处理TextChanged
事件。但在这种情况下,您仍然可以访问正确的视图模型并让它完成工作。
这样做,WPF将确保它不会尝试取消引用null
值,并且如果Label
控件最终被初始化,那么它就是&#39}正确初始化为您期望的值。
这里是一个简单的视图模型,它具有用于此目的的单个属性,并且包含对于任何视图模型类都是典型的样板逻辑(您可以在Stack Overflow上找到这些示例...我' m为了方便和与本文其余部分的一致性,这里提供这个):
class ViewModel : INotifyPropertyChanged
{
private int _textLength;
public int TextLength
{
get { return _textLength; }
set { _UpdateField(ref _textLength, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void _UpdateField<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, newValue))
{
field = newValue;
_OnPropertyChanged(propertyName);
}
}
private void _OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
switch (propertyName)
{
// you can add "case nameof(...):" cases here to handle
// specific property changes, rather than polluting the
// property setters themselves
}
}
}
使用类似的视图模型,然后您可以编写XAML:
<Window x:Class="TestSO42984032TextLengthLabel.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:l="clr-namespace:TestSO42984032TextLengthLabel"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:ViewModel/>
</Window.DataContext>
<StackPanel>
<RichTextBox TextChanged="RichTextBox_TextChanged"/>
<Label Content="{Binding TextLength}"/>
</StackPanel>
</Window>
当然,您需要代码隐藏:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void RichTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
ViewModel model = (ViewModel)DataContext;
RichTextBox richTextBox = (RichTextBox)sender;
TextRange range = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
var text = range.Text.Trim();
model.TextLength = text.Length;
if (text.Length > 140)
{
int split = 0;
while (richTextBox.CaretPosition.DeleteTextInRun(-1) == 0)
{
richTextBox.CaretPosition.GetPositionAtOffset(--split);
}
}
}
}
现在,只要文本发生更改,您的事件处理程序就会被调用,并且作为其工作的一部分,它将使用正确的值更新视图模型属性。此时肯定会设置DataContext
,因此您可以安全地使用它,而无需考虑null
引用。
如果由于某种原因获得纯文本信息也很有用,您可以扩展您的视图模型以包含:
class ViewModel : INotifyPropertyChanged
{
private string _text;
private int _textLength;
public string Text
{
get { return _text; }
set { _UpdateField(ref _text, value); }
}
public int TextLength
{
get { return _textLength; }
set { _UpdateField(ref _textLength, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void _UpdateField<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, newValue))
{
field = newValue;
_OnPropertyChanged(propertyName);
}
}
private void _OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
switch (propertyName)
{
case nameof(Text):
TextLength = Text.Length;
break;
}
}
}
请注意,我在这里使用switch
语句来更新TextLength
属性。您的代码隐藏将会是这样的:
private void RichTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
ViewModel model = (ViewModel)DataContext;
RichTextBox richTextBox = (RichTextBox)sender;
TextRange range = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
var text = range.Text.Trim();
model.Text = text;
if (text.Length > 140)
{
int split = 0;
while (richTextBox.CaretPosition.DeleteTextInRun(-1) == 0)
{
richTextBox.CaretPosition.GetPositionAtOffset(--split);
}
}
}
最后,请注意绑定可以使用属性路径,而不仅仅是简单的属性名称。因此,如果您愿意,可以完全省略TextLength
属性:
class ViewModel : INotifyPropertyChanged
{
private string _text = string.Empty;
public string Text
{
get { return _text; }
set { _UpdateField(ref _text, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void _UpdateField<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, newValue))
{
field = newValue;
_OnPropertyChanged(propertyName);
}
}
private void _OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
switch (propertyName)
{
// empty
}
}
}
并将XAML更改为:
<Window x:Class="TestSO42984032TextLengthLabel.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:l="clr-namespace:TestSO42984032TextLengthLabel"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:ViewModel/>
</Window.DataContext>
<StackPanel>
<RichTextBox TextChanged="RichTextBox_TextChanged"/>
<Label Content="{Binding Text.Length}"/>
</StackPanel>
</Window>
请注意,在这种情况下,您需要初始化视图模型字段,以确保它具有实际的非null
字符串值。如果没有这个更改,程序将会运行,但您的Label
最初将没有设置值。
希望有所帮助。正如您所看到的,即使在视图模型范例中,也有很多变化,具体取决于程序其余部分的重要性。但这应该让你指出正确的方向。