برنامج الأغذية العالمي والتركيز الأولي

StackOverflow https://stackoverflow.com/questions/817610

  •  03-07-2019
  •  | 
  •  

سؤال

ويبدو أنه عندما يبدأ تطبيق WPF، لا شيء لديه التركيز.

وهذا أمر غريب حقا. كل إطار آخر لقد استعملت لا فقط ما كنت تتوقع: يضع التركيز في البداية على عنصر التحكم الأول في ترتيب الجدولة. ولكني أكدت أنه من برنامج الأغذية العالمي، وليس فقط بلدي التطبيق - إذا أنا إنشاء نافذة جديدة، ومجرد وضع مربع نص فيه، وتشغيل التطبيق، لم يكن لديك مربع نص التركيز حتى أنا اضغط عليه أو اضغط على Tab . يوك.

وبلدي التطبيق الفعلي هو أكثر تعقيدا من مجرد نص. لدي عدة طبقات من UserControls ضمن UserControls. واحدة من تلك UserControls ديه القابل للتركيز = "الحقيقية" ومعالجات KeyDown / KeyUp، وأريد أن يكون التركيز بمجرد فتح نافذتي. ما زلت نوعا من المبتدئين WPF، رغم ذلك، وأنا لا وجود الكثير من الحظ في معرفة كيفية القيام بذلك.

إذا أبدأ بلدي التطبيق واضغط على مفتاح تبويب، ثم التركيز يذهب إلى بلدي تحكم focusable من، ويبدأ العمل بالطريقة التي أريدها. لكنني لا تريد للمستخدمين بلدي لدينا لضرب تبويب قبل أن يتمكنوا من البدء في استخدام النافذة.

ولقد لعبت حوالي مع FocusManager.FocusedElement، ولكن لست متأكدا التي تتحكم في وضعها على (نافذة على مستوى عال؟ الوالد الذي يحتوي على عنصر تحكم focusable من؟ السيطرة focusable من نفسه؟) أو ما إلى مجموعة ل.

وماذا يجب أن أفعل للحصول على بلدي التحكم بعمق المتداخلة أن يكون التركيز الأولي بمجرد فتح النافذة؟ أو الأفضل من ذلك، أن تركز أول تحكم focusable من في ترتيب الجدولة؟

هل كانت مفيدة؟

المحلول

وكان لي فكرة لامعة لحفر من خلال العاكس لنرى أين يتم استخدام الخاصية القابل للتركيز، وجدت طريقي إلى هذا الحل. أنا فقط بحاجة إلى إضافة التعليمات البرمجية التالية إلى منشئ نافذتي ل:

Loaded += (sender, e) =>
    MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));

وهذا سوف تلقائيا حدد عنصر التحكم الأول في ترتيب الجدولة، لذلك هو الحل العام التي ينبغي أن تكون قادرة على أن سقط في أي نافذة ومجرد العمل.

نصائح أخرى

وهذا يعمل أيضا:

<Window FocusManager.FocusedElement="{Binding ElementName=SomeElement}">

   <DataGrid x:Name="SomeElement">
     ...
   </DataGrid>
</Window>

واستنادا إلى الإجابة تنفيذ باعتبارها السلوك المرفقة:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace UI.Behaviors
{
    public static class FocusBehavior
    {
        public static readonly DependencyProperty FocusFirstProperty =
            DependencyProperty.RegisterAttached(
                "FocusFirst",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, OnFocusFirstPropertyChanged));

        public static bool GetFocusFirst(Control control)
        {
            return (bool)control.GetValue(FocusFirstProperty);
        }

        public static void SetFocusFirst (Control control, bool value)
        {
            control.SetValue(FocusFirstProperty, value);
        }

        static void OnFocusFirstPropertyChanged(
            DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Control control = obj as Control;
            if (control == null || !(args.NewValue is bool))
            {
                return;
            }

            if ((bool)args.NewValue)
            {
                control.Loaded += (sender, e) =>
                    control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }
        }
    }
}

استخدم مثل هذا:

<Window xmlns:Behaviors="clr-namespace:UI.Behaviors"
        Behaviors:FocusBehavior.FocusFirst="true">

ولقد وجدت الحلول الممكنة آخر. شارك مارك سميث على FirstFocusedElement العلامات تمديد للاستخدام مع FocusManager.FocusedElement.

<UserControl x:Class="FocusTest.Page2"
    xmlns:FocusTest="clr-namespace:FocusTest"
    FocusManager.FocusedElement="{FocusTest:FirstFocusedElement}">

وبعد وجود 'WPF التركيز الأولي كابوس "، واستنادا إلى بعض الإجابات على كومة، ما يلي أثبت لي أن أكون أفضل حل.

أولا، إضافة الخاصة بك App.xaml OnStartup () ما يلي:

EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
          new RoutedEventHandler(WindowLoaded));

وثم إضافة الحدث "WindowLoaded" أيضا في App.xaml:

void WindowLoaded(object sender, RoutedEventArgs e)
    {
        var window = e.Source as Window;
        System.Threading.Thread.Sleep(100);
        window.Dispatcher.Invoke(
        new Action(() =>
        {
            window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));

        }));
    }

ويجب أن تكون هذه المسألة خيوط استخدامها فشل WPF التركيز الأولي في الغالب بسبب بعض الظروف سباق الإطار.

ولقد وجدت الحل التالي أفضل لأنها تستخدم عالميا لالتطبيق كله.

ونأمل أن يساعد ...

وهران

حل

وكان نفس المشكلة مع الحل بسيط: في الإطار الرئيسي:

  <Window ....
        FocusManager.FocusedElement="{Binding ElementName=usercontrolelementname}"
         ... />

في عنصر تحكم المستخدم:

private void UserControl_GotFocus_1(object sender, RoutedEventArgs e)
        {
            targetcontrol.Focus();
            this.GotFocus -= UserControl_GotFocus_1;  // to set focus only once
        }

ويمكنك بسهولة أن سيطرة ضعت لنفسها باعتبارها العنصر تركيزا في XAML.

<Window>
   <DataGrid FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
     ...
   </DataGrid>
</Window>

ولقد حاولت أبدا وضع هذا في على UserControl ورؤية إذا كان هذا يعمل، ولكنه قد.

وهناك نسخة الحد الأدنى من Mizipzor في الإجابة للحصول على C # 6 +.

public static class FocusBehavior
{
    public static readonly DependencyProperty GiveInitialFocusProperty =
        DependencyProperty.RegisterAttached(
            "GiveInitialFocus",
            typeof(bool),
            typeof(FocusBehavior),
            new PropertyMetadata(false, OnFocusFirstPropertyChanged));

    public static bool GetGiveInitialFocus(Control control) => (bool)control.GetValue(GiveInitialFocusProperty);
    public static void SetGiveInitialFocus(Control control, bool value) => control.SetValue(GiveInitialFocusProperty, value);

    private static void OnFocusFirstPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var control = obj as Control;

        if (control == null || !(args.NewValue is bool))
            return;

        if ((bool)args.NewValue)
            control.Loaded += OnControlLoaded;
        else
            control.Loaded -= OnControlLoaded;
    }

    private static void OnControlLoaded(object sender, RoutedEventArgs e) => ((Control)sender).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}

استخدم في XAML الخاص بك:

<Window local:FocusBehavior.GiveInitialFocus="True" />

إذا كنت مثلي، وكنت تستخدم بعض الأطر التي، بطريقة أو بأخرى، لخبط مع السلوكيات التركيز الأساسية، وجعل كل الحلول المذكورة أعلاه لا صلة لها بالموضوع، لا يزال بإمكانك القيام بذلك:

1 - (! أيا كانت) ملاحظة العنصر الذي تحصل التركيز

2 - إضافة هذا في التعليمات البرمجية وراء xxx.xaml.cs

private bool _firstLoad;

و3 - أضف هذا على العنصر الذي تحصل التركيز الأول:

GotFocus="Element_GotFocus"

و4 - أضف الأسلوب Element_GotFocus في التعليمات البرمجية خلف، وتحديد اسمه عنصر WPF الذين يحتاجون إلى التركيز الأول:

private void Element_GotFocus(object sender, RoutedEventArgs e)
{
    if(_firstLoad)
    {
        this.MyElementWithFistFocus.Focus();
        _firstLoad = false;
    }
}

و5 - إدارة الحدث المحملة

في XAML

Loaded="MyWindow_Loaded"   

وفي xaml.cs

private void MyWindow_Loaded(object sender, RoutedEventArgs e)
{
        _firstLoad = true;
        this.Element_GotFocus(null, null);
}

والأمل وهذا سوف يساعد كحل أخير

وأنا أيضا واجهت نفس المشكلة. كان لي ثلاثة مربعات النص داخل حاوية قماش وأراد مربع النص الأول أن تركز عندما يفتح تحكم المستخدم. وجاء كود WPF نمط MVVM. أنا خلقت طبقة منفصلة السلوك للتركيز العنصر وbinded إلى جهة نظري من هذا القبيل.

وقماش قواعد سلوك

public  class CanvasLoadedBehavior : Behavior<Canvas>
{
    private Canvas _canvas;
    protected override void OnAttached()
    {
        base.OnAttached();
        _canvas = AssociatedObject as Canvas;
        if (_canvas.Name == "ReturnRefundCanvas")
        {

            _canvas.Loaded += _canvas_Loaded;
        }


    }

    void _canvas_Loaded(object sender, RoutedEventArgs e)
    {
        FocusNavigationDirection focusDirection = FocusNavigationDirection.Next;

        // MoveFocus takes a TraveralReqest as its argument.
        TraversalRequest request = new TraversalRequest(focusDirection);
        UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
        if (elementWithFocus != null)
        {
            elementWithFocus.MoveFocus(request);
        }

    }

}

ورمز لمشاهدة

<Canvas  Name="ReturnRefundCanvas" Height="200" Width="1466" DataContext="{Binding RefundSearchViewModel}">
                <i:Interaction.Behaviors>
                    <b:CanvasLoadedBehavior />
                </i:Interaction.Behaviors>
                <uc:Keyboard Canvas.Left="973" Canvas.Top="111" ToolTip="Keyboard" RenderTransformOrigin="-2.795,9.787"></uc:Keyboard>
                <Label  Style="{StaticResource Devlbl}" Canvas.Left="28" Content="Return and Refund Search" Canvas.Top="10" />
                <Image Height="30" Width="28" Canvas.Top="6" Canvas.Left="5" Source="pack://application:,,,/HomaKiosk;component/images/searchF.png">
                    <Image.OpacityMask>
                        <ImageBrush ImageSource="pack://application:,,,/HomaKiosk;component/images/searchF.png"/>
                    </Image.OpacityMask>
                </Image>

                <Separator Height="4" Canvas.Left="6" Margin="0" Canvas.Top="35" Width="1007"/>

                <ContentControl Canvas.Top="45" Canvas.Left="21"
                    ContentTemplate="{StaticResource ErrorMsg}"
                    Visibility="{Binding Error, Converter={c:StringNullOrEmptyToVisibilityConverter}}" 
                    Content="{Binding Error}" Width="992"></ContentControl>

                <Label  Style="{StaticResource Devlbl}" Canvas.Left="29" Name="FirstName" Content="First Name" Canvas.Top="90" />
                <wpf:AutoCompleteTextBox  Style="{StaticResource AutoComp}" Height="32" Canvas.Left="33" ToolTip="First Name"  Canvas.Top="120" Width="205"                     Padding="10,5" TabIndex="1001"
                    VerticalAlignment="Top"

                    Watermark=""
                    IconPlacement="Left"
                    IconVisibility="Visible"
                    Delay="100"

                    Text="{Binding FirstName, Mode=TwoWay, TargetNullValue=''}" 
                    Provider="{Binding FirstNameSuggestions}">
                    <wpf:AutoCompleteTextBox.ItemTemplate>
                        <DataTemplate>
                            <Border Padding="5">
                                <StackPanel Orientation="Vertical">
                                    <TextBlock Text="{Binding}"
                   FontWeight="Bold" />
                                </StackPanel>
                            </Border>
                        </DataTemplate>
                    </wpf:AutoCompleteTextBox.ItemTemplate>
                </wpf:AutoCompleteTextBox>

                <Label Style="{StaticResource Devlbl}" Canvas.Left="250" Content="Last Name" Canvas.Top="90" />
                <wpf:AutoCompleteTextBox  Style="{StaticResource AutoComp}" Height="32" ToolTip="Last Name" Canvas.Left="250"  Canvas.Top="120" Width="205" Padding="10,5"  TabIndex="1002"
                    VerticalAlignment="Top"
                    Watermark=""
                    IconPlacement="Left"
                    IconVisibility="Visible"
                    Delay="100"
                   Text="{Binding LastName, Mode=TwoWay, TargetNullValue=''}" 
                    Provider="{Binding LastNameSuggestions}">
                    <wpf:AutoCompleteTextBox.ItemTemplate>
                        <DataTemplate>
                            <Border Padding="5">
                                <StackPanel Orientation="Vertical">
                                    <TextBlock Text="{Binding}"
                   FontWeight="Bold" />
                                </StackPanel>
                            </Border>
                        </DataTemplate>
                    </wpf:AutoCompleteTextBox.ItemTemplate>
                </wpf:AutoCompleteTextBox>

                <Label Style="{StaticResource Devlbl}" Canvas.Left="480" Content="Receipt No" Canvas.Top="90" />
                             <wpf:AutoCompleteTextBox  Style="{StaticResource AutoComp}" Height="32" ToolTip="Receipt No" Canvas.Left="480"  Canvas.Top="120" Width="205" Padding="10,5"  TabIndex="1002"
                    VerticalAlignment="Top"
                    Watermark=""
                    IconPlacement="Left"
                    IconVisibility="Visible"
                    Delay="100"
                    Text="{Binding ReceiptNo, Mode=TwoWay, TargetNullValue=''}" 
                    Provider="{Binding ReceiptIdSuggestions}">
                    <wpf:AutoCompleteTextBox.ItemTemplate>
                        <DataTemplate>
                            <Border Padding="5">
                                <StackPanel Orientation="Vertical" >
                                    <TextBlock Text="{Binding}"
                   FontWeight="Bold">

                                    </TextBlock>
                                </StackPanel>
                            </Border>
                        </DataTemplate>
                    </wpf:AutoCompleteTextBox.ItemTemplate>
                    <i:Interaction.Behaviors>
                        <b:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9]+$" MaxLength="15" />
                    </i:Interaction.Behaviors>
                </wpf:AutoCompleteTextBox>
                <!--<Label Style="{StaticResource Devlbl}" Canvas.Left="710" Content="Duration" Canvas.Top="79" />-->
                <!--<ComboBox AllowDrop="True" Canvas.Left="710" ToolTip="Duration" Canvas.Top="107" Width="205" TabIndex="1004"
                    Style="{StaticResource CommonComboBox}"      
                    ItemsSource="{Binding Durations}" DisplayMemberPath="Description" SelectedValuePath="Id" SelectedValue="{Binding SelectedDate, Mode=TwoWay}">

                </ComboBox>-->

                <Button Content="Search" Style="{StaticResource MyButton}" ToolTip="Search" 
                    Canvas.Top="116" Canvas.Left="710" Cursor="Hand" 
                    Command="{Binding SearchCommand}" TabIndex="2001">
                </Button>
                <Button Content="Clear" Style="{StaticResource MyButton}"  ToolTip="Clear"
                    Canvas.Top="116" Canvas.Left="840" Cursor="Hand" 
                    Command="{Binding ClearCommand}" TabIndex="2002">
                </Button>
                <Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="25" Source="pack://application:,,,/HomaKiosk;component/images/chkpending.png"/>
                <Label  Style="{StaticResource LegendLbl}" Canvas.Left="50" Content="Check Returned and Payment Pending" Canvas.Top="178" />
                <Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="300" Source="pack://application:,,,/HomaKiosk;component/images/chkrepaid.png"/>
                <Label  Style="{StaticResource LegendLbl}" Canvas.Left="325" Content="Repaid" Canvas.Top="178" />
                <Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="395" Source="pack://application:,,,/HomaKiosk;component/images/refund.png"/>
                <Label  Style="{StaticResource LegendLbl}" Canvas.Left="415" Content="Refunded" Canvas.Top="178" />
                 </Canvas>

وفوق تم حل لا يعمل كما هو متوقع بالنسبة لي، لقد تغيرت قليلا السلوك التي اقترحها Mizipzor على النحو التالي:

ومن هذا الجزء

if ((bool)args.NewValue)
        {
            control.Loaded += (sender, e) =>
                   control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
        }

لهذا

if ((bool)args.NewValue)
        {
            control.Loaded += (sender, e) => control.Focus();
        }

وأنا لا ربط هذا السلوك إلى النافذة أو UserControl، ولكن للسيطرة أريد أن أركز في البداية، منها مثلا:

<TextBox ui:FocusBehavior.InitialFocus="True" />

وأوه، آسف لتسمية مختلفة أنا باستخدام اسم InitialFocus للخاصية المرفقة.

وهذا العمل بالنسبة لي، ربما لأنها يمكن أن تساعد شخص آخر.

<Window FocusManager.FocusedElement="{Binding ElementName=yourControlName}">
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top