最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - How to reliably detect if an object initializer did NOT set a property? - Stack Overflow

programmeradmin3浏览0评论

My custom control is a Border that has been modified to support a bindable FrameId property that the library user will define as an enum in the client XAML they're developing. As shown below, the FrameId property either "is" or "is not" set.

<ContentPage ...>
    <ScrollView>
        <VerticalStackLayout
            Padding="30,0"
            Spacing="25">

            <!--Explicit-->
            <controls:FrameWithId 
                FrameId="{Binding Source={x:Static local:FrameId.BarcodeFrame}}" >                
                <Image 
                    Source="dotnet_bot.png" 
                    HeightRequest="185"  
                    Aspect="AspectFit" />
            </controls:FrameWithId>
            
            <!--Implicit-->
            <controls:FrameWithId >
                <CollectionView
                    ItemsSource="{Binding Frames}" 
                    ItemTemplate="{StaticResource FrameCardTemplate}"/>
            </controls:FrameWithId>
                        
            <!--Explicit-->
            <controls:FrameWithId 
                FrameId="{Binding Source={x:Static local:FrameId.QRCodeFrame}}">
                <Button Text="Click Me" />
            </controls:FrameWithId>

        </VerticalStackLayout>
    </ScrollView>  
</ContentPage> 

The ID is used to bootstrap the app by running a discovery flow in the background. This enumeration might take a second or two, but the UI strives to keep startup responsive by not awaiting this. The core challenge is reliably detecting whether a property assignment did not get set in the XAML so that the one-time discovery can be run in a default configuration.


My Question

Is it safe to assume that the constructor and object initializer are guaranteed to execute sequentially without interruption on the UI thread upon which they are being invoked?


Because if the answer is "yes" then my preferred option is super-simple, it seems to work great, and I believe this represents a worst-case by setting the delay to one tick. I've got at least two other ways I could detect this, but they're less optimal. Of course, if you can think of any alternative that achieves the goal in a more robust manner, I'm listening.

Framework Control Self-Discovery based on FrameId
enum Reserved { DefaultId, }

interface IDiscoveryMonitor { event EventHandler Discovered; }

class FrameWithId : Border, IDiscoveryMonitor
{
    public FrameWithId()
    {
        Stroke = SolidColorBrush.Transparent;
        var idB4 = FrameId;
        Task
            .Delay(TimeSpan.FromTicks(1))
            .GetAwaiter()
            .OnCompleted(() =>
            {
                // - This ASSUMES that CTOR and Object Initializer cannot
                //   be separated in time under any circumstances. 
                // - This assumption APPEARS TO BE RELIABLE HERE.
                // - But IS IT REALLY ???
                var idFtr = FrameId;
                Debug.WriteLine($"ID Before {idB4} => ID After {idFtr}");
                if(Equals(idFtr, Reserved.DefaultId))
                {
                    // The ID has 'not' been set so run discovery for default.
                    _ = MockRunDiscovery();
                }
            });
    }
    .
    .
    .

The output from the Debug.WriteLine(...) statements


Bindable FrameId property
    .
    .
    .
    public static readonly BindableProperty FrameIdProperty =
        BindableProperty.Create(
            propertyName: nameof(FrameWithId.FrameId),
            returnType: typeof(Enum),
            declaringType: typeof(FrameWithId),
            defaultValue: Reserved.DefaultId,
            defaultBindingMode: BindingMode.OneWay,
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                if (bindable is FrameWithId @this)
                {
                    _ = @this.MockRunDiscovery();
                }
            });
    .
    .
    .

MRE

A minimal project can be found in this REPO. It might make things more clear if one was to run it.

发布评论

评论列表(0)

  1. 暂无评论