Wpf 将OneWayToSource与目标的一次性初始化绑定
我有一个Wpf 将OneWayToSource与目标的一次性初始化绑定,wpf,data-binding,Wpf,Data Binding,我有一个DataGrid,其中可编辑的单元格绑定到各个项目的视图模型中各自的值 最初,数据被加载并显示给用户,然后用户可以在网格中编辑数据 绑定工作正常(在我的例子中是UpdateSourceTrigger=OnPropertyChanged),但是由于double(视图模型)和string(UI)之间的转换,双向绑定会导致恼人的UI错误,比如当用户键入时,使小数点分隔符或小数点后的零消失 两个错误的解决方案是: <TextBox Style="{StaticResource E
DataGrid
,其中可编辑的单元格绑定到各个项目的视图模型中各自的值
最初,数据被加载并显示给用户,然后用户可以在网格中编辑数据
绑定工作正常(在我的例子中是UpdateSourceTrigger=OnPropertyChanged
),但是由于double
(视图模型)和string
(UI)之间的转换,双向绑定会导致恼人的UI错误,比如当用户键入时,使小数点分隔符或小数点后的零消失
两个错误的解决方案是:
<TextBox Style="{StaticResource ErrorStyle}">
<TextBox.Text>
<MultiBinding UpdateSourceTrigger="PropertyChanged"
Mode="TwoWay"
Converter="{StaticResource DoubleUserStringConverter}">
<Binding Path="TheProperty" ValidatesOnDataErrors="True"/>
<Binding Path="ThePropertyUserString"/>
/MultiBinding>
</TextBox.Text>
</TextBox>
/// <summary>
/// multibinding, first binding is double? and second is string, both representing the same value
/// the double? value is for the viewmodel to use as normally intended
/// the string value is for the user not to have ui bugs
/// </summary>
class DoubleUserStringConverter : IMultiValueConverter
{
private OriginalConverterYouWanted converter;
public DoubleUserStringConverter()
{
converter = new OriginalConverterYouWanted(); //single binding, not multi
//for types "double" in the view model and "string" in the UI
//in case of invalid strings, the double value sent to UI is null
}
//from view model to UI:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[1] == null) //null string means UI initialization, use double
return converter.Convert(values[0], targetType, parameter, culture);
else
return values[1]; //in the rest of the time, send user string to UI
}
//from UI to view model
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
return new object[] {
converter.ConvertBack(value, targetTypes[0], parameter, culture), //can be null
value //string is always sent as is, no changes to what the user types
};
}
}
- 在视图模型中将属性设置为
,并在视图模型内进行必要的转换。字符串
- 问题:给我带来了一个奇怪的问题,即UI和视图模型之间的区域性不兼容(我不希望视图模型知道UI的区域性)
- 使用
绑定。当VM停止发回解析和重新转换的值时,这消除了所有UI错误。OneWayToSource
- 问题:我无法(或不知道如何)使用加载的数据初始化网格中的值
OneTime
绑定”之后使用一个OneWayToSource
绑定,或者以某种方式将两者相加吗
我尝试将
FallbackValue
和TargetNullValue
绑定到源值,但它们不接受绑定。小数点消失是它们在尝试修复其他内容时引入的“功能”。我以为是.NET4.0引入了它,人们开始注意到这是一个突破性的变化,但文档似乎暗示了.NET4.5
这通常是因为您设置了updatesourcetrigger=propertychanged
简单的解决方法通常是将其移除
因为
, UpdateSourceTrigger=LostFocus
是文本框文本绑定的默认行为
或者,您可以尝试使用KeepTextBoxDisplaySynchronizedWithTextProperty
您可以在显示任何内容之前在Mainwindow中进行设置。我发现了一个黑客解决方案,它涉及使用两个属性,原始属性和一个专用于用户的字符串以实现平滑行为。为此,请使用特定的转换器。(我想我会将此作为未来案例的模式) 这适用于视图模型不更改属性,只有用户更改属性的情况。(如果您想要视图模型也更改属性的真正双向交互,则需要在需要更改属性时将string属性设置为null) 在视图模型中:
<TextBox Style="{StaticResource ErrorStyle}">
<TextBox.Text>
<MultiBinding UpdateSourceTrigger="PropertyChanged"
Mode="TwoWay"
Converter="{StaticResource DoubleUserStringConverter}">
<Binding Path="TheProperty" ValidatesOnDataErrors="True"/>
<Binding Path="ThePropertyUserString"/>
/MultiBinding>
</TextBox.Text>
</TextBox>
/// <summary>
/// multibinding, first binding is double? and second is string, both representing the same value
/// the double? value is for the viewmodel to use as normally intended
/// the string value is for the user not to have ui bugs
/// </summary>
class DoubleUserStringConverter : IMultiValueConverter
{
private OriginalConverterYouWanted converter;
public DoubleUserStringConverter()
{
converter = new OriginalConverterYouWanted(); //single binding, not multi
//for types "double" in the view model and "string" in the UI
//in case of invalid strings, the double value sent to UI is null
}
//from view model to UI:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[1] == null) //null string means UI initialization, use double
return converter.Convert(values[0], targetType, parameter, culture);
else
return values[1]; //in the rest of the time, send user string to UI
}
//from UI to view model
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
return new object[] {
converter.ConvertBack(value, targetTypes[0], parameter, culture), //can be null
value //string is always sent as is, no changes to what the user types
};
}
}
与标准代码的区别在于:
- 添加不带逻辑的字符串属性
- 在原始属性更改时为此属性添加通知
<TextBox Style="{StaticResource ErrorStyle}">
<TextBox.Text>
<MultiBinding UpdateSourceTrigger="PropertyChanged"
Mode="TwoWay"
Converter="{StaticResource DoubleUserStringConverter}">
<Binding Path="TheProperty" ValidatesOnDataErrors="True"/>
<Binding Path="ThePropertyUserString"/>
/MultiBinding>
</TextBox.Text>
</TextBox>
/// <summary>
/// multibinding, first binding is double? and second is string, both representing the same value
/// the double? value is for the viewmodel to use as normally intended
/// the string value is for the user not to have ui bugs
/// </summary>
class DoubleUserStringConverter : IMultiValueConverter
{
private OriginalConverterYouWanted converter;
public DoubleUserStringConverter()
{
converter = new OriginalConverterYouWanted(); //single binding, not multi
//for types "double" in the view model and "string" in the UI
//in case of invalid strings, the double value sent to UI is null
}
//from view model to UI:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[1] == null) //null string means UI initialization, use double
return converter.Convert(values[0], targetType, parameter, culture);
else
return values[1]; //in the rest of the time, send user string to UI
}
//from UI to view model
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
return new object[] {
converter.ConvertBack(value, targetTypes[0], parameter, culture), //can be null
value //string is always sent as is, no changes to what the user types
};
}
}
/多重绑定>
转换器:
<TextBox Style="{StaticResource ErrorStyle}">
<TextBox.Text>
<MultiBinding UpdateSourceTrigger="PropertyChanged"
Mode="TwoWay"
Converter="{StaticResource DoubleUserStringConverter}">
<Binding Path="TheProperty" ValidatesOnDataErrors="True"/>
<Binding Path="ThePropertyUserString"/>
/MultiBinding>
</TextBox.Text>
</TextBox>
/// <summary>
/// multibinding, first binding is double? and second is string, both representing the same value
/// the double? value is for the viewmodel to use as normally intended
/// the string value is for the user not to have ui bugs
/// </summary>
class DoubleUserStringConverter : IMultiValueConverter
{
private OriginalConverterYouWanted converter;
public DoubleUserStringConverter()
{
converter = new OriginalConverterYouWanted(); //single binding, not multi
//for types "double" in the view model and "string" in the UI
//in case of invalid strings, the double value sent to UI is null
}
//from view model to UI:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[1] == null) //null string means UI initialization, use double
return converter.Convert(values[0], targetType, parameter, culture);
else
return values[1]; //in the rest of the time, send user string to UI
}
//from UI to view model
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
return new object[] {
converter.ConvertBack(value, targetTypes[0], parameter, culture), //can be null
value //string is always sent as is, no changes to what the user types
};
}
}
//
///多重绑定,第一个绑定是双绑定?第二个是字符串,两者都表示相同的值
///替身?值是供viewmodel正常使用的
///字符串值用于用户不存在ui错误
///
类DoubleUserStringConverter:IMultiValueConverter
{
私有原始转换器您想要的转换器;
公共DoubleUserStringConverter()
{
converter=new originalconverteryouwant();//单绑定,而不是多绑定
//对于视图模型中的“double”和UI中的“string”类型
//如果字符串无效,则发送到UI的双精度值为null
}
//从视图模型到用户界面:
公共对象转换(对象[]值,类型targetType,对象参数,CultureInfo区域性)
{
如果(values[1]==null)//null字符串表示UI初始化,则使用double
返回converter.Convert(值[0],目标类型,参数,区域性);
其他的
返回值[1];//在剩余时间内,将用户字符串发送到UI
}
//从UI到视图模型
公共对象[]转换回(对象值,类型[]targetTypes,
对象参数,CultureInfo(区域性)
{
返回新对象[]{
converter.ConvertBack(值,targetTypes[0],参数,区域性),//可以为null
值//字符串始终按原样发送,不更改用户键入的内容
};
}
}
设置UpdateSourceTrigger=LostFocus或Explicit部分解决了这个问题。“双向绑定会导致恼人的UI错误,比如用户键入时小数点分隔符消失”-你的确切意思是什么?它应该是固定的,因为双向绑定是一种方式。我处理了这个问题,发现这种情况的发生不是由于属性改变。即使事件没有发生(因为值没有改变),绑定仍然会丢弃最后一个点和点后的零。这很可能是由于PropertyDescriptor的内部实现——绑定通过它工作。如果你说俄语,我最近在这里解释了他们的工作,与设置一个属性相比,这似乎是一个很大的工作。是的,但这是一个完整的解决方案,所有其他的都有恼人的UI错误。考虑到您通常已经有了一个转换器和一个get/set/notify逻辑,它实际上并不多。我尝试了您的解决方案,LostFocus
一个是最好的,但不幸的是,如果用户带着无效字符串离开,它仍然会删除整个文本。如果网格只有一行,单击该行外部不会更改焦点,则必须单击某些特定位置。-对于兼容性解决方案,每当验证失败时,它也会删除整个文本。