更新绑定到由同一局部变量支持的属性的文本框

Update TextBoxes bound to properties backed by the same local variable

在使用 ReactiveUI 的应用程序中,我有两个属性由同一个局部变量支持。然后使用属性绑定到两个文本框,其中一个显示值,另一个显示值乘以 2。我需要让一个框反映另一个框中的更改。

视图模型:

public class AppViewModel : ReactiveObject
{
    private int? _boxCommon;
    public int? boxOrg
    {
        get => _boxCommon;
        set
        {
            Trace.WriteLine($"**** Check1: {value}");
            _ = this.RaiseAndSetIfChanged(ref _boxCommon, value);
        }
    }
    public int? boxDouble
    {
        get => _boxCommon * 2;
        set
        {
            Trace.WriteLine($"**** Check2: {value}");
            _ = this.RaiseAndSetIfChanged(ref _boxCommon, (int)value / 2);
        }
    }

    private int? lastVal;

    public AppViewModel()
    {
        _boxCommon = 10;
        lastVal = 10;
        
        // Reflect changes to the other box.
        this.WhenAnyValue(x => x.boxOrg)
            .Throttle(TimeSpan.FromMilliseconds(800))
            .Select((t) =>
            {
                if (t != lastVal)
                {
                    return t * 2;
                }
                else
                {
                    return boxDouble;
                }
            })
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe((t) => boxDouble = t);  // seems reduntdant cause both backed by the same var.

        this.WhenAnyValue(x => x.boxDouble)
            .Throttle(TimeSpan.FromMilliseconds(800))
            .Select((t) =>
            {
                if (t != lastVal)
                {

                    return t / 2;
                }
                else
                {
                    return boxOrg;
                }
            })
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe((t) => boxOrg = t);            
    }
}

查看:

<reactiveui:ReactiveWindow 
    x:Class="ReactiveDemo.MainWindow"
    x:TypeArguments="reactivedemo:AppViewModel"
    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:reactivedemo="clr-namespace:ReactiveDemo"
    xmlns:reactiveui="http://reactiveui.net"
    Title="Test" Height="150" Width="200"
    mc:Ignorable="d">
    <Grid Margin="12">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBlock Text="OrgNum: "/>
        <TextBox Grid.Column="1" x:Name="orgBox" />
        <TextBlock Grid.Row="1" Text="DoubleNum: "/>
        <TextBox Grid.Column="1" Grid.Row="1" x:Name="doubleBox" />
    </Grid>
</reactiveui:ReactiveWindow>

查看后面的代码:

public MainWindow()
{
    InitializeComponent();
    ViewModel = new AppViewModel();

    this.WhenActivated(disposableRegistration =>
    {
        // Notice we don't have to provide a converter, on WPF a global converter is
        // registered which knows how to convert a boolean into visibility.
        this.Bind(ViewModel,
            viewModel => viewModel.boxOrg,
            view => view.orgBox.Text)
            .DisposeWith(disposableRegistration);
        this.Bind(ViewModel,
            viewModel => viewModel.boxDouble,
            view => view.doubleBox.Text)
            .DisposeWith(disposableRegistration);

    });
}

当我在一个框中进行更改时,Trace 会打印出设置到另一个框中的新值。但是,GUI 元素不会更新为新值。 WPF 和 ReactiveUI 的新手,非常感谢任何指点。

您宁愿使用 ValueConverter 而不是您的解决方案:

视图模型:

private int _boxSingle;
public int BoxSingle
{
    get => _boxSingle;
    set
    {
        this.RaiseAndSetIfChanged(ref _boxSingle, value);
    }
}

绑定:

this.Bind(ViewModel, vm => vm.BoxSingle, view => view.textBox1.Text)
    .DisposeWith(d);

this.Bind(ViewModel, vm => vm.BoxSingle, view => view.textBox2.Text, 
        v => (v * 2).ToString(), 
        v => int.Parse(v) / 2 )
    .DisposeWith(d);