Invalidoperationexception как исправить - IT Справочник
Llscompany.ru

IT Справочник
39 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Invalidoperationexception как исправить

Invalidoperationexception как исправить

Решение проблемы с ошибкой «System.InvalidOperationException: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления ‘имя_элемента_GUI’ не из того потока, в котором он был создан.» заключается в создании и вызове методов-делегатов. Статья написана на основе перевода статьи Rüdiger Klaehn, оригинал см. в [1].

Проблема обычно возникает, когда необходимо получить доступ на запись к одному и тому же ресурсу асинхронно из нескольких потоков. Например, Вы имеете на форме ListBox, в который задумали выводить сообщения из обработчика события, который обрабатывается в другом потоке. У меня такое произошло, когда понадобилось отображение данных в ListBox, принятых в обработчике события поступления данных по USB.

Почему такая проблема возникает: ListBox создается в основном потоке (thread), запускающем GUI окна программы и обрабатывающим сообщения главного окна формы. Другие потоки могут быть созданы для поддержки обмена данными с внешними устройствами (сеть Ethernet, COM-порт, USB и т. п.). Эти другие потоки могут обрабатывать события приема данных асинхронно с выполнением основного потока. Поэтому попытка разными потоками что-то записать в ListBox может привести к конфликту с записью в ListBox данных из основного потока GUI интерфейса программы.

Как проблему можно решить: для ListBox создаются подпрограммы (методы), через которые выводятся данные в ListBox. Данные выводятся в ListBox только через эти подпрограммы, больше никак. Эти подпрограммы делаются защищенными (thread-safe) для вызова из любых потоков через delegate, InvokeRequired, Invoke.

Программирование интерфейса пользователя через Windows Forms довольно простое, пока вы не используете несколько потоков. Однако всякий раз, когда Вашему приложению нужно выполнить какую-нибудь фактическую работу, становится необходимым использовать поточную обработку (threading), т. е. создать дополнительный поток (thread) или потоки, чтобы обеспечить работоспособность пользовательского интерфейса (скорость отклика UI). В этом случае программирование Windows Forms может стать довольно сложным.

Вы наверное уже знаете, что Windows Forms главным образом не являются потокозащищенными (not thread safe). Например, Вы не можете безопасно прочитать (get) или установить (set) свойство объекта управления (control) Windows.Forms из любого потока, за исключением того потока, который обрабатывает очередь сообщений формы (message queue). Это чрезвычайно важно, когда Вы делаете модификацию своих элементов управления (controls) Ваших Windows Forms из потока очереди сообщений. Могут быть и другие случаи, когда разные потоки вступают в конфликт при доступе к одному и тому же общему ресурсу – например, обработчик события получения данных от внешнего устройства (USB, сокет Ethernet и проч.) должен выводить данные в ListBox, который был создан в главном окне программы. В этом случае выполнение программы может вызывать исключение «System.InvalidOperationException: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления ‘имя_экземпляра_ListBox’ не из того потока, в котором он был создан.».

Само собой, имеется стандартный механизм для решения этой проблемы. Каждый элемент управления (control) Windows Forms имеет свойство InvokeRequired, которое вернет false, если текущий поток является «родным» для контрола, т. е. является потоком очереди сообщений. Также имеется метод Invoke, который делает возможным поставить выполнение делегата (delegate) с параметрами в очередь сообщений управления.

Поскольку делегат выполняется непосредственно из очереди сообщений, то не возникает проблемы с потоками. Однако такой стиль программирования может быть довольно утомительным. Чтобы сделать что-то столь же простое, как установка свойства текста или запрет/разрешение элемента управления, Вам нужно определить отдельный метод, который соответствует делегату.

[Пример: случайные строки (Random Strings)]

Чтобы проиллюстрировать этот метод, я написал маленькую программу на Windows Forms, которая генерирует случайные строки. Вот кусок кода, который показывает, как сделана синхронизация между рабочим потоком (worker thread) и потоком цикла очереди сообщений (message loop thread).

char PickRandomChar( string digits)
<
Thread.Sleep(100);
return digits[random.Next(digits.Length)];
>
delegate void SetBoolDelegate( bool parameter);
void SetInputEnabled( bool enabled)
<
if (!InvokeRequired)
<
button1.Enabled=enabled;
comboBoxDigits.Enabled=enabled;
numericUpDownDigits.Enabled=enabled;
>
else
Invoke( new SetBoolDelegate(SetInputEnabled), new object [] );
>
delegate void SetStringDelegate( string parameter);
void SetStatus( string status) <
if (!InvokeRequired)
labelStatus.Text=status;
else
Invoke( new SetStringDelegate(SetStatus), new object [] );
>
void SetResult( string result) <
if (!InvokeRequired)
textBoxResult.Text=result;
else
Invoke( new SetStringDelegate(SetResult), new object [] );
>
delegate int GetIntDelegate();
int GetNumberOfDigits()
<
if (!InvokeRequired)
return ( int )numericUpDownDigits.Value;
else
return ( int )Invoke( new GetIntDelegate(GetNumberOfDigits), null );
>
delegate string GetStringDelegate();
string GetDigits()
<
if (!InvokeRequired)
return comboBoxDigits.Text;
else
return ( string )Invoke( new GetStringDelegate(GetDigits), null );
>
void Work()
<
try
<
SetInputEnabled( false );
SetStatus( «Working» );
int n=GetNumberOfDigits();
string digits=GetDigits();
StringBuilder text= new StringBuilder ();
for ( int i=0;i!=n;i++)
<
text.Append(PickRandomChar(digits));
SetResult(text.ToString());
>
SetStatus( «Ready» );
>
catch (ThreadAbortException)
<
SetResult( «» );
SetStatus( «Error» );
>
finally
<
SetInputEnabled( true );
>
>
void Start()
<
Stop();
thread= new Thread( new ThreadStart(Work));
thread.Start();
>
void Stop()
<
if (thread!= null )
<
thread.Abort();
thread= null ;
>
>

Здесь используется Thread.Abort, так как это самое простое решение. Если Вы делаете что-то, что не должно быть прервано ни при каких обстоятельствах, то вместо этого Вы должны использовать флаг сигнализации для потока. Здесь приведен простой, но очень повторяющийся код. Имейте в виду, что Вы всегда должны проверить InvokeRequired, потому что вызов Invoke перед созданием очереди сообщений может привести к ошибке. Скачать исходный код проекта (Visual Studio C# 2010) можно по ссылке [7].

[Генерирование потокозащищенных оберток (thread-safe wrappers)]

В предыдущей статье (см. [2]) я показал, как можно автоматически генерировать обертки для классов, чтобы заставить их «неявно» реализовать интерфейс. Тот же метод генерации кода можно расширить, чтобы создать обертки, автоматически обеспечивающие вызов метода в правильном потоке. Я позже подробно опишу, как это работает. В первую очередь рассмотрим, как используется весь механизм. Сначала Вы предоставляете соответствующие свойства в Вашей форме (чекбоксы, листбоксы, и проч.), не заботясь о проблемах с потоками. Это именно то, что Вы хотели бы сделать, если бы совсем не использовали многопоточность.

public bool InputEnabled
<
set
<
button1.Enabled= value ;
comboBoxDigits.Enabled= value ;
numericUpDownDigits.Enabled= value ;
>
>
public string Status
<
set < labelStatus.Text= value ;>
>
public int NumberOfDigits
<
get < return numericUpDownDigits.Value; >
>
public string Digits
<
get < return comboBoxDigits.Text; >
>
public string Result
<
set < textBoxResult.Text= value ; >
>

Затем определите интерфейс, который содержит все свойства и/или методы, к которым может быть получен доступ из других разных потоков.

Читать еще:  Не включается пк блок питания исправен

interface IFormState
<
int NumberOfDigits < get ; >
string Digits < get ; >
string Status < set ; >
string Result < set ; >
bool InputEnabled < set ; >
>

Теперь в методе worker все, что Вы должны сделать – создать thread-safe wrapper и использовать его. Для Вас опущен весь повторяющийся код.

void Work()
<
IFormState state=Wrapper.Create( typeof (IFormState), this );
try
<
state.InputEnabled= false ;
state.Status= «Working» ;
int n=state.NumberOfDigits;
string digits=state.Digits;
StringBuilder text= new StringBuilder ();

for ( int i=0;i <
text.Append(PickRandomChar(digits));
state.Result=text.ToString();
>
state.Status= «Ready» ;
>
catch (ThreadAbortException)
<
state.Status= «Error» ;
state.Result= «» ;
>
finally
<
state.InputEnabled= true ;
>
>

[Как это работает]

Генератор обертки (wrapper generator) использует System.Reflection.Emit для генерации proxy-класса, который содержит все требуемые для интерфейса методы. Это также включает методы доступа к свойствам, у которых есть специальная сигнатура.

Тело этих методов будет делать вызов оригинальных методов напрямую, если InvokeRequired вернул false. Это важно, чтобы удостовериться, что запрос методов также работает, если форма еще не подключена к потоку обработки сообщений.

Если InvokeRequired вернул true, создается делегат, указывающий на оригинальный метод, и созданный делегат передается в метод Invoke формы. Типы делегата кэшируются так, чтобы Вы не получили несколько типов делегата для той же самой сигнатуры метода.

Поскольку wrapper generator использует интерфейс для вызова синхронизации ISynchronizeInvoke, Вы можете применить это решение и для приложений, не использующих Windows-Forms. Все, что нужно сделать – самостоятельно реализовать интерфейс и возможно обработку очереди сообщений.

[Ограничения и возможные проблемы]

Важно понимать, что пока thread-safe wrapper скрывает издержки потоковой синхронизации, из него нельзя делать выход. К примеру, доступ к свойству через thread safe wrapper будет намного медленнее, чем прямой доступ к свойству, если InvokeRequired вернул true. Поэтому если Вам нужно делать многочисленные сложные изменения в Вашей форме из разных потоков, лучшим решением будет создать один отдельный метод для всех действий и вызывать его, вместо того чтобы использовать отдельные вызовы доступа к свойствам.

Также нужно иметь в виду, что не каждый объект может быть безопасно передан из одного потока в другой без синхронизации. В общем случае можно безопасно передавать только типы наподобие int, DateTime и т. п. и иммунные ссылочные типы наподобие string. Будьте особенно осторожны при передаче мутированных ссылочных типов (mutable reference types) наподобие StringBuilder из одного потока к другому. Это будет удачным только в том случае, если будет реально обеспечено, что объект не был модифицирован, пока имеется ссылка на этот объект в других потоках, или все будет удачно если объект является thread safe. Если есть сомнения, то просто передайте глубокую копию вместо ссылки.

Whidbey уменьшает проблемы многопоточности, так как он имеет дополнительную поддержку (см. [5]) для фоновой обработки в Windows Forms, и это тем более делает работу с делегатами намного проще благодаря поддержке анонимных методов (см. [4]), которые являются реально закрытыми (closure, см. [6]).

Установка свойства в Whidbey намного проще:

Точно так же просто получить значение свойства:

К сожалению, Whidbey наверное выйдет в релиз одновременно с Duke Nukem Forever, где-нибудь в 2025 году.

System.InvalidOperationException

Igor Baptista

Terrarian

Attachments

Igor Baptista

Terrarian

Marcus101RR

Master of Ravens

Try the troubleshooting section if you would.

Welcome to PC Support Section.

In order to further assist you, please verify the following information below before proceeding. Please, we remind you that Terraria has certain requirements in order to function properly on your system. If you fail to check these requirements you may encounter errors or issues.

To avoid errors or mistakes, please consider posting your System Specifications. You can obtain this information by Right-Clicking My Computer on your system. You will get basic information about your Processor and RAM. If you wish to get a full detailed list, you can use third party software to determine your specifications or salvage the information from the Device Manager (Advanced Users). You may also use the available and recommended Third Party Software to gain your full system specifications for our technicians.

How to improve your support thread

    Post screenshots of errors

      You can use the

    key on your keyboard to paste your current monitor to the clipboard.

    • Click the window that you want to copy.
    • Press ALT+PRINT SCREEN. Important The text you see on your keyboard might be PrtSc, PrtScn, or PrntScrn. The other text on the Print Screen key is usually SysRq.
    • Paste (CTRL+V) the image into a Microsoft Office program or other application.
  • Provide your system specifications
  • Provide your current mandatory dependencies versions (XNA & .NET)
  • Be reminded this post is intended to simplify your next reply and ease our troubleshooting. If you fail to provide detailed information, it becomes a tedious task to determine what caused your problem. Please be kind enough to follow these simple steps and helpful tips!

    NOTE: If you are using an illegal copy of the game, you will receive no support, this process determines if you are using a legal copy.

    Before you ask, check in these threads to solve your issues:

    Obtaining Logs via Terraria (New)
    There is now a new way to obtain logs of Terraria and try to identify the issue at hand. This little method requires a bit more work, however, we provide you with some instructions on step by step on how to get this working. Please make sure that you check which version of Terraria you have before doing this. Note that the Steam version is slightly easier than the other one.
    Log Location: C:Users DocumentsMy GamesTerrariaLogs

    Steam Version
    There is no special requirement with steam as it is one simple platform.

    1. Open Steam Library .
    2. Right-Click Terraria on the Library and select Properties .
    3. Select General Tab , if not already selected.
    4. Click Set Launch Options .
    5. In the text box insert -logerrors -logfile

    GOG Version
    There are different procedures for the operating system you are using, we will try to get them for all.

    1. Create a shortcut of Terraria Executable .
    2. Right-Click the Shortcut and select Properties .
    3. In Target Box, add at the end the parameters -logerrors -logfile

    Troubleshooting Your Problem with TerrariaServer.exe
    In order to figure out what your problem is with the game, we require that you run the Terraria Server Client (TerrariaServer.exe). This will display any errors or successes on launch. Should there be any errors from the program itself, use the command prompt and copy the error to display it here.

    1. Right click within the Command Prompt.
    2. In the drop-down menu, select Mark.
    3. Once you made a selection, Right Click or Press Enter to copy.
    4. Paste your results in your thread.

    If you have trouble with the above instructions, your system might be showing «Not Responding» or your System may need to be rebooted to start clean.

    Deleting the JSON files to clear Terraria Settings
    Before proceeding any further, please delete the config.json file located in your Terraria Folder under My Documents/My Games. Then start Terraria again, this may fix some unexplained issues, but we wish to make sure you are running a nice and clean installation:

    1. Locate My Documents Folder.
    2. Open My Games Folder.
    3. Open Terraria Folder.
    4. Delete Config.json file from this location.
      • You can also delete the Favorites/Profile files as well, just in case.

    Frequently Asked Questions

    Q: My world has corrupted somehow and will not load properly, what can I do?
    A: You may have corrupted the world by using modded clients, computer shutdown before the world could complete the save, or system failure within Terraria that caused the problem. You can try attempting to load your world using TEdit (Download).

    Q: My game is not launching, or I get errors regarding XNA/.NET Framework!
    A: You can attempt to make sure you have all Game Dependencies first, then try attempting this solution:

    If you don’t feel like sifting through all that, it’s basically to do with the framework permissions.

    This is how you change the right to use Framework/XNA:

    1. Right-Click the specific directory (Listed Below).
    2. Select Properties.
    3. Select the Security Tab
    4. Click on Advanced Option
    5. Select the Owner Tab
    6. Click on the bottom button to Edit.
    7. On this window select the Administrator in the row and make sure to select the Checkboxes below.
    8. Hit Apply and close all the windows.
    9. Try running the game again.

    Do the above for all of the following FOLDERS:

    C:WindowsMicrosoft.NETassemblyGAC_32:
    Microsoft.Xna.Frameworkv4.0_4.0.0.0__842cf8be1de50553
    Microsoft.Xna.Framework.Gamev4.0_4.0.0.0__842cf8be1de50553
    Microsoft.Xna.Framework.Graphicsv4.0_4.0.0.0__842cf8be1de50553
    Microsoft.Xna.Framework.Xactv4.0_4.0.0.0__842cf8be1de50553

    C:WindowsMicrosoft.NETassemblyGAC_MSIL:
    Microsoft.Xna.Framework.Avatarv4.0_4.0.0.0__842cf8be1de50553
    Microsoft.Xna.Framework.GamerServicesv4.0_4.0.0.0__842cf8be1de50553
    Microsoft.Xna.Framework.Input.Touchv4.0_4.0.0.0__842cf8be1de50553
    Microsoft.Xna.Framework.Netv4.0_4.0.0.0__842cf8be1de50553
    Microsoft.Xna.Framework.Storagev4.0_4.0.0.0__842cf8be1de50553
    Microsoft.Xna.Framework.Videov4.0_4.0.0.0__842cf8be1de50553

    Q: Steam has reported that one (1) file has failed verification and was downloaded?
    A: This file is known as the serverconfig.txt file. Originally this file shouldn’t be packed with the game as Terraria should create this file automatically on launch if it is missing or out of date. Due to it being changed and updated by server owners, the file will constantly fail the verification process. This has no effect on playing the game, and can be ignored.

    Q: I am experiencing low frame rate for Terraria, but the machine passes as recommended?
    A: If you are using nVidia Control Panel, you can select Terraria.exe process and change the specifications on how your graphic card handles the game. Follow these instructions:

    1. Open nVidia Control Panel.
    2. Select Manage 3D Settings.
    3. Choose Program Settings Tab.
    4. Select Terraria as current program.
    5. Turn Triple buffering and Vertical sync to On .
    6. Run Terraria and turn Frame Skip to Off .
    7. The application should be running better than your current setup.

    Alternate Solution (The Aero Mode Bug)

    1. Goto your Desktop.
    2. Right Click and Select Personalize.
    3. Enable Aero Mode by selecting an Aero Background Option.
    4. You can also go Fullscreen Mode while Disabled Aero Mode .

    Q: Experiencing an XAudio Driver Issue?
    A: Check this out about the error: http://forums.terraria.org/index.ph. out-due-to-xaudio2_6-dll-on-windows-10.32894/

    Q: Missing XInput Driver for the game?
    A: You can download Microsoft DirectX Web Installer and fix this issue properly. We do not recommend searching for the driver (DLL) manually. Download it here.

    Q: Where can I find my world and player files?
    A: You can find your world and character files based on your system here:

    • Windows: DocumentsMy GamesTerrariaPlayers
    • Mac:

    /Library/Application Support/Terraria/Players
    Linux:

    /.local/share/Terraria/Players

    However, if you’re using Steam Cloud Sync, the files will be in a different location.

    • /userdata/ /105600/remote/players

    Q: Users with Windows 10 and Terraria Crashing (The Encryption Fix)
    A: Apparently Terraria uses a specific encryption method, some OS types do not allow this like Windows 10. This can be fixed!

    Terraria uses the RijndaelManaged class for player encryption, which isn’t FIPS (Federal Information Processing Standard) compliant. There’s a flag in the registry that tells Windows whether it should allow non-compliant encryption methods to be used. The registry key is:

    If the value fipsalgorithmpolicy is present and set to 1, non-compliant algorithms will be blocked and will throw exceptions if you try to use them (like you got). Setting it to 0 should fix the error.

    You might also want to check: HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlLsaFipsAlgorithmPolicy

    In case you don’t understand the above text, I’ll explain it by step:

    • Press the Windows Key (Button) and search for REGEDIT .
    • Browse to the location: HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlLsa
    • Locate the fipsalgorithmpolicy key and edit it by set its value to 0, or find the map with that name and disable it.

    If done, I think the error wouldn’t appear anymore.

    Q: Framerate dips down to 20 FPS or lower, and then comes back?
    A: This sounds like an issue with the CPU Affinity, you can set your affinity and see if the issue resolves.

    Исключение System.InvalidOperationException «для BeginExecuteReader нужно открытое и доступное подключение»

    Всем привет. Я наткнулся на непредвиденную проблему.
    Что надо исправить в коде, чтобы убрать исключение «System.InvalidOperationException»? (Скрин приложен). Или дело не в коде?

    Для BeginExecuteReader нужно открытое и доступное подключение Connection
    Когда запуская программу вылазит ошибка "Для BeginExecuteReader нужно открытое и доступное.

    Исключение System.InvalidOperationException
    выбрасывает когда пытаюсь по таймеру добавлять текст в текст бокс public partial class.

    Исключение «System.InvalidOperationException»
    Что не так с проектом? (в rar-архиве). Как устранить исключение «System.InvalidOperationException»?

    Исключение System.InvalidOperationException
    выбрасывает когда пытаюсь по таймеру добавлять текст в текст бокс public partial class.

    Решение

    Если еще непонятна причина исключения, то оно возникало потому что к моменту вызова ExecuteReaderAsync соединение не успевало открыться.

    Добавлено через 8 минут
    И еще. SqlDataReader тоже нужно закрывать. Поэтому код лучше записать так.

    OwenGlendower, ах, ещё один нюансик: есть идеи, как ещё можно ввести User’а, чтобы не выпадало исключение?

    P.S. Без PPC тоже не хочет работать.

    Решение

    OwenGlendower, спасибо, вроде без перебоев работает.

    Ещё одна тема, которую я единолично не смог освоить: как асинхронно вывести две таблицы? Или есть какая-то статья по этой теме?

    Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

    Необработанное исключение типа «System.InvalidOperationException» в System.Data.dll
    В программировании нуб. Помогите исправить ошибку. Делал всё по видео-уроку. Но почему то при.

    Необработанное исключение типа «System.InvalidOperationException» в EntityFramework.dll
    Добрый день! пишу приложение WPF с веб сервисом wfc, в веб сервесе модель базы данных entity.

    Необработанное исключение типа «System.InvalidOperationException» в Newtonsoft.Json.dll
    Доброго времени суток. Не могу понять по какой причине программа выполняться криво. JObject.

    Необработанное исключение типа «System.InvalidOperationException»
    Добрый день уважаемые форумчане! Нужна ваша помощь. Ошибка такова: попытка доступа к элементу.

    Класс DispatcherObject

    Большую часть времени вы не будете взаимодействовать с диспетчером напрямую. Однако немало времени придется тратить на использование экземпляров DispatcherObject, потому что каждый визуальный объект WPF наследуется от этого класса. DispatcherObject — это просто объект, привязанный к диспетчеру. Другими словами — объект, привязанный к потоку диспетчера.

    DispatcherObject имеет всего три члена, которые перечислены в таблице:

    Объекты WPF часто вызывают VerifyAccess(), чтобы защитить себя. Они не вызывают VerifyAccess() в ответ на каждую операцию (поскольку это было бы слишком накладно по производительности), но вызывают этот метод достаточно часто, чтобы было маловероятным долго использовать объект из неверного потока.

    Например, следующий код реагирует на щелчок на кнопке, создавая новый объект System.Threading.Thread. Затем он использует этот поток для вызова небольшого фрагмента кода, который изменяет текстовое поле в текущем окне:

    Этот код специально задуман так, чтобы выдать сбой. Метод UpdateTextWrong() будет выполнен в новом потоке, которому не разрешен доступ к объектам WPF. В этом случае объект TextBox перехватывает нарушение, вызывая VerifyAccess(), при этом генерируется исключение InvalidOperationException.

    Чтобы исправить код, понадобится получить ссылку на диспетчер, владеющий объектом TextBox (тот же самый диспетчер, который владеет окном и всеми прочими объектами WPF в приложении). Получив доступ к этому диспетчеру, можно вызывать Dispatcher.BeginInvoke(), чтобы маршализировать некоторый код потоку диспетчера. По сути, BeginInvoke() планирует указанный код в качестве задачи для диспетчера. Затем диспетчер выполняет этот код. Ниже показан корректный код:

    Метод Dispatcher.BeginInvoke() принимает два параметра. Первый указывает свойство задачи. В большинстве случаев будет применяться DispatcherPriority.Normal, но можно также использовать более низкий приоритет, если есть задача, которая не обязательно должна быть завершена немедленно, и которую можно отложить до того момента, когда диспетчеру нечего будет делать.

    Например, это может иметь смысл, если нужно отобразить сообщение о состоянии длительно выполняющейся операции где-то в рамках пользовательского интерфейса. Можно использовать DispatcherPriority.ApplicationIdle, чтобы подождать, пока приложение завершит всю прочую работу, либо еще более «сдержанный» метод DispatcherPriority.SystemIdle, чтобы подождать, пока вся система не придет в состояние ожидания, и центральный процессор не станет простаивать.

    Допускается также применять пониженный приоритет, чтобы отвлечь внимание диспетчера на что-то другое. Однако рекомендуется оставлять высокие приоритеты для событий ввода (таких как нажатия клавиш). Они должны обрабатываться почти постоянно, или же возникнет впечатление, что приложение несколько медлительно. С другой стороны, добавление нескольких миллисекунд ко времени выполнения фоновой операции не будет заметно, так что приоритет DispatcherPriority.Normal более оправдан в такой ситуации.

    Второй параметр BeginInvoke() — это делегат, указывающий на метод с кодом, который необходимо выполнить. Этот метод может находиться где-то в другом месте кода, или же его можно определить встроенным (как в приведенном примере). Подход на основе встроенного кода хорош для простых операций, таких как обновление в одной строке. Однако если нужно использовать более сложный процесс для обновления пользовательского интерфейса, лучше будет вынести такой код в отдельный метод.

    Метод BeginInvoke() также возвращает значение, которое в данном примере не используется. BeginInvoke() возвращает объект DispatcherOperation, который позволяет получить состояние операции маршализации и определить, когда код действительно был выполнен. Однако DispatcherOperation применяется редко, потому что код, который передается BeginInvoke(), должен выполняться за очень короткое время.

    Помните, что длительная фоновая операция должна выполняться в отдельном потоке, а результат маршализироваться потоку диспетчера (и в этот момент будет обновлен пользовательский интерфейс, чтобы изменить разделяемый объект). Не имеет смысла выполнять длительно работающий код в методе, который передается BeginInvoke(). Например, приведенный ниже слегка реорганизованный код работает, однако он менее практичен:

    Здесь проблема заключается в том, что вся работа происходит в потоке диспетчера. Это значит, что код займет диспетчер примерно так же, как это происходило бы в приложении без многопоточности.

    Диспетчер также предоставляет метод Invoke(). Подобно BeginInvoke(), он маршализирует указанный код потоку диспетчера. Но в отличие от BeginInvoke(), метод Invoke() останавливает поток до тех пор, пока диспетчер выполняет код. Метод Invoke() можно использовать, если нужно приостановить асинхронную операцию до тех пор, пока от пользователя не поступит какой-нибудь отклик.

    Например, метод Invoke() можно вызвать для запуска фрагмента кода, отображающего диалоговое окно с кнопками ОК и Cancel. После того как пользователь щелкнет на кнопке и маршализируемый код завершится, Invoke() вернет управление, и можно будет продолжить работу в соответствии с ответом пользователя.

    Ссылка на основную публикацию
    ВсеИнструменты 220 Вольт
    Adblock
    detector