更改变量时的事件处理可能会导致监控变量发生更改(C#、WPF)

本文关键字:变量 WPF 监控 改变 事件处理 | 更新日期: 2023-09-27 18:26:51

我有三个变量(公共属性)的问题。比方说,我想要一个二维的几何向量。

我们用以下三个属性来描述它:MyVector:{BEGIN:integer?,END:integer?、LENGTH:integer}

("integer?"表示其类型为Nullable<int>

  • 我们通过设置BEGIN来移动矢量
  • 我们可以通过显式更改length来更改向量的长度
  • 我们可以通过更改END来更改向量的长度,END会隐式更改length

到目前为止,没有问题。但我们还有其他规则:

MyVector: {BEGIN:odd integer, END: odd integer, LENGTH: integer}

我无法控制我收到的整数!所以我不能像ADA那样设置一个严格的类型

所以当BEGIN被更改时,我们必须检查输入是否是奇数。如果不是,我们必须证明它的合理性(比如说,如果LENGTH至少保持为0,它将随机移动1。)当END被更改时,我们必须再次进行检查。我们还需要设置LENGTH,它将一个更改事件调用为LENGTH。当LENGTH更改时,我们必须将END设置为BEGIN+LENGTH。这会将更改事件调用为END。

以下是可能导致事件循环和其他奇怪行为的原因。

我可以将其分解为三种情况:

  1. BEGIN被更改->对齐->END被更改
  2. END被更改->对齐->LENGTH被更改
  3. LENGTH已更改->END已更改

从这一点开始,我尝试实现状态转换自动化,其中状态是:

enum VectorChangeStates{
relaxed,
begin_changed, begin_changes_end, exit_1,
end_changed, end_changes_length, exit_2,
length_changed, length_changes_end, exit_3,
unknown
}

我就是不能让它正常工作!

错误是:当我设置BEGIN属性时,END被设置,它设置了LENGTH,LENGTH设置了END,所以LENGTH完全是野生的!(当然,它不是矢量,也不是随机变化的,但描述它需要太长时间)

下面是一些代码片段:

我的房产是这样的:

public static readonly DependencyProperty LENGTHProperty =
DependencyProperty.Register(
"LENGTH",
typeof(int),
typeof(MyVector),
new PropertyMetadata(0, new PropertyChangedCallback(OnLENGTHChanged)));
public int LENGTH
{
get { return (int)this.GetValue(LENGTHProperty); }
set { this.SetValue(LENGTHProperty, value); }
}

注:this.SetValue()发送更改事件

更改事件:

private void OnLENGTHChanged(int newValue)
{
// Avoid values lower than 0
if (newValue < 0)
{
this.LENGTH = 0;
return;
}
if (this.mActualState == VectorChangeState.Relaxed)
{
this.mActualState = VectorChangeState.length_changed;
this.HandleState();
}
}

其中this.mActualState为:private VectorChangeState mActualState=VectorChangeState.Relaxed;

并且CCD_ 4正在管理状态转换。我不会复制它(因为替换其中的名称会花费太长时间)。错误处理:如果出现问题(例如:我会调用BEGIN.ToString(),但BEGIN是null,则是this.mActualState = VectorChangeState.Relaxed

问题:这个问题可以通过实现状态转换机(或者类似的)来解决吗?如果是,我是不是想错了?如果没有,解决方案是什么?

我在这方面工作了将近两天,无论我实现了什么(状态机,还是不实现!),错误仍然存在,我很沮丧。。。

谢谢你的回答,很抱歉发了这么长的帖子!

解决方案已标记。实际代码是一个完整的"myVector"类,当恒星正确对齐时可能会出现(我有时间的时候)

更改变量时的事件处理可能会导致监控变量发生更改(C#、WPF)

我真的,真的认为你应该只使用BeginEnd,计算Length。如果用户想要设置矢量的原点和长度,则在创建矢量时使用这些数字来导出End。如果你走这条路,那么依赖关系只会朝一个方向流动,这会让变得更简单

您可以使用WPF的值强制机制来计算Length,也可以确保BeginEnd的值有效(例如,确保Begin不在End之后)。

观察:

public class MyVector : DependencyObject
{
    public static readonly DependencyProperty BeginProperty;
    public static readonly DependencyProperty EndProperty;
    public static readonly DependencyProperty LengthProperty;
    public int? Begin
    {
        get { return (int?)GetValue(BeginProperty); }
        set { SetValue(BeginProperty, value); }
    }
    public int? End
    {
        get { return (int?)GetValue(EndProperty); }
        set { SetValue(EndProperty, value); }
    }
    public int Length
    {
        get { return (int)GetValue(LengthProperty); }
    }
    public void Resize(int newLength)
    {
        if (newLength < 0)
            throw new ArgumentOutOfRangeException("newLength"");
        if (this.Begin == null)
            this.Begin = 1;
        this.End = this.Begin + newLength;
    }
    static MyVector()
    {
        BeginProperty = DependencyProperty.Register(
            "Begin",
            typeof(int?),
            typeof(MyVector),
            new PropertyMetadata(default(int?), OnBeginChanged, CoerceBegin));
        EndProperty = DependencyProperty.Register(
            "End",
            typeof(int?),
            typeof(MyVector),
            new PropertyMetadata(default(int?), OnEndChanged, CoerceEnd));
        var lengthKey = DependencyProperty.RegisterReadOnly(
            "Length",
            typeof(int?),
            typeof(MyVector),
            new PropertyMetadata(default(int), null, CoerceLength));
        LengthProperty = lengthKey.DependencyProperty;
    }
    private static void OnBeginChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        d.CoerceValue(EndProperty);
        d.CoerceValue(LengthProperty);
    }
    private static object CoerceBegin(DependencyObject d, object baseValue)
    {
        var vector = (MyVector)d;
        var begin = (int?)baseValue;
        if (begin > vector.End)
            return vector.End;
        if (begin % 2 == 0)
            return begin == 0 ? 1 : begin - 1;
        return baseValue;
    }
    private static void OnEndChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        d.CoerceValue(BeginProperty);
        d.CoerceValue(LengthProperty);
    }
    private static object CoerceEnd(DependencyObject d, object baseValue)
    {
        var vector = (MyVector)d;
        var end = (int?)baseValue;
        if (end < vector.Begin)
            return vector.Begin;
        if (end % 2 == 0)
            return end + 1;
        return baseValue;
    }
    private static object CoerceLength(DependencyObject d, object baseValue)
    {
        var vector = (MyVector)d;
        return (vector.End - vector.Begin) ?? 0;
    }
    public override string ToString()
    {
        return string.Format(
            "[MyVector Begin: {0}, End: {1}, Length: {2}]",
            Begin,
            End,
            Length);
    }
}

测试用途:

var v = new MyVector(); // => [MyVector Begin: , End: , Length: 0]
v.Begin = 3;            // => [MyVector Begin: 3, End: , Length: 0]
v.End = 5;              // => [MyVector Begin: 3, End: 5, Length: 2]
v.Begin = 8;            // => [MyVector Begin: 5, End: 5, Length: 0]
v.End = 10;             // => [MyVector Begin: 7, End: 11, Length: 4]
v.Resize(6);            // => [MyVector Begin: 7, End: 13, Length: 6]