更改变量时的事件处理可能会导致监控变量发生更改(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。
以下是可能导致事件循环和其他奇怪行为的原因。
我可以将其分解为三种情况:
- BEGIN被更改->对齐->END被更改
- END被更改->对齐->LENGTH被更改
- 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"类,当恒星正确对齐时可能会出现(我有时间的时候)
我真的,真的认为你应该只使用Begin
和End
,计算Length
。如果用户想要设置矢量的原点和长度,则在创建矢量时使用这些数字来导出End
。如果你走这条路,那么依赖关系只会朝一个方向流动,这会让变得更简单。
您可以使用WPF的值强制机制来计算Length
,也可以确保Begin
和End
的值有效(例如,确保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]