拦截每个数据绑定以使用窄参数执行函数
Intercept every data binding to execute function with narrow parameter
我有一个包含原始数据类型的文件,例如 short
和 uint
以及 float
的原始数据形式。我将文件解析为 class,类似这样,以便独立跟踪所有内容的 有效性 并保存在 属性:
中
// Every class inherits this and therefore has the property "Valid"
public class Object { public bool Valid {get;set;} }
// Primitive data types as classes
public class Short : Object { public short Value {get;set;} }
public class UInt : Object { public uint Value {get;set;} }
public class Float : Object { public float Value {get;set;} }
// ... and other data types as classes
使用了这些原始 classes 的更大分组,但与此问题无关。最终,我通过包含的属性到达最大范围,它代表文件本身:
public class File : Object { public byte[] Data {get;private set;} }
public class FileTypeA : File { public Float X {get;set;} }
我正在使用数据绑定和 xaml 以及 Windows Presentation Foundation。我在这里展示了一个过度简化的示例,但足以说明数据绑定使用一堆 INotifyPropertyChanged 东西按预期工作。
我将文件数据的 CRC32 存储在包含的对象中,如下所示:
// This class contains private methods for calculating the CRC32 using a byte[] parameter
public class CRC32 : UInt { }
// The file's header data stores a CRC32 of the file data (excluding the header)
public class Header : Object { public CRC32 CRC {get;set;} }
// The aforementioned FileTypeA class is really more along the lines of this:
public class FileTypeA : File { public Header H {get;set;} public Float X {get;set;} }
当用户打开 FileTypeA
类型的文件时,我实例化了一个 FileTypeA
对象,它具有有效解析所有文件数据的连锁反应,如下所示:
// OpenFileDialog results in a string of the file path, for example:
string filepath = @"path\to\tests\test.a";
// Obtain byte[] of file data and store it along with the filepath in the FileTypeA object
FileTypeA fta = new FileTypeA(System.IO.File.ReadAllBytes(filepath), filepath);
// Instantiate and show a window suitable for displaying the data of type FileTypeA.
// The window stores a property of type FileTypeA.
FTAWindow fta_window = new FTAWindow(fta);
fta_window.Show();
FTAWindow
包含我用来引用所有 FileTypeA 数据的单个 属性:
public class FTAWindow : Window { public FileTypeA A {get;set;} }
我正在使用数据绑定来显示和提供 A
中各种属性的更改,最值得注意的是包含的基本类型对象中称为 Value
的属性。例如,在 xaml 中,我做了类似的事情:
<TextBox
x:Name="X_TextBox_Value"
Foreground="{Binding Path=A.X.Valid, Converter={StaticResource ValidToColor}}"
Text="{Binding Path=A.X.Value}"
/>
我也在window中显示了CRC32值。
问题就在这里: 我想在用户通过 window 中的数据绑定更改文件数据时动态地重新计算文件数据的 CRC32。数据绑定直接从 window 中的用户控件传递到属性;但我需要传递 CRC32 计算函数 A.Data
而数据绑定属性都是特定的、不相关的、范围较窄的 A.X.Value
并且构造属性无法访问它们包含的相邻构造属性的值class。有没有什么方法可以拦截每个数据绑定(或注册所有更改的通知,可能通过某种临时通知中心 class 就像 Apple 的 AppKit 一样)而不对所有内容使用 IValueConverter 以便我可以调用 CRC 计算FTAWindow
中的函数可以访问 A
?在绑定 属性 范围内,无法访问 A
。我认为我不应该以某种方式将 xaml 中的 A
传递给绑定属性的 setters.
我想让 window 的 A
属性 的每个数据绑定 setter(例如设置 A.X.Value
)做它做的事通常(设置值)然后执行位于 window 的代码隐藏中的此函数:
private void RecalculateCRC()
{
A.H.CRC.Value = CRC32.Calculate(A.Data);
}
我该怎么做?每次使用数据绑定设置 window 的 属性 时,如何使用参数 (A.Data
) 调用 window 方法 (RecalculateCRC()
)?
是不是像“How do I call a function via xaml?" If so, then how do I call the function after the data binding is resolved? Must I use a style trigger such as with a TextBox's LostFocus
event? Also related: Calling functions with parameters in xaml
一样简单
更新:
我有这个用于 INotifyPropertyChanged:
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
// I can put something here...
}
我可以将 A
绑定到 window 本身并使用它,以便在任何 属性 更改时调用它。这意味着将文件对象本身绑定到 window 并使用 IValueConverter 作为数据解析器,这没有任何意义。
我看到两个选项:
- 将对文件或其
byte[]
数据的引用存储为每个 class 的 属性,例如 Float
,但这似乎是一种 hack 和浪费。
- 不要使用数据绑定调用函数(那么为什么要使用数据绑定呢?)。相反,在用户控件上使用结束事件(例如每个文本框的
LostFocus
)来调用该函数。
样式触发器看起来也很像 hack。我会说事件最适合,但实际上意味着远离数据操作任务。
现在,我正在使用样式和事件,这很简单!
相关:
Subscribe to INotifyPropertyChanged for nested (child) objects
How do I subscribe to PropertyChanged event in my ViewModel?
在容器 class 的构造函数中订阅容器 class 的属性更改,如下所示:
public class FileTypeA : File
{
public Header H {get;set;}
public Float X {get;set;}
// constructor:
public FileTypeA(byte[] givenData, string givenPath) : base(givenData, givenPath)
{
X = new Float(...);
// watch for changes to the property:
X.PropertyChanged += MetaChanged;
}
// gets called when the aforementioned watched properties change:
private void MetaChanged(object sender, PropertyChangedEventArgs e)
{
H.UpdateCRC(Encode(...), ...);
}
}
您可以使用像这样的通用函数,一个带有所有属性反射的 for 循环,或者手动指定属性。
这很有帮助:
我有一个包含原始数据类型的文件,例如 short
和 uint
以及 float
的原始数据形式。我将文件解析为 class,类似这样,以便独立跟踪所有内容的 有效性 并保存在 属性:
// Every class inherits this and therefore has the property "Valid"
public class Object { public bool Valid {get;set;} }
// Primitive data types as classes
public class Short : Object { public short Value {get;set;} }
public class UInt : Object { public uint Value {get;set;} }
public class Float : Object { public float Value {get;set;} }
// ... and other data types as classes
使用了这些原始 classes 的更大分组,但与此问题无关。最终,我通过包含的属性到达最大范围,它代表文件本身:
public class File : Object { public byte[] Data {get;private set;} }
public class FileTypeA : File { public Float X {get;set;} }
我正在使用数据绑定和 xaml 以及 Windows Presentation Foundation。我在这里展示了一个过度简化的示例,但足以说明数据绑定使用一堆 INotifyPropertyChanged 东西按预期工作。
我将文件数据的 CRC32 存储在包含的对象中,如下所示:
// This class contains private methods for calculating the CRC32 using a byte[] parameter
public class CRC32 : UInt { }
// The file's header data stores a CRC32 of the file data (excluding the header)
public class Header : Object { public CRC32 CRC {get;set;} }
// The aforementioned FileTypeA class is really more along the lines of this:
public class FileTypeA : File { public Header H {get;set;} public Float X {get;set;} }
当用户打开 FileTypeA
类型的文件时,我实例化了一个 FileTypeA
对象,它具有有效解析所有文件数据的连锁反应,如下所示:
// OpenFileDialog results in a string of the file path, for example:
string filepath = @"path\to\tests\test.a";
// Obtain byte[] of file data and store it along with the filepath in the FileTypeA object
FileTypeA fta = new FileTypeA(System.IO.File.ReadAllBytes(filepath), filepath);
// Instantiate and show a window suitable for displaying the data of type FileTypeA.
// The window stores a property of type FileTypeA.
FTAWindow fta_window = new FTAWindow(fta);
fta_window.Show();
FTAWindow
包含我用来引用所有 FileTypeA 数据的单个 属性:
public class FTAWindow : Window { public FileTypeA A {get;set;} }
我正在使用数据绑定来显示和提供 A
中各种属性的更改,最值得注意的是包含的基本类型对象中称为 Value
的属性。例如,在 xaml 中,我做了类似的事情:
<TextBox
x:Name="X_TextBox_Value"
Foreground="{Binding Path=A.X.Valid, Converter={StaticResource ValidToColor}}"
Text="{Binding Path=A.X.Value}"
/>
我也在window中显示了CRC32值。
问题就在这里: 我想在用户通过 window 中的数据绑定更改文件数据时动态地重新计算文件数据的 CRC32。数据绑定直接从 window 中的用户控件传递到属性;但我需要传递 CRC32 计算函数 A.Data
而数据绑定属性都是特定的、不相关的、范围较窄的 A.X.Value
并且构造属性无法访问它们包含的相邻构造属性的值class。有没有什么方法可以拦截每个数据绑定(或注册所有更改的通知,可能通过某种临时通知中心 class 就像 Apple 的 AppKit 一样)而不对所有内容使用 IValueConverter 以便我可以调用 CRC 计算FTAWindow
中的函数可以访问 A
?在绑定 属性 范围内,无法访问 A
。我认为我不应该以某种方式将 xaml 中的 A
传递给绑定属性的 setters.
我想让 window 的 A
属性 的每个数据绑定 setter(例如设置 A.X.Value
)做它做的事通常(设置值)然后执行位于 window 的代码隐藏中的此函数:
private void RecalculateCRC()
{
A.H.CRC.Value = CRC32.Calculate(A.Data);
}
我该怎么做?每次使用数据绑定设置 window 的 属性 时,如何使用参数 (A.Data
) 调用 window 方法 (RecalculateCRC()
)?
是不是像“How do I call a function via xaml?" If so, then how do I call the function after the data binding is resolved? Must I use a style trigger such as with a TextBox's LostFocus
event? Also related: Calling functions with parameters in xaml
更新:
我有这个用于 INotifyPropertyChanged:
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
// I can put something here...
}
我可以将 A
绑定到 window 本身并使用它,以便在任何 属性 更改时调用它。这意味着将文件对象本身绑定到 window 并使用 IValueConverter 作为数据解析器,这没有任何意义。
我看到两个选项:
- 将对文件或其
byte[]
数据的引用存储为每个 class 的 属性,例如Float
,但这似乎是一种 hack 和浪费。 - 不要使用数据绑定调用函数(那么为什么要使用数据绑定呢?)。相反,在用户控件上使用结束事件(例如每个文本框的
LostFocus
)来调用该函数。
样式触发器看起来也很像 hack。我会说事件最适合,但实际上意味着远离数据操作任务。
现在,我正在使用样式和事件,这很简单!
相关:
Subscribe to INotifyPropertyChanged for nested (child) objects
How do I subscribe to PropertyChanged event in my ViewModel?
在容器 class 的构造函数中订阅容器 class 的属性更改,如下所示:
public class FileTypeA : File
{
public Header H {get;set;}
public Float X {get;set;}
// constructor:
public FileTypeA(byte[] givenData, string givenPath) : base(givenData, givenPath)
{
X = new Float(...);
// watch for changes to the property:
X.PropertyChanged += MetaChanged;
}
// gets called when the aforementioned watched properties change:
private void MetaChanged(object sender, PropertyChangedEventArgs e)
{
H.UpdateCRC(Encode(...), ...);
}
}
您可以使用像这样的通用函数,一个带有所有属性反射的 for 循环,或者手动指定属性。
这很有帮助: