WPF 中的内存模拟:绑定字节数组位置
Memory simulation in WPF: Binding byte array positions
我正在使用 C# 编写语言解释器。我的用户界面允许在运行时可视化和更改全局变量和直接内存地址。
当我尝试可视化和更改直接内存地址时遇到问题,因为它们可以以不同的数据大小(BYTE、WORD 和 DWORD)可视化。
0 1 2 3
---------------------------------
| FFx16 | FFx16 | FFx16 | FFx16 | Memory
---------------------------------
- BYTE 3-
---- WORD 1 -----
------------ DWORD 0 ------------
因此,如果我在 UI 中可视化 BYTE3、WORD1 和 DWORD0,当我更改 BYTE3 的值时,我的视图不会升级 WORD1 和 DWORD0 值。
内存和执行上下文(模型):
public class Memoria
{
private byte[] memoria;
public Memoria(int size)
{
memoria = new byte[size];
}
public void Write<T>(int index, Tipo t, T value)
{
int nBytes = t.GetBytes();
byte[] bytesArray = t.GetBytesArray(value);
if (BitConverter.IsLittleEndian)
Array.Reverse(bytesArray);
for (int i = 0; i < nBytes; i++)
{
memoria[index+ i] = bytesArray[i];
}
}
}
public class Context
{
public Memoria DataMem { get; set; }
public Dictionary<int, IVariableObservable> VarGlobal { get; private set; }
public Dictionary<int, IVariableObservable> DirectAdress { get; private set; }
public InsertValues ()
{
foreach (IVariableObservable v in VarGlobal.Values)
{
Action action = () => v.Valor = v.InitValue;
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, action);
v.InsertValue();
}
}
public UpdateValue (int index)
{
IVariableObservable v = VarGlobal[index];
v.UpdateValue();
}
}
}
// * Language interpreter types are represented in Tipo objects
public abstract class Tipo
{
//* ....... More methods
public virtual int GetBytes()
{
return 0;
}
// * UI Representation
public virtual T GetUIRepresentation<T>(object valor)
{
return (T)Convert.ChangeType(valor, typeof(T));
}
}
变量(型号):
public interface IVariableObservable : INotifyPropertyChanged
{
string Name { get; }
Tipo Tipo { get; }
object Valor { get; set; }
object InitValue { get; set; }
int Offset { get; set; }
Memoria DataMem { get; set; }
void InsertValue()
void UpdateValue();
void OnPropertyChanged(string propertyName);
}
public interface IVariableObservable<T> : IVariableObservable
{
new T Valor { get; set; }
new T InitValue { get; set; }
}
public class VariableObservable<T> : INotifyPropertyChanged, IVariableObservable<T>
{
private T valor;
public T Valor
{
get
{
return this.valor;
}
set
{
if (value.ToString() == this.valor.ToString())
return;
this.valor = value;
this.OnPropertyChanged("Valor");
}
}
object IVariableObservable.Valor
{
get { return Valor; }
set
{
Valor = Tipo.GetUIRepresentation<T>(value);
}
}
public Memoria DataMem { get; set; }
public void InsertValue()
{
DataMem.Write<T>(Offset, Tipo, Valor);
}
public void UpdateValue()
{
Valor = DataMem.Read<T>(Offset, Tipo);
}
}
我的视图模型:
public class VariableViewModel : WorkspaceViewModel
{
readonly IVariableObservable _variable;
readonly ObserverRepository _observerRepository;
public VariableViewModel(IVariableObservable variable, ObserverRepository observerRespository)
{
if (variable == null)
throw new ArgumentNullException("variable");
if (observerRespository == null)
throw new ArgumentNullException("observerRespository");
_variable = variable;
_observerRepository = observerRespository;
this._variable.PropertyChanged += this.OnVariableValueChanged;
}
private void OnVariableValueChanged(object sender, EventArgs e)
{
this.OnPropertyChanged("Valor");
}
public object Valor
{
get
{
return _variable.Valor;
}
set
{
if (value == _variable.Valor)
return;
_variable.Valor = value;
this.OnPropertyChanged("Valor");
_variable.InsertValue();
}
}
}
有没有办法检查不同内存位置的变化并将变化传播到共享这些内存位置的所有内存地址?
好的,正如评论中所讨论的那样,我没有修复您的代码,而是完全重写代码以使用不同的体系结构,我认为这种体系结构对您来说会更好,前提是它不会破坏您需要的其他功能。
我的代码的主要目标是使变量不保留其值的副本,而是在检索值时查看内存存储本身,同样使用内存存储设置其值。
所有变量存储是 'pointer' 到内存位置(IMemory 对象中的地址)。 IMemory 对象提供读取和写入操作以读取和写入一个或多个连续字节 from/to 内存。
IMemory 公开了一个 MemoryChanged 事件,只要发生写入操作就会触发该事件。变量在其构造函数中将自身附加到此事件,并在收到事件后检查是否有任何更改的地址覆盖了变量的任何部分。如果他们这样做,则变量会触发其 INotifyPropertyChanged 事件,WPF 等可以使用该事件来监视变量更新。
现在代码:
public interface IMemory
{
void Write(int address, params byte[] bytes);
byte[] Read(int address, int numBytes);
byte Read(int address);
event MemoryChangedEventHandler MemoryChanged;
}
public class Memory : IMemory
{
private readonly byte[] _memory;
public Memory(int size)
{
_memory = new byte[size];
}
public void Write(int address, params byte[] bytes)
{
for (int offset = 0; offset < bytes.Length; offset++)
{
_memory[address + offset] = bytes[offset];
}
UpdateMemory(address, bytes.Length);
}
public byte[] Read(int address, int numBytes)
{
return _memory.Skip(address).Take(numBytes).ToArray();
}
public byte Read(int address)
{
return _memory[address];
}
private void UpdateMemory(int address, int length)
{
if (MemoryChanged != null)
{
MemoryChanged(this, new MemoryChangedEventArgs
{
StartAddress = address,
EndAddress = address + length
});
}
}
public event MemoryChangedEventHandler MemoryChanged;
}
public delegate void MemoryChangedEventHandler(object sender, MemoryChangedEventArgs e);
public class MemoryChangedEventArgs
{
public int StartAddress { get; set; }
public int EndAddress { get; set; }
}
public class IntVariable : INotifyPropertyChanged
{
private readonly int _address;
private readonly Memory _memory;
public IntVariable(int address, Memory memory)
{
_address = address;
_memory = memory;
_memory.MemoryChanged += MemoryChanged;
}
private void MemoryChanged(object sender, MemoryChangedEventArgs e)
{
int startAddress = _address;
int endAddress = startAddress + sizeof (int);
int changedStartAddress = e.StartAddress;
int changedEndAddress = e.EndAddress;
if (IsVariableChanged(startAddress, changedStartAddress, endAddress, changedEndAddress))
{
OnPropertyChanged("Value");
}
}
private static bool IsVariableChanged(int startAddress, int changedStartAddress, int endAddress, int changedEndAddress)
{
return Math.Max(startAddress, changedStartAddress) <= Math.Min(endAddress, changedEndAddress);
}
public int Value
{
get
{
var intBytes = _memory.Read(_address, sizeof(int));
return BitConverter.ToInt32(intBytes, 0);
}
set
{
var intBytes = BitConverter.GetBytes(value);
_memory.Write(_address, intBytes);
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
因此,您将构建 Memory 对象,然后创建引用 Memory 对象和内存中地址的 IntVariable(显然,您将根据不同可视化的需要创建不同的变量类型)对象。
例如
var _memory = new Memory(20);
var variable1 = new IntVariable(0, _memory);
var variable2 = new IntVariable(0, _memory);
然后执行 variable1.Value = 4;
会使 variable1 和 variable2 触发它们的 INotifyPropertyChanged 事件。
希望这就是您要找的。
我正在使用 C# 编写语言解释器。我的用户界面允许在运行时可视化和更改全局变量和直接内存地址。
当我尝试可视化和更改直接内存地址时遇到问题,因为它们可以以不同的数据大小(BYTE、WORD 和 DWORD)可视化。
0 1 2 3
---------------------------------
| FFx16 | FFx16 | FFx16 | FFx16 | Memory
---------------------------------
- BYTE 3-
---- WORD 1 -----
------------ DWORD 0 ------------
因此,如果我在 UI 中可视化 BYTE3、WORD1 和 DWORD0,当我更改 BYTE3 的值时,我的视图不会升级 WORD1 和 DWORD0 值。
内存和执行上下文(模型):
public class Memoria
{
private byte[] memoria;
public Memoria(int size)
{
memoria = new byte[size];
}
public void Write<T>(int index, Tipo t, T value)
{
int nBytes = t.GetBytes();
byte[] bytesArray = t.GetBytesArray(value);
if (BitConverter.IsLittleEndian)
Array.Reverse(bytesArray);
for (int i = 0; i < nBytes; i++)
{
memoria[index+ i] = bytesArray[i];
}
}
}
public class Context
{
public Memoria DataMem { get; set; }
public Dictionary<int, IVariableObservable> VarGlobal { get; private set; }
public Dictionary<int, IVariableObservable> DirectAdress { get; private set; }
public InsertValues ()
{
foreach (IVariableObservable v in VarGlobal.Values)
{
Action action = () => v.Valor = v.InitValue;
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, action);
v.InsertValue();
}
}
public UpdateValue (int index)
{
IVariableObservable v = VarGlobal[index];
v.UpdateValue();
}
}
}
// * Language interpreter types are represented in Tipo objects
public abstract class Tipo
{
//* ....... More methods
public virtual int GetBytes()
{
return 0;
}
// * UI Representation
public virtual T GetUIRepresentation<T>(object valor)
{
return (T)Convert.ChangeType(valor, typeof(T));
}
}
变量(型号):
public interface IVariableObservable : INotifyPropertyChanged
{
string Name { get; }
Tipo Tipo { get; }
object Valor { get; set; }
object InitValue { get; set; }
int Offset { get; set; }
Memoria DataMem { get; set; }
void InsertValue()
void UpdateValue();
void OnPropertyChanged(string propertyName);
}
public interface IVariableObservable<T> : IVariableObservable
{
new T Valor { get; set; }
new T InitValue { get; set; }
}
public class VariableObservable<T> : INotifyPropertyChanged, IVariableObservable<T>
{
private T valor;
public T Valor
{
get
{
return this.valor;
}
set
{
if (value.ToString() == this.valor.ToString())
return;
this.valor = value;
this.OnPropertyChanged("Valor");
}
}
object IVariableObservable.Valor
{
get { return Valor; }
set
{
Valor = Tipo.GetUIRepresentation<T>(value);
}
}
public Memoria DataMem { get; set; }
public void InsertValue()
{
DataMem.Write<T>(Offset, Tipo, Valor);
}
public void UpdateValue()
{
Valor = DataMem.Read<T>(Offset, Tipo);
}
}
我的视图模型:
public class VariableViewModel : WorkspaceViewModel
{
readonly IVariableObservable _variable;
readonly ObserverRepository _observerRepository;
public VariableViewModel(IVariableObservable variable, ObserverRepository observerRespository)
{
if (variable == null)
throw new ArgumentNullException("variable");
if (observerRespository == null)
throw new ArgumentNullException("observerRespository");
_variable = variable;
_observerRepository = observerRespository;
this._variable.PropertyChanged += this.OnVariableValueChanged;
}
private void OnVariableValueChanged(object sender, EventArgs e)
{
this.OnPropertyChanged("Valor");
}
public object Valor
{
get
{
return _variable.Valor;
}
set
{
if (value == _variable.Valor)
return;
_variable.Valor = value;
this.OnPropertyChanged("Valor");
_variable.InsertValue();
}
}
}
有没有办法检查不同内存位置的变化并将变化传播到共享这些内存位置的所有内存地址?
好的,正如评论中所讨论的那样,我没有修复您的代码,而是完全重写代码以使用不同的体系结构,我认为这种体系结构对您来说会更好,前提是它不会破坏您需要的其他功能。
我的代码的主要目标是使变量不保留其值的副本,而是在检索值时查看内存存储本身,同样使用内存存储设置其值。
所有变量存储是 'pointer' 到内存位置(IMemory 对象中的地址)。 IMemory 对象提供读取和写入操作以读取和写入一个或多个连续字节 from/to 内存。
IMemory 公开了一个 MemoryChanged 事件,只要发生写入操作就会触发该事件。变量在其构造函数中将自身附加到此事件,并在收到事件后检查是否有任何更改的地址覆盖了变量的任何部分。如果他们这样做,则变量会触发其 INotifyPropertyChanged 事件,WPF 等可以使用该事件来监视变量更新。
现在代码:
public interface IMemory
{
void Write(int address, params byte[] bytes);
byte[] Read(int address, int numBytes);
byte Read(int address);
event MemoryChangedEventHandler MemoryChanged;
}
public class Memory : IMemory
{
private readonly byte[] _memory;
public Memory(int size)
{
_memory = new byte[size];
}
public void Write(int address, params byte[] bytes)
{
for (int offset = 0; offset < bytes.Length; offset++)
{
_memory[address + offset] = bytes[offset];
}
UpdateMemory(address, bytes.Length);
}
public byte[] Read(int address, int numBytes)
{
return _memory.Skip(address).Take(numBytes).ToArray();
}
public byte Read(int address)
{
return _memory[address];
}
private void UpdateMemory(int address, int length)
{
if (MemoryChanged != null)
{
MemoryChanged(this, new MemoryChangedEventArgs
{
StartAddress = address,
EndAddress = address + length
});
}
}
public event MemoryChangedEventHandler MemoryChanged;
}
public delegate void MemoryChangedEventHandler(object sender, MemoryChangedEventArgs e);
public class MemoryChangedEventArgs
{
public int StartAddress { get; set; }
public int EndAddress { get; set; }
}
public class IntVariable : INotifyPropertyChanged
{
private readonly int _address;
private readonly Memory _memory;
public IntVariable(int address, Memory memory)
{
_address = address;
_memory = memory;
_memory.MemoryChanged += MemoryChanged;
}
private void MemoryChanged(object sender, MemoryChangedEventArgs e)
{
int startAddress = _address;
int endAddress = startAddress + sizeof (int);
int changedStartAddress = e.StartAddress;
int changedEndAddress = e.EndAddress;
if (IsVariableChanged(startAddress, changedStartAddress, endAddress, changedEndAddress))
{
OnPropertyChanged("Value");
}
}
private static bool IsVariableChanged(int startAddress, int changedStartAddress, int endAddress, int changedEndAddress)
{
return Math.Max(startAddress, changedStartAddress) <= Math.Min(endAddress, changedEndAddress);
}
public int Value
{
get
{
var intBytes = _memory.Read(_address, sizeof(int));
return BitConverter.ToInt32(intBytes, 0);
}
set
{
var intBytes = BitConverter.GetBytes(value);
_memory.Write(_address, intBytes);
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
因此,您将构建 Memory 对象,然后创建引用 Memory 对象和内存中地址的 IntVariable(显然,您将根据不同可视化的需要创建不同的变量类型)对象。
例如
var _memory = new Memory(20);
var variable1 = new IntVariable(0, _memory);
var variable2 = new IntVariable(0, _memory);
然后执行 variable1.Value = 4;
会使 variable1 和 variable2 触发它们的 INotifyPropertyChanged 事件。
希望这就是您要找的。