programing

어플리케이션은 어디에 있습니까?WPF의 DoEvents()?

newsource 2023. 4. 10. 21:58

어플리케이션은 어디에 있습니까?WPF의 DoEvents()?

버튼을 누를 때마다 확대/축소되는 다음 샘플 코드가 있습니다.

XAML:

<Window x:Class="WpfApplication12.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <Canvas x:Name="myCanvas">

        <Canvas.LayoutTransform>
            <ScaleTransform x:Name="myScaleTransform" />
        </Canvas.LayoutTransform> 

        <Button Content="Button" 
                Name="myButton" 
                Canvas.Left="50" 
                Canvas.Top="50" 
                Click="myButton_Click" />
    </Canvas>
</Window>

*.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void myButton_Click(object sender, RoutedEventArgs e)
    {
        Console.WriteLine("scale {0}, location: {1}", 
            myScaleTransform.ScaleX,
            myCanvas.PointToScreen(GetMyByttonLocation()));

        myScaleTransform.ScaleX =
            myScaleTransform.ScaleY =
            myScaleTransform.ScaleX + 1;
        
        Console.WriteLine("scale {0}, location: {1}",
            myScaleTransform.ScaleX,
            myCanvas.PointToScreen(GetMyByttonLocation()));
    }
    
    private Point GetMyByttonLocation()
    {
        return new Point(
            Canvas.GetLeft(myButton),
            Canvas.GetTop(myButton));
    }
}

출력은 다음과 같습니다.

scale 1, location: 296;315
scale 2, location: 296;315

scale 2, location: 346;365
scale 3, location: 346;365

scale 3, location: 396;415
scale 4, location: 396;415

보다시피, 문제가 있는데, 나는 그것을 이용해서 해결한다고 생각했다.Application.DoEvents();하지만... 에는 선험자가 존재하지 않습니다.넷 4

무엇을 해야 하나?

이런 거 해봐

public static void DoEvents()
{
    Application.Current.Dispatcher.Invoke(DispatcherPriority.Background,
                                          new Action(delegate { }));
}

방금 Dispatcher 스레드에서 실행되는 메서드로 작업을 시작한 경우 UI 스레드를 차단하지 않고 차단해야 합니다.msdn은 디스패처 자체를 기반으로 DoEvents()를 구현하는 방법을 설명합니다.

public void DoEvents()
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
        new DispatcherOperationCallback(ExitFrame), frame);
    Dispatcher.PushFrame(frame);
}

public object ExitFrame(object f)
{
    ((DispatcherFrame)f).Continue = false;

    return null;
}

(디스패처로부터 취득).Push Frame 메서드)

일부에서는 동일한 논리를 적용하는 단일 방식을 선호할 수 있습니다.

public static void DoEvents()
{
    var frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
        new DispatcherOperationCallback(
            delegate (object f)
            {
                ((DispatcherFrame)f).Continue = false;
                return null;
            }),frame);
    Dispatcher.PushFrame(frame);
}

참고 항목: https://kent-boogaart.com/blog/dispatcher-frames

오래된 어플리케이션DoEvents() 메서드는 WPF에서 Dispatcher 또는 Background Worker Thread를 사용하여 설명한 대로 처리를 수행하는 것을 권장하지 않습니다.두 개체를 모두 사용하는 방법에 대한 몇 가지 기사는 링크를 참조하십시오.

꼭 어플리케이션을 사용해야 하는 경우.DoEvents()를 선택하면 시스템을 Import할 수 있습니다.창문들.forms.displays를 어플리케이션에 삽입하여 메서드를 호출합니다.단, WPF가 제공하는 이점을 모두 잃게 되므로 이 방법은 권장하지 않습니다.

윈도우 그래픽을 업데이트해야 할 경우 다음과 같이 사용하는 것이 좋습니다.

public static void DoEvents()
{
    Application.Current.Dispatcher.Invoke(DispatcherPriority.Render,
                                          new Action(delegate { }));
}
myCanvas.UpdateLayout();

효과가 있는 것 같습니다.

두 가지 접근방식의 문제 중 하나는 CPU 사용률이 유휴 상태(내 경험으로는 최대 12%)라는 것입니다.예를 들어 이 기술을 사용하여 모달 UI 동작을 구현하는 경우 등 경우에 따라서는 이 방법이 최적이 아닙니다.

다음 변형에서는 타이머를 사용하는 프레임 간에 최소 지연이 발생합니다(여기서는 Rx로 기술되어 있지만 일반 타이머로 실행할 수 있습니다).

 var minFrameDelay = Observable.Interval(TimeSpan.FromMilliseconds(50)).Take(1).Replay();
 minFrameDelay.Connect();
 // synchronously add a low-priority no-op to the Dispatcher's queue
 Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => minFrameDelay.Wait()));

「 」의 async ★★★★★★★★★★★★★★★★★」await이전 동기 을 경유하여 할 수 .이러한 블록은 UI를 사용하여 ()* 블록입니다.Task.Delay

private async void myButton_Click(object sender, RoutedEventArgs e)
{
    Console.WriteLine("scale {0}, location: {1}", 
        myScaleTransform.ScaleX,
        myCanvas.PointToScreen(GetMyByttonLocation()));

    myScaleTransform.ScaleX =
        myScaleTransform.ScaleY =
        myScaleTransform.ScaleX + 1;

    await Task.Delay(1); // In my experiments, 0 doesn't work. Also, I have noticed
                         // that I need to add as much as 100ms to allow the visual tree
                         // to complete its arrange cycle and for properties to get their
                         // final values (as opposed to NaN for widths etc.)

    Console.WriteLine("scale {0}, location: {1}",
        myScaleTransform.ScaleX,
        myCanvas.PointToScreen(GetMyByttonLocation()));
}

솔직히 말씀드리면, 저는 위의 정확한 코드를 사용해 본 적이 없지만, 많은 아이템을 넣을 때 엄격한 루프로 사용합니다.ItemsControl비싼 아이템 템플릿이 있어 UI 상의 다른 아이템에 시간을 더 주기 위해 약간의 지연을 추가할 수 있습니다.

예를 들어 다음과 같습니다.

        var levelOptions = new ObservableCollection<GameLevelChoiceItem>();

        this.ViewModel[LevelOptionsViewModelKey] = levelOptions;

        var syllabus = await this.LevelRepository.GetSyllabusAsync();
        foreach (var level in syllabus.Levels)
        {
            foreach (var subLevel in level.SubLevels)
            {
                var abilities = new List<GamePlayingAbility>(100);

                foreach (var g in subLevel.Games)
                {
                    var gwa = await this.MetricsRepository.GetGamePlayingAbilityAsync(g.Value);
                    abilities.Add(gwa);
                }

                double PlayingScore = AssessmentMetricsProcessor.ComputePlayingLevelAbility(abilities);

                levelOptions.Add(new GameLevelChoiceItem()
                    {
                        LevelAbilityMetric = PlayingScore,
                        AbilityCaption = PlayingScore.ToString(),
                        LevelCaption = subLevel.Name,
                        LevelDescriptor = level.Ordinal + "." + subLevel.Ordinal,
                        LevelLevels = subLevel.Games.Select(g => g.Value),
                    });

                await Task.Delay(100);
            }
        }

Windows Store 에서는, 컬렉션에 좋은 테마 전환이 있는 경우, 그 효과는 매우 바람직합니다.

루크

  • 댓글을 봐주세요.답변을 빠르게 쓸 때 동기화된 코드 블록을 가져다가 스레드를 다시 발신자에게 넘겨주는 동작을 생각하고 있었습니다.그 결과, 코드 블록은 비동기화 되었습니다.나는 내 대답을 완전히 바꾸고 싶지 않다. 왜냐하면 독자들은 서비와 내가 무슨 말다툼을 하고 있었는지 볼 수 없기 때문이다.

WPF에서 DoEvent()를 만듭니다.

Thread t = new Thread(() => {
            // do some thing in thread
            
            for (var i = 0; i < 500; i++)
            {
                Thread.Sleep(10); // in thread

                // call owner thread
                this.Dispatcher.Invoke(() => {
                    MediaItem uc = new MediaItem();
                    wpnList.Children.Add(uc);
                });
            }
            

        });
        t.TrySetApartmentState(ApartmentState.STA); //for using Clipboard in Threading
        t.Start();

잘 해 주세요!

푸시 프레임:

using System.Windows.Threading;
...
var frame = new DispatcherFrame();
Dispatcher.PushFrame(frame);

종료 프레임:

frame.Continue = false;

다음으로 Dispatcher Frame을 사용하여 Windows Forms DoEvents 메서드와 유사한 결과를 얻는 예를 나타냅니다.

https://learn.microsoft.com/dotnet/api/system.windows.threading.dispatcher.pushframe

갱신일 :

재미있는 제작 방법Task.Delay()비고정적인

// How to use: Task.Delay(250).WaitNB();
public static void WaitNB(this Task task)
{
    var frame = new DispatcherFrame();
    task.ContinueWith(t => frame.Continue = false);
    Dispatcher.PushFrame(frame);
}

원래 질문에 대한 답변:DoEvents는 어디에 있나요?

나는 DoEvents가 VBA라고 생각해.그리고 VBA에는 Sleep 기능이 없는 것 같습니다.그러나 VBA는 Sleep 또는 Delay와 정확히 동일한 효과를 얻을 수 있는 방법이 있습니다.DoEvents는 Sleep(0)과 동등한 것 같습니다.

VB 및 C#에서는 거래처입니다.NET. 그리고 첫 번째 질문은 C# 질문입니다.C#에서는 스레드를 사용합니다.sleep(0). 여기서 0은 0밀리초입니다.

당신은 필요하다

using System.Threading.Task;

사용하기 위해 파일 맨 위에 있는

Sleep(100);

당신의 코드로.

언급URL : https://stackoverflow.com/questions/4502037/where-is-the-application-doevents-in-wpf