首页 > 解决方案 > 转换器未通过两种方式绑定到文本属性的自定义用户控件内的文本框取消焦点转换回

问题描述

我正在创建一个自定义 UWP 用户控件。我有两种方法将 TextBox 中的文本与 IValueConverter 绑定,以将字符串转换为十进制并返回。从后面加载数据时,我的转换器正在将十进制转换为文本框中的字符串。但是,当文本框在我的自定义控件中失去焦点时,我无法触发转换器的 ConvertBack 方法,就像常规文本框控件的通常行为一样。

有没有办法注意到 TextBox unfocus 并通过它的依赖属性触发转换回我的用户控件内的小数回到我的模型数据?

这是我的用户控件。

<UserControl
    <Grid Margin="15,0,15,0">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5*"/>
            <ColumnDefinition Width="5*"/>
        </Grid.ColumnDefinitions>
        <TextBox
            x:Name="textBox"
            Grid.Row="0"
            Grid.Column="0"
            Grid.ColumnSpan="2"
            Header="{x:Bind Header}"
            Text="{x:Bind Text}"
            IsEnabled="{x:Bind IsControlEnabled}"/>

        <TextBlock
            Grid.Row="1" 
            Grid.Column="0" 
            Foreground="RosyBrown"
            Text="{x:Bind InspectionValidation}"/>
    </Grid>
</UserControl>

这是它的代码隐藏

public sealed partial class FrmTextBox : UserControl, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public static readonly DependencyProperty HeaderProperty =
        DependencyProperty.Register("Header", typeof(string),
            typeof(FrmComboBox), new PropertyMetadata(null));

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string),
            typeof(FrmComboBox), new PropertyMetadata(null));

    public static readonly DependencyProperty
        InspectionValidationProperty =
            DependencyProperty.Register("InspectionValidation", typeof(string)
                , typeof(FrmInspection), null);

    public static readonly DependencyProperty
        IsLayoutEnabledProperty =
            DependencyProperty.Register("IsLayoutEnabled", typeof(int?)
                , typeof(FrmInspection), null);


    public string Header
    {
        get { return (string)GetValue(HeaderProperty); }
        set { SetValue(HeaderProperty, value); }
    }

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set
        {
            SetValue(TextProperty, value);
        }
    }

    public string InspectionValidation
    {
        get => (string) GetValue(InspectionValidationProperty);
        set =>SetValue( InspectionValidationProperty, value);
    }

    public int? IsLayoutEnabled
    {
        get => (int?) GetValue(IsLayoutEnabledProperty);
        set
        {
            IsControlEnabled = (value == -1) ? true : false;
            SetValue( IsLayoutEnabledProperty, value);
        }
    }
    private bool isControlEnabled { get; set; }
    public bool IsControlEnabled
    {
        get => isControlEnabled;
        set
        {
            if (value == isControlEnabled) return;
            isControlEnabled = value;
            OnPropertyChanged();

        }
    }

    public FrmTextBox()
    {
        this.InitializeComponent();
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

这是我的 IValueConverter

public class StringToDecimalConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value != null)
            return value.ToString();

        return string.Empty;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        try
        {
            if (value != null)
            {
                Decimal newValue;
                Decimal.TryParse((string) value, out newValue);
                return newValue;
            }
            return null;
        }
        catch
        {
            return null;
        }
    }
}


这是我的用户控件的 Xaml 实现。

<controls:FrmTextBox
   Grid.Row="1"
   Grid.Column="1"
   Header="Labor Count"
   Text="{x:Bind ViewModel.Current.LaborCount, Mode=TwoWay, Converter={StaticResource StringToDecimal}}"
   InspectionValidation=""
   IsLayoutEnabled="-1">
</controls:FrmTextBox>

标签: c#data-bindinguwp

解决方案


有没有办法注意到 TextBox unfocus 并通过它的依赖属性触发转换回我的用户控件内的小数回到我的模型数据?

如果 TextBox 未获得焦点,您可以订阅 LostFocus 事件来监听。然后在 LostFocus 事件中,您可以将 textbox 的当前值传递给您的 Text 依赖属性,当 Text 属性的值发生变化时,它会触发转换返回方法,然后将小数返回给您的模型数据。

在您的 usercontrol.xaml 中:

<TextBox
        x:Name="textBox"
        Grid.Row="0"
        Grid.Column="0"
        Grid.ColumnSpan="2"
        Header="{x:Bind Header}"
        Text="{x:Bind Text}"
        IsEnabled="{x:Bind IsControlEnabled}" LostFocus="textBox_LostFocus"/>

在您的 usercontrol.cs 中:

......

private void textBox_LostFocus(object sender, RoutedEventArgs e)
{
    Text = textBox.Text;
}

或者直接将你的文本框的绑定模型设置为Twoway。

在您的 usercontrol.xaml 中:

<TextBox
        x:Name="textBox"
        Grid.Row="0"
        Grid.Column="0"
        Grid.ColumnSpan="2"
        Header="{x:Bind Header}"
        Text="{x:Bind Text,Mode=TwoWay}"
        IsEnabled="{x:Bind IsControlEnabled}"/>

推荐阅读