如何使用双向数据绑定而不是一对一转换?



我有一个文本框,可以显示数据模型中的字段。字段的类型是字符串列表。

我添加了包含数据类和实现INotifyPropertyChangedIDataErrorInfo接口的视图模型类。视图模型包含string属性PropName,我将TextBox.Text绑定到双向PropNamePropName二传手和getter将字符串转换为List<string>并返回。它们使用空格作为分隔符将字符串拆分为多个部分。此外,我有验证来检查字符串,我希望它在文本更改后立即工作,所以我使用UpdateSourceTrigger="PropertyChanged"立即进行验证。它是如何工作的?

考虑一个例子。我的期望是用户键入一个单词,然后再次输入分隔符,然后再次键入一个单词,然后将其转换为List<string>。在用户添加分隔符后,有人立即执行将值存储到源并发生转换并将最后一个分隔符修剪为无用。之后,有人再次读取属性(我试图不调用INotifyPropertyChanged.PropertyChanged但没有成功(,最后一个分隔符消失了。如果用户在中间的单词中插入分隔符,一切正常。

<TextBox>
<TextBox.Text>
<Binding Path="PropName" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<DataErrorValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

class DataModel
{
public List<string> PropName{get;set;}
};
class ViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private DataModel data;
public string PropName
{
get { return data.PropName.Join(' '); }
set
{ 
data.PropName = value.Split(' ', StringSplitOptions.RemoveEmptyEntries);
RaisePropertyChanged();// I can don't call it. It doesn't affect.
}
}
};

首先,您不应实现视图模型来查看视图模型内的转化。
对于此方案,您应该设置一个IValueConverter(请参阅Microsoft文档:数据转换(。

要解决您的问题,您有两个选择:使用TextBox的默认Binding.UpdateSourceTrigger,即UpdateSourceTrigger.LostFocus或禁止绑定更新,以防TextBox.Text值以特定分隔符结尾。

我建议切换回UpdateSourceTrigger.LostFocus值。验证每个字符的输入是没有意义的。UpdateSourceTrigger.LostFocus在拼写检查或键入建议等方案中非常有意义。

下面的示例演示如何使用正确的值转换并禁止绑定:

视图模型.cs

class ViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private DataModel Data { get; set; }
private List<string> propName;
public List<string> PropName
{
get => this.Data;
set
{ 
this.Data.PropName = value;
RaisePropertyChanged();
}
}
}

ListToStringConverter.cs

[ValueConversion(typeof(List<string>), typeof(string))]
public class ListToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value is IEnumerable<string> stringCollection 
? string.Join(";", stringCollection)
: Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string[] stringSeparators = new string[] {";", " "};
return value is string stringValue && stringValue.LastIndexOfAny(stringSeparators) < stringValue.Length - 1 
? stringValue.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries).ToList() 
: Binding.DoNothing;
}
}

MainWindow.xaml

<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<TextBox>
<TextBox.Text>
<Binding Path="PropName" UpdateSourceTrigger="PropertyChanged">
<Binding.Converter>
<ListToStringConverter />
</Binding.Converter>
<Binding.ValidationRules>
<DataErrorValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</Window>

最新更新