转换器从DataGrid获取值而不是绑定对象?

时间:2013-09-25 15:53:39

标签: c# wpf data-binding imultivalueconverter 2-way-object-databinding

我正在利用绑定到数据对象的DataGridTextColumn来显示应用程序中的各种度量。我正在尝试实现一个允许测量以不同单位显示的功能,并认为绑定中的转换器可能是我的最佳选择。

这适用于大多数应用程序,但我在DataGrid中有另一个字段,用户可以在其中编辑字段的值。在这种情况下,我有一个双向数据绑定,将来自用户的输入值(让我们说在华氏度)转换回数据对象的默认单位(摄氏度)。

我希望Converter从数据对象中检索Celcius中的值,进行转换,然后将此值(以华氏度)发送到DataGridTextColumn。但是,在数据对象上设置值并通知PropertyChanged后,不会调用该属性的“get”方法。相反,转换似乎是从DataGridTextColumn获取用户输入的值(华氏温度)。

这是正常的行为,如果是这样,有没有办法强制转换为总是返回数据对象的值?

一些要提供帮助的摘要:

<Window.Resources>
    <myProject:ConvertMetricValuesToEnglish x:Key="ValueMToE" />
</Window.Resources>
.
.
.
<DataGridTextColumn x:Name="maxCol" Header="Maximum" Width="100">
    <DataGridTextColumn.Binding>
        <MultiBinding Mode="TwoWay" StringFormat='0.#####' Converter="{StaticResource ValueMToE}" >
            <Binding Path="UserMax" Mode="TwoWay" />
            <Binding Path="Unit" Mode="OneWay" />
        </MultiBinding>
    </DataGridTextColumn.Binding>
</DataGridTextColumn>

转换器方法:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
    if (values.Length != 2)
    {
        return null;
    }
    if (values[0].GetType() != typeof(double) || values[1].GetType() != typeof(string))
    {
        return values[0];
    }
    double d = (double)values[0];
    string s = (string)values[1];

    return ConvertValueToEnglish(d, s);
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
    return new object[] { StringToDouble((string)value), Binding.DoNothing };
}

我在setter中进行'ConvertBack'转换,因为ConvertBack中的信息有限:

    private double? _userMax;
    public double UserMax
    {
        get
        {
            if (_userMax == null)
            {
                _userMax = Max;
            }

            return (double)_userMax;
        }
        set
        {
            if (Metric)
            {
                if (value == _userMax)
                {
                    return;
                }
                _userMax = value;
            }
            else
            {
                double num = ConvertValueToMetric(value, _unit);
                if (num == _userMax)
                {
                    return;
                }
                _userMax = num;
            }
            OnPropertyChanged("UserMax");
        }
    }

编辑:以下是演示此问题的示例项目的链接。左列是用户可编辑的,表示用户看到/编辑的数据。右列显示用户进行更改时实际存储的基础值(此值不应更改)。

如果修改左栏中的值,并选择“标签”或在同一行中选择其他列,则可以看到输入值的值。但是当它失去焦点时它会改变。通过设置断点,您可以看到当单元格本身失去焦点时,使用DependencyProperty.UnsetValue调用Convert方法,然后使用Unit的get方法调用,然后使用DataGrid中的值再次使用Convert方法。

TempConverter.zip

1 个答案:

答案 0 :(得分:2)

我能够自己解决问题。问题是在DataGrid中的整行失去焦点之前,源数据对象没有被更新。为了解决这个问题,我将一个TextBox作为ControlTemplate应用于单元格,并设置一个事件,以便在TextBox失去焦点时触发UpdateSource。

XAML:

<DataGridTextColumn x:Name="maxCol" Header="Maximum" Width="100">
    <DataGridTextColumn.CellStyle>
        <Style TargetType="DataGridCell">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <TextBox LostFocus="TextBlock_LostFocus">
                            <TextBox.Text>
                                <MultiBinding StringFormat='0.#####' Converter="{StaticResource ValueMToE}" UpdateSourceTrigger="Explicit">
                                    <Binding Path="UserMax" Mode="TwoWay" />
                                    <Binding Path="Unit" Mode="OneWay" />
                                </MultiBinding>
                            </TextBox.Text>
                        </TextBox>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

事件处理程序:

private void TextBlock_LostFocus(object sender, RoutedEventArgs e)
{
    TextBox b = sender as TextBox;
    if (b == null)
    {
        return;
    }
    MultiBindingExpression mb = BindingOperations.GetMultiBindingExpression(b, TextBox.TextProperty);
    mb.UpdateSource();
}