我试图限制由滑块触发的事件,当值已更改时,我希望限制为1秒,每秒打印一次,但打印的数据不正确.同时打印集合中的所有值,但我希望每秒打印该唯一数据类型的最后一个值,结果发布在下面.

[完全可复制代码]

<Grid>
    <TextBox x:Name="txtbilly" Text="{Binding Position, Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}" Margin="0,0,0,382" ></TextBox>
    <TextBox x:Name="txtbob" Text="{Binding Position, Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}" Margin="0,162,0,233" ></TextBox>
    <Slider x:Name="slbilly"  Value="{Binding Position, Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}" Margin="0,57,0,306" GotMouseCapture="slbilly_GotMouseCapture"/>
    <Slider x:Name="slbob"  Value="{Binding Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="0,206,0,171" GotMouseCapture="slbob_GotMouseCapture" />
</Grid>

代码隐藏:

public partial class MainWindow : Window
{
    Student billy = new Student("Unique1", 0.0f);
    Student Bob = new Student("Unique2", 0.0f);
    public MainWindow()
    {
        InitializeComponent();
        txtbilly.DataContext = billy;
        slbilly.DataContext = billy;
        billy.PropertyChanged += Students_PropertyChanged;

        txtbob.DataContext = Bob;
        slbob.DataContext = Bob;
        Bob.PropertyChanged += Students_PropertyChanged;

    }
    static IList<Student> studentsList = new List<Student>();
    IObservable<Student> observable;
    private void Students_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        var student = (Student)sender;
        studentsList.Add(student);
        Debug.Print("List COunt ==>>>" + studentsList.Count.ToString() + "\n");

        observable = studentsList.ToObservable(Scheduler.Default);

        observable.Throttle(TimeSpan.FromSeconds(1), Scheduler.Default);
    }

    private void slbilly_GotMouseCapture(object sender, MouseEventArgs e)
    {
        observable?.Subscribe(i => Debug.Print("{0}\nPos {1}\n Time Received {2}\nOBS Count{3}", i?.ID?.ToString(), i.Position.ToString(), DateTime.Now.ToString(), observable.Count<Student>().ToString()));
    }


    private void slbob_GotMouseCapture(object sender, MouseEventArgs e)
    {

        observable?.Subscribe(i => Debug.Print("{0}\nPos {1}\n Time Received {2}\nOBS Count{3}", i?.ID?.ToString(), i.Position.ToString(), DateTime.Now.ToString(), observable.Count<Student>().ToString()));
    }
}

型号:

public class Student : INotifyPropertyChanged
{
    private string _ID;
    public string ID
    {
        get
        {
            return _ID;
        }
        set
        {
            _ID = value;
            OnPropertyChanged(new PropertyChangedEventArgs("ID"));
        }
    }
    private float _Position;
    public float Position
    {
        get
        {
            return _Position;
        }
        set
        {
            _Position = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Position"));
        }
    }
    public Student(string id, float position)
    {

        this.Position = position;
        this.ID = id;

    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, e);
        }
    }
}

结果:

  1. Unique1 Pos 0.06468305收到时间2022年4月18日00:16:05

  2. Unique1 Pos 0.06468305收到时间2022年4月18日00:16:05 OBS

  3. Unique1 Pos 0.06468305收到时间2022年4月18日00:16:05 OBS

  4. Unique1 Pos 0.06468305收到时间2022年4月18日00:16:05 OBS

  5. Unique1 Pos 0.06468305收到时间2022年4月18日00:16:05 OBS

预期:如果用户从0.0开始,并在1秒内从0.0拖动到300.98,然后在2秒内拖动到200.45:

收到Unique1 Pos 0.0时间2022年4月18日00:16:05

Unique1 Pos 300.98收到时间2022年4月18日00:16:06

Unique1 Pos 200.45收到时间2022年4月18日00:16:07

问题:

  1. studentsList个计数持续增长,且不被可观察对象重置(每次使用鼠标从控件中释放时,它都应重置列表).

  2. InvalidOperationException:'集合已修改;枚举操作可能无法执行.'

  3. 调试.仅当我将鼠标从拖动动作中释放后,打印才会被打印/执行

@谜团性的回答整理了我的第四个已知问题.

我是Rx技术的新手,所以我不确定我是否以正确的方式实现了它.

Basically if the Value changed is coming from the same control I would like to throttle it, e.g. on the slider control when the user click the knob to drag start throttling once the user releases the mouse click stop throttling

推荐答案

为了向你展示你可能需要什么来让你的可观察到的工作,它应该是这样的:

var observable =
    Observable
        .Merge(
            Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(h => billy.PropertyChanged += h, h => billy.PropertyChanged += h).Select(x => billy),
            Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(h => Bob.PropertyChanged += h, h => Bob.PropertyChanged += h).Select(x => Bob))
        .Throttle(TimeSpan.FromSeconds(5.0))
        .ObserveOn(SynchronizationContext.Current)
        .Do(s =>
        {
            studentsList.Add(s);
            Debug.Print($"List Count ==>>>{studentsList.Count}{Environment.NewLine}");
        })
        .Select(s => Observable.FromAsync(() => ExpensiveHttpCall(s)).Select(u => new { Student = s, Result = u }))
        .Switch();

还有订阅,如下所示:

_subscription =
    observable
    .ObserveOn(SynchronizationContext.Current)
        .Subscribe(x =>
        {
            Debug.Print($"{x.Student.ID}{Environment.NewLine}Pos {x.Student.Position}{Environment.NewLine}Time Received {DateTime.Now.ToString()}{Environment.NewLine}List Count{studentsList.Count()}");
        });

我添加了以下代码来模拟长时间运行的HTTP调用:

    private async Task<Unit> ExpensiveHttpCall(Student student)
    {
        await Task.Delay(TimeSpan.FromSeconds(5.0));
        return Unit.Default;
    }

现在我不知道你想用这个查询做什么,但这应该有助于你朝着正确的方向前进.

Rx的关键是try 将您的查询简化为您订阅一次的单个查询.这让生活变得容易多了.

问任何问题.

以下是完整的代码:

public partial class MainWindow : Window
{
    Student billy = new Student("Unique1", 0.0f);
    Student Bob = new Student("Unique2", 0.0f);
    public MainWindow()
    {
        InitializeComponent();
        txtbilly.DataContext = billy;
        slbilly.DataContext = billy;

        txtbob.DataContext = Bob;
        slbob.DataContext = Bob;

        var observable =
            Observable
                .Merge(
                    Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(h => billy.PropertyChanged += h, h => billy.PropertyChanged += h).Select(x => billy),
                    Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(h => Bob.PropertyChanged += h, h => Bob.PropertyChanged += h).Select(x => Bob))
                .Throttle(TimeSpan.FromSeconds(5.0))
                .ObserveOn(SynchronizationContext.Current)
                .Do(s =>
                {
                    studentsList.Add(s);
                    Debug.Print($"List Count ==>>>{studentsList.Count}{Environment.NewLine}");
                })
                .Select(s => Observable.FromAsync(() => ExpensiveHttpCall(s)).Select(u => new { Student = s, Result = u }))
                .Switch();

        _subscription =
            observable
            .ObserveOn(SynchronizationContext.Current)
                .Subscribe(x =>
                {
                    Debug.Print($"{x.Student.ID}{Environment.NewLine}Pos {x.Student.Position}{Environment.NewLine}Time Received {DateTime.Now.ToString()}{Environment.NewLine}List Count{studentsList.Count()}");
                });
    }

    private IDisposable? _subscription = null;

    private async Task<Unit> ExpensiveHttpCall(Student student)
    {
        await Task.Delay(TimeSpan.FromSeconds(5.0));
        return Unit.Default;
    }

    static IList<Student> studentsList = new List<Student>();
}

Csharp相关问答推荐

如何将ref T*重新解释为ref nint?

MongoDB将JS查询转换为C#的问题

Monty Hall游戏节目模拟给我50/50的结果

为什么EF Core 6会针对null验证Count(*)?

编写DataAnnotations自定义验证器的多种方法

读取配置文件(mytest. exe. config)

Microsoft. VisualBasic. FileIO. FileSystem. MoveFile()对话框有错误?

Azure Redis缓存与Entra ID身份验证

MS Graph v5.42.0:在寻呼消息时更改页面大小

在C#中,将两个哈希集连接在一起的时间复杂度是多少?

BlockingCollection T引发意外InvalidOperationException

用C#从XML内部元素中获取特定值

当try 测试具有协变返回类型的抽象属性时,类似功能引发System.ArgumentException

在.NET8中如何反序列化为私有字段?

如何使用EPPlus C#在单个单元格中可视化显示多行文字

C#中类库项目的源代码生成器

KeyDown从我的文本框中删除输入,如何停止?

C#System.Commandline:如何向命令添加参数以便向其传递值?

Foreach非常慢的C#

如何阻止可传递依赖项出现在项目中