Smart Row Selection: Maintaining Infragistics UltraGrid State After Refresh

... skipping 1000 words about bad solutions ...

The Clean/Best Solution

Here's a pattern that elegantly handles this situation:

public void RefreshGrid()
{
    // 1. Store the current entity before refresh
    SomeEntity currentEntity = null;
    if (dataGrid.ActiveRow != null)
    {
        currentEntity = dataGrid.ActiveRow.ListObject as SomeEntity;
    }

    // 2. Refresh the grid
    dataGrid.RefreshData();

    // 3. Restore selection using entity ID
    if (currentEntity != null)
    {
        dataGrid.ActiveRow = dataGrid.Rows.FirstOrDefault(r => 
            ((SomeEntity)r.ListObject).Id == currentEntity.Id);
    }
}

Why This Pattern Is Best Practice

  1. Type Safety: Using the strongly-typed entity object instead of raw values
  2. Identity-Based: Uses unique IDs instead of volatile row positions
  3. Null-Safe: Handles cases where no row is selected
  4. Concise: LINQ makes the code readable and maintainable
  5. Reliable: Works even if data order changes or rows are filtered

2010年前的我的户外活动记录

  • 2010-06-19 西胡林-火村 西枫队
  • 2009-08-29 黄安坨 - 百花山 坐隐队
  • 2006-06-23晚-06-25午 龙聚山庄-后河-泉水营地-古城河-三叉-泉水营地-龙聚山庄 领队
  • 2006-06-09晚-06-11晚 龙聚山庄-苏家河-五里坡-三叉河-苏家河-龙聚山庄 领队
  • 2005-08-12-08-14 后河-古城河-五里坡-三叉河-后河
  • 2005-07-24 刘家峪-黄草梁-柏峪 一日
  • 2005-07-17 箭扣一日
  • 2005-05-27-29 后河二日(拣垃圾) 领队
  • 20050521-22 黄安陀-百花山-百花草甸-百花林场两日 领队
  • 20050109 龙聚山庄-后河-三岔-龙庆峡 一日 领队
  • 20041106 水闸-绝石梁-圈门一日(九龙山)
  • 20040925 威海 戚家夼-石门-仙姑顶-望岛村 一日穿越 领队 1.0级
  • 20040922 威海 戚家夼-石门-通讯站-潍坊路 半日探路 领队1.0级
  • 20040912 威海 菊花顶-古陌岭-远遥村 半日穿越 领队 1.0级
  • 20040908 威海 菊花顶-古陌岭-远遥村 独行半日探路 1.0级
  • 20040815 马栏-老龙窝-煤窝一日探路 2.0组 领队
  • 20040731-0801 后龙庆峡一日一夜 领队 1.5级 领队
  • 20040725 香山邮局->快活林->香山水库->挂甲塔->打鹰洼->四棵树->植物园->香山停车场一日穿越 1.0级 领队
  • 20040718 西大庄科-小海坨-大海坨-大海陀村一日 2.0级 领队
  • 20040711 九龙山-绝石梁-峰口庵-王平村 1.5级 领队
  • 20040702-0704 蒸汽机游游队 北京-延庆-龙聚山庄-后河-玉渡山-次仲泉-大海陀(未登顶)-小海陀-松山-延庆-北京 2.5+级
  • 20040618-0620 摩西队 北京-龙聚山庄-后河-古城河-五里坡-古城河-三岔河-龙庆峡-三岔河-后河-龙聚山庄 负重后龙庆峡探路穿越 2.0级
  • 20040612-13 变色龙yuci队 黄安陀-百花山-百花山停车场两日 2.0级
  • 20040605晚-20040606 私下带队 北京-龙聚山庄-后河-古城河-三岔河-后河-龙聚山庄 负重后龙庆峡一日穿越 2.0级
  • 20040530 私下带队 北京-龙聚山庄-后河-古城河-三岔河-后河-龙聚山庄 后龙庆峡一日穿越 2.0级
  • 20040523 西枫队 圈门-峰口庵-龙潭 一日 1.0
  • 20040522 漂流队 柏峪-黄草梁-北灵山-灵山停车场一日 2.0级
  • 20040515-0516 咕咚队雨中密云小水峪-牛盆峪穿越(雨大林密,未完成,中途折返) 1.7级
  • 20040502-0503 泰安药乡国家森林公园
  • 20040501 自驾车北京-济南->泰安
  • 20040417 变色龙队玉皇庙-无名山1-无名山2..-无名山N-连理石-妙境林场-北港沟一日疯狂抱石穿棘探路 2.0级
  • 20040411 yuci队 玉皇庙-清水尖一日F·B探路(探路未完成) 1.0级
  • 20040404 小榄队 涧沟村-庙洼-阳台山-大风口-凤凰岭-飞来石-减肥路-天梯-神泉-龙泉寺 一日穿越 2.0级
  • 20040328 小榄队 柏峪-黄草梁-留言壁-实心楼-落叶谷-椴木沟-灵山停车场一日穿越 1.5级
  • 20040321 yuci变色龙队 柏峪-十里坪-腊子口-象鼻山 一日FB 1.2级
  • 20031002 航天桥-月陀岛自驾车一日游(非绿野)
  • 20020915 高崖口-妙峰山 一日穿越(非绿野)

网友语录 - 第13期 - 人类之所以进步,是因为下一代不听上一代的话

安子 尽量多发现身边那些笑点很低,很容易满足,无论何时看起来都是喜洋洋的人,并且尽量多的跟他们在一起,你会感觉到被滋养,被激发,被启迪。它们像炭火一样煲养你的生命,给你力量,带来喜悦,他们是真正的人间天使。(更重要的,只要你贴他们足够近,他们还有能力把你转化成他们的同类)


碧螺姑娘 突然间真实感受到了“人生是旷野”的具体意义。虽然风刀霜剑严相催,但就是要热热闹闹地去活着。


奧匈帝國小説家弗朗茨·卡夫卡(Franz Kafka)寫過一則微型小説叫《法律門前》。小説講的是:有個鄉下人走到一處敞開的大門前,但是看門人不讓他進去。鄉下人問,那他以後可不可以進去呢?看門人跟他説,以後有可能,但是現在不行。看門人還暗示他說,如果他實在想進去,可以試一試,不過裏面還有更多看門人守著其他大門,這些看門人一個比一個難纏。後來這個鄉下人就在這個大門前等了一輩子,就等有機會允許他進去。等到自己快要死的時候,鄉下人問:爲什麽一直沒有其他人要求進這個大門?看門人跟他說:因爲這個大門就是專門給你一個人開的,等你死了,大門就會關起來。


人生若梦为欢几何 有句话说的很好,你把生活当游戏,把周围所有的人当npc,就不会内耗了。


CarrieZ 人类之所以进步,是因为下一代不听上一代的话


…more

Implementing QuickFix/n Logging with NLog

Wen working with QuickFix/n ibrary , efficient logging is crucial for troubleshooting. Here's how to implement a custom logging solution that routes QuickFix logs through NLog to your ELK stack.

Key Components

  1. NLogAdapter: A custom adapter that implements QuickFix's ILog interface:
public class NLogAdapter(ILogger logger) : ILog
{
    private const string HeartbeatPattern = @"\x0135=0\x01";
    private static readonly Regex HeartbeatRegex = new(HeartbeatPattern, RegexOptions.Compiled);

    private static bool IsHeartBeat(string message) => HeartbeatRegex.IsMatch(message);

    public void OnIncoming(string message)
    {
        if (!IsHeartBeat(message))
        {
            logger.Info("Incoming: {Message}", message);
        }
    }
    // ... other implementations
}
  1. NLogQuickFixLogFactory: A factory class to create log instances:
public class NLogQuickFixLogFactory(ILog logger) : ILogFactory
{
    public ILog Create(SessionID sessionId) => logger;
    public ILog CreateNonSessionLog() => logger;
}

Implementation Steps

  1. Register Dependencies in your DI container:
builder.Services.AddSingleton<NLog.ILogger>(_ => LogManager.GetCurrentClassLogger());
builder.Services.AddSingleton<ILog, NLogAdapter>();
builder.Services.AddSingleton<ILogFactory, NLogQuickFixLogFactory>();
  1. Configure QuickFix to use the custom logger:
var initiator = new SocketInitiator(
    clientApp,
    storeFactory,
    sessionSettings,
    new NLogQuickFixLogFactory(quickfixLogger)  // Use custom logger injeted by ILog here 
);

Key Features

  • Heartbeat Filtering: Reduces log noise by filtering out FIX heartbeat messages
  • Structured Logging: Uses NLog's structured logging format for better parsing in ELK
  • Separation of Concerns: Cleanly separates QuickFix logging from application logging

Benefits

  1. Centralized logging in ELK stack
  2. Better debugging apabilities
  3. Reduced log volume through heartbeat filtering
  4. Consistent logging format across your application

Common NUnit `Assert` statements

Here’s a consolidated list of common NUnit Assert statements, categorized by their purpose. This should cover most of the common scenarios:


Basic Assertions

  • Equality:

    Assert.That(actual, Is.EqualTo(expected));
    Assert.That(actual, Is.Not.EqualTo(expected));
    
  • Boolean Conditions:

    Assert.That(condition, Is.True);
    Assert.That(condition, Is.False);
    
  • Null Checks:

    Assert.That(obj, Is.Null);
    Assert.That(obj, Is.Not.Null);
    

String Assertions

  • Contains:

    Assert.That(actualString, Does.Contain(substring));
    
  • Starts With / Ends With:

    Assert.That(actualString, Does.StartWith(prefix));
    Assert.That(actualString, Does.EndWith(suffix));
    
  • Empty or Not Empty:

    Assert.That(actualString, Is.Empty);
    Assert.That(actualString, Is.Not.Empty);
    
  • Matches Regex:

    Assert.That(actualString, Does.Match(regexPattern));
    

Collection Assertions

  • Contains Item:

    Assert.That(collection, Does.Contain(item));
    
  • Has Specific Count:

    Assert.That(collection, Has.Count.EqualTo(expectedCount));
    
  • Empty or Not Empty:

    Assert.That(collection, Is.Empty);
    Assert.That(collection, Is.Not.Empty);
    
  • Unique Items:

    Assert.That(collection, Is.Unique);
    

Numeric Assertions

  • Greater Than / Less Than:

    Assert.That(actual, Is.GreaterThan(expected));
    Assert.That(actual, Is.LessThan(expected));
    
  • Greater Than or Equal / Less Than or Equal:

    Assert.That(actual, Is.GreaterThanOrEqualTo(expected));
    Assert.That(actual, Is.LessThanOrEqualTo(expected));
    
  • In Range:

    Assert.That(actual, Is.InRange(lower, upper));
    

Type Assertions

  • Instance of Type:

    Assert.That(obj, Is.TypeOf<ExpectedType>());
    Assert.That(obj, Is.InstanceOf<ExpectedType>());
    
  • Assignable From:

    Assert.That(obj, Is.AssignableTo<ExpectedType>());
    

Exception Assertions

  • Throws Exception:

    Assert.Throws<ExpectedExceptionType>(() => { methodCall(); });
    
  • Throws Specific Exception with Condition:

    var ex = Assert.Throws<ExpectedExceptionType>(() => { methodCall(); });
    Assert.That(ex.Message, Does.Contain("expected message"));
    

Miscellaneous

  • Same Instance:

    Assert.That(actual, Is.SameAs(expected));
    Assert.That(actual, Is.Not.SameAs(expected));
    
  • Applies a Condition:

    Assert.That(collection, Has.Some.Matches<ExpectedType>(item => item.Condition));
    
  • Delayed Constraints (Asynchronous):

    Assert.That(() => condition, Is.True.After(500).PollEvery(50));
    
  • Group related assertions together to improve readability and reporting:

    Assert.Multiple(() =>
    {
        Assert.That(okResult, Is.Not.Null, "okResult should not be null");
        Assert.That(okResult.Value, Is.TypeOf<string>(), "Value should be of type string");
    });