Диспетчер WPF вызывает индикатор выполнения - PullRequest
0 голосов
/ 22 января 2020

Я пытался научиться использовать Dispatches в Windows Presentation Foundation уже около 4 часов, и есть проблема, которую я никак не могу решить, независимо от того, сколько я гуглю.

У меня есть эта простая программа, которая рассчитывает процент прохождения пути через установленные сроки, например, 19% пути с 5 января по 31 марта.

Независимо от того, что я пытаюсь Я пытался написать класс DayChangeNotification, но это продолжало вызывать у меня проблемы, затем попытался использовать пакет Nuget для настройки задачи планирования для окна, но решил, что это сокращает углы, поэтому я вернулся к слегка модифицированному MidnightNotifier, который я нашел на некоторый стекопоток, вот мой код для MainWindow - я не уверен на 100% в том, как работать с событиями, происходящими из полностью синхронных линейных игр, поэтому, пожалуйста, будьте осторожны :)

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

namespace DateMeter
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DateTime StartDate = new DateTime(2020, 1, 6), EndDate = new DateTime(2020, 3, 30); //Made a global for these as an attempt
            WindowStartupLocation = WindowStartupLocation.Manual;
            Left = SystemParameters.WorkArea.Width - Width - (50 * (SystemParameters.WorkArea.Width / 2560)); //Don't know if this ratio
            Top = SystemParameters.WorkArea.Height - Height - (50 * (SystemParameters.WorkArea.Height / 1440)); //code works yet.
            ProgressBar timeToDate = pbDate;
            pbDate.Value = ((DateTime.Now.Date - StartDate).TotalDays / (EndDate - StartDate).TotalDays);
            pbDate.Maximum = 1; //Value between 0-1 rather than 0-100

            MidnightNotifier.DayChanged += (o, e) => 
            {
                Dispatcher.Invoke(delegate ()
                {
                    pbDate.Value = ((DateTime.Now.Date - StartDate).TotalDays / (EndDate - StartDate).TotalDays);
                });

            };
        }
    }
}

и вот мой Класс MidnightNotifier,

using System;
using System.Timers;

namespace DateMeter
{
    static class MidnightNotifier
    {
        private static readonly Timer timer;

        static MidnightNotifier()
        {
            timer = new Timer(GetSleepTime());
            timer.Elapsed += (s, e) =>
            {
                OnDayChanged();
                timer.Interval = GetSleepTime();
            };
            timer.Start();

            SystemEvents.TimeChanged += OnSystemTimeChanged;
        }

        private static double GetSleepTime()
        {
            var midnightTonight = DateTime.Today.AddDays(1);
            var differenceInMilliseconds = (midnightTonight - DateTime.Now).TotalMilliseconds;
            return differenceInMilliseconds;
        }

        private static void OnDayChanged()
        {
            var handler = DayChanged;
            if (handler != null)
                handler(null, null);
        }

        private static void OnSystemTimeChanged(object sender, EventArgs e)
        {
            timer.Interval = GetSleepTime();
        }

        public static event EventHandler<EventArgs> DayChanged;
    }
}

Если вам нужна дополнительная информация, дайте мне знать, спасибо за любую помощь, ребята :)

Редактировать: Мой плохой это полностью сорвалось с ума, извините, ребята

        xmlns:local="clr-namespace:DateMeter"
        mc:Ignorable="d"
        Height="150" Width="150" WindowStyle="None"
        AllowsTransparency="True" Background="Transparent">
    <Window.Resources>
        <local:ProgressToAngleConverter x:Key="ProgressConverter"/>
        <Style TargetType="{x:Type ProgressBar}" x:Key="ProgressBarStyle">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ProgressBar}">
                        <Grid>
                            <Ellipse Stroke="Black" Fill="#969696"/>
                            <Ellipse Stroke="Black" Margin="5" Fill="#2B2B2B"/>
                            <local:Arc StrokeThickness="4" Stroke="#2ce64e" Margin="1">
                                <local:Arc.StartAngle>
                                    <MultiBinding Converter="{StaticResource ProgressConverter}">
                                        <Binding Path="Minimum" RelativeSource="{RelativeSource TemplatedParent}"/>
                                        <Binding Path="." RelativeSource="{RelativeSource TemplatedParent}"/>
                                    </MultiBinding>
                                </local:Arc.StartAngle>
                                <local:Arc.EndAngle>
                                    <MultiBinding Converter="{StaticResource ProgressConverter}">
                                        <Binding Path="Value" RelativeSource="{RelativeSource TemplatedParent}"/>
                                        <Binding Path="." RelativeSource="{RelativeSource TemplatedParent}"/>
                                    </MultiBinding>
                                </local:Arc.EndAngle>
                            </local:Arc>
                            <TextBlock Text="{Binding Value, RelativeSource={RelativeSource TemplatedParent}, StringFormat={}{0:0.0%}}"
                                   Foreground="{TemplateBinding Background}" VerticalAlignment="Center" HorizontalAlignment="Center"
                                   FontSize="24" FontWeight="Light"/>

                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Border CornerRadius="90" BorderBrush="#2B2B2B" BorderThickness="4" Background="#838383">
        <Grid>
            <Viewbox>
                <ProgressBar Name="pbDate" Style="{StaticResource ProgressBarStyle}" 
                             Height="100" Width="100"/>
            </Viewbox>
        </Grid>
    </Border>
</Window>  

Вот мой xaml для MainWindow (только у меня есть окно)

Проблема, которая продолжает возникать, - это classi c 'Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им. '

1 Ответ

0 голосов
/ 02 февраля 2020

Я предполагаю исключение «Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им». происходит в обработчике событий DayChanged, верно? Взгляните на это из MSDN:

Если в приложении WPF используется System.Timers.Timer, стоит отметить, что System.Timers.Timer работает в другом потоке, чем пользователь интерфейс (UI) поток. Чтобы получить доступ к объектам в потоке пользовательского интерфейса (UI), необходимо опубликовать операцию в диспетчере потока пользовательского интерфейса (UI) с помощью Invoke или BeginInvoke. Причины использования DispatcherTimer, а не System.Timers.Timer, заключаются в том, что DispatcherTimer работает в том же потоке, что и Dispatcher, и DispatcherPriority можно установить для DispatcherTimer.

Выше приведено DispatchTimer документация. По сути, если вы используете DispatchTimer вместо System.Timers.Timer, то событие, которое вызывается из указанного таймера, будет происходить в том же потоке, что и пользовательский интерфейс, поэтому обработчики смогут свободно взаимодействовать с пользовательским интерфейсом, не вызывая Dispatcher.Invoke.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...