Я бы, вероятно, сбил что-то, используя атрибуты, а затем класс преобразования, чтобы преобразовать подходящие атрибуты в примитивы битового поля. Что-то вроде ...
using System;
namespace BitfieldTest
{
[global::System.AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
sealed class BitfieldLengthAttribute : Attribute
{
uint length;
public BitfieldLengthAttribute(uint length)
{
this.length = length;
}
public uint Length { get { return length; } }
}
static class PrimitiveConversion
{
public static long ToLong<T>(T t) where T : struct
{
long r = 0;
int offset = 0;
// For every field suitably attributed with a BitfieldLength
foreach (System.Reflection.FieldInfo f in t.GetType().GetFields())
{
object[] attrs = f.GetCustomAttributes(typeof(BitfieldLengthAttribute), false);
if (attrs.Length == 1)
{
uint fieldLength = ((BitfieldLengthAttribute)attrs[0]).Length;
// Calculate a bitmask of the desired length
long mask = 0;
for (int i = 0; i < fieldLength; i++)
mask |= 1 << i;
r |= ((UInt32)f.GetValue(t) & mask) << offset;
offset += (int)fieldLength;
}
}
return r;
}
}
struct PESHeader
{
[BitfieldLength(2)]
public uint reserved;
[BitfieldLength(2)]
public uint scrambling_control;
[BitfieldLength(1)]
public uint priority;
[BitfieldLength(1)]
public uint data_alignment_indicator;
[BitfieldLength(1)]
public uint copyright;
[BitfieldLength(1)]
public uint original_or_copy;
};
public class MainClass
{
public static void Main(string[] args)
{
PESHeader p = new PESHeader();
p.reserved = 3;
p.scrambling_control = 2;
p.data_alignment_indicator = 1;
long l = PrimitiveConversion.ToLong(p);
for (int i = 63; i >= 0; i--)
{
Console.Write( ((l & (1l << i)) > 0) ? "1" : "0");
}
Console.WriteLine();
return;
}
}
}
Что производит ожидаемый ... 000101011. Конечно, для этого требуется больше проверки ошибок и немного более удобного набора текста, но концепция (я думаю) звучит, многократно используется и позволяет вам выбивать легко поддерживаемые структуры дюжиной.
adamw
Я прикрепил объекты ICommand
к свойству Tag
объектов Button
и MenuItem
до .
Затем я просто проверяю, смогу ли я его применить и запустить, если смогу, например:
private void button1_Click(object sender, EventArgs e)
{
ICommand command = ((Control)(sender)).Tag as ICommand;
if (command != null)
{
command.Execute();
}
}
Для еще более легкой жизни попробуйте создать подкласс элементов управления (например, Button
, MenuItem
)
Мой подход основан на ответе Гейла, но использовании дополнительного метода и создании закрепления, доступного для lifeycle управления:
public static class ButtonExtensions
{
public static IDisposable Bind(this ButtonBase invoker, ICommand command)
{
void Click(object sender, EventArgs args) => command.Execute(null);
void CanExecuteChanged(object sender, EventArgs args) => invoker.Enabled = command.CanExecute(null);
invoker.Enabled = command.CanExecute(null);
invoker.Click += Click;
command.CanExecuteChanged += CanExecuteChanged;
return Disposable.Create(() =>
{
invoker.Enabled = false;
invoker.Click -= Click;
command.CanExecuteChanged -= CanExecuteChanged;
});
}
}
Вы можете использовать его как это:
private List<IDisposable> Disposables { get; } = new List<IDisposable>();
private ICommand MyCommand { get; }
public MyControl()
{
MyCommand = DelegateCommand.Create(() => ...);
Disposables.Add(myButton.Bind(MyCommand));
}
~MyControl()
{
foreach(var disposable in Disposables)
{
disposable?.Dispose();
}
}
Однако можно было бы предпочесть использовать ReactiveUI, у которого есть родная поддержка этого:
Я не думаю, что вы можете сделать это напрямую, но как насчет использования обработчика нажатия кнопки для вызова команды? Это не так чисто, как WPF, но вы все равно получаете разделение.
Я бы рекомендовал реализовать INotifyPropertyChanged , вы можете использовать его как в WinForms, так и в WPF. См. здесь для введения и здесь для дополнительной информации.