Не удается запустить фоновое задание, потому что & ldquo; вызывающий поток не может получить доступ к этому объекту, потому что ему принадлежит другой поток. & Rdquo; [Дубликат]

Обновлено (2018) с 2 версиями (проверено и продолжает работать и в Woocommerce 3.3.x) :

1) Версия плагина с Функция конструктора:

Используемые вами крючки устарели в WooCommerce 3 +

Чтобы заставить работать для всех цен на продукты, включая цены на изменение, вы должны использовать это:

## The following goes inside the constructor ##

// Simple, grouped and external products
add_filter('woocommerce_product_get_price', array( $this, 'custom_price' ), 99, 2 );
add_filter('woocommerce_product_get_regular_price', array( $this, 'custom_price' ), 99, 2 );
// Variations 
add_filter('woocommerce_product_variation_get_regular_price', array( $this, 'custom_price' ), 99, 2 );
add_filter('woocommerce_product_variation_get_price', array( $this, 'custom_price' ), 99, 2 );

// Variable (price range)
add_filter('woocommerce_variation_prices_price', array( $this, 'custom_variable_price' ), 99, 3 );
add_filter('woocommerce_variation_prices_regular_price', array( $this, 'custom_variable_price' ), 99, 3 );

## This goes outside the constructor ##

public function custom_price( $price, $product ) {
    // Delete product cached price  (if needed)
    // wc_delete_product_transients($product->get_id());

    return $price * 2; // X2 for testing
}

public function custom_variable_price( $price, $variation, $product ) {
    // Delete product cached price  (if needed)
    // wc_delete_product_transients($variation->get_id());

    return $price * 2; // X2 for testing
}

Код проверен и отлично работает (только) в WooCommerce 3 +.


2) Для версии темы: functions.php файл в активной дочерней теме (или активной теме) :

// Simple, grouped and external products
add_filter('woocommerce_product_get_price', 'custom_price', 99, 2 );
add_filter('woocommerce_product_get_regular_price', 'custom_price', 99, 2 );
// Variations
add_filter('woocommerce_product_variation_get_regular_price', 'custom_price', 99, 2 );
add_filter('woocommerce_product_variation_get_price', 'custom_price', 99, 2 );
function custom_price( $price, $product ) {
    // Delete product cached price  (if needed)
    // wc_delete_product_transients($product->get_id());

    return $price * 2; // X2 for testing
}

// Variable (price range)
add_filter('woocommerce_variation_prices_price', 'custom_variable_price', 99, 3 );
add_filter('woocommerce_variation_prices_regular_price', 'custom_variable_price', 99, 3 );
function custom_variable_price( $price, $variation, $product ) {
    // Delete product cached price  (if needed)
    // wc_delete_product_transients($variation->get_id());

    return $price * 2; // X2 for testing
}

Протестировано и работает в woocommerce 3 +


Для продаваемых товаров у вас есть эти крючки:

  • woocommerce_product_get_sale_price (простые, сгруппированные и внешние продукты)
  • woocommerce_variation_prices_sale_price (переменные продукты (min-max))
  • woocommerce_variation_prices_sale_price (варианты продуктов)
242
задан Christos 1 December 2015 в 22:27
поделиться

12 ответов

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

this.Dispatcher.Invoke(() =>
{
    ...// your code here.
});

Вы также можете использовать control.Dispatcher.CheckAccess() , чтобы проверить, является ли текущий поток владеет контролем. Если он действительно владеет, ваш код выглядит нормально. В противном случае используйте шаблон выше.

511
ответ дан oddRaven 25 August 2018 в 19:51
поделиться

это произошло со мной, потому что я попытался выполнить access UI компонент в another thread insted of UI thread

, как этот

private void button_Click(object sender, RoutedEventArgs e)
{
    new Thread(SyncProcces).Start();
}

private void SyncProcces()
{
    string val1 = null, val2 = null;
    //here is the problem 
    val1 = textBox1.Text;//access UI in another thread
    val2 = textBox2.Text;//access UI in another thread
    localStore = new LocalStore(val1);
    remoteStore = new RemoteStore(val2);
}

, чтобы решить эту проблему, обернуть любой вызов ui внутри , о чем упоминал Кандид в своем ответе

private void SyncProcces()
{
    string val1 = null, val2 = null;
    this.Dispatcher.Invoke((Action)(() =>
    {//this refer to form in WPF application 
        val1 = textBox.Text;
        val2 = textBox_Copy.Text;
    }));
    localStore = new LocalStore(val1);
    remoteStore = new RemoteStore(val2 );
}
16
ответ дан Community 25 August 2018 в 19:51
поделиться

Кроме того, другое решение гарантирует, что ваши элементы управления создаются в потоке пользовательского интерфейса, а не потоком рабочего потока, например.

0
ответ дан FindOutIslamNow 25 August 2018 в 19:51
поделиться

Чтобы добавить мои 2 цента, исключение может возникнуть, даже если вы вызываете свой код через System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(). Дело в том, что вам нужно вызвать Invoke() элемента Dispatcher элемента управления, к которому вы пытаетесь получить доступ, что в некоторых случаях может не совпадать с System.Windows.Threading.Dispatcher.CurrentDispatcher. Поэтому вместо этого вы должны использовать YourControl.Dispatcher.Invoke() для обеспечения безопасности. Я уже несколько часов стучал головой, прежде чем понял это.

26
ответ дан Hakam Fostok 25 August 2018 в 19:51
поделиться

Проблема в том, что вы вызываете GetGridData из фонового потока. Этот метод обращается к нескольким элементам управления WPF, которые привязаны к основному потоку. Любая попытка доступа к ним из фонового потока приведет к этой ошибке.

Чтобы вернуться к правильной теме, вы должны использовать SynchronizationContext.Current.Post. Однако в этом конкретном случае, похоже, большая часть работы, которую вы выполняете, основана на пользовательском интерфейсе. Следовательно, вы создадите фоновый поток, чтобы сразу вернуться к потоку пользовательского интерфейса и выполнить некоторую работу. Вам нужно немного реорганизовать свой код, чтобы он мог выполнять дорогостоящую работу в фоновом потоке, а затем публиковать новые данные в потоке пользовательского интерфейса после

2
ответ дан JaredPar 25 August 2018 в 19:51
поделиться

Как уже упоминалось здесь , Dispatcher.Invoke может заморозить UI. Вместо этого используйте Dispatcher.BeginInvoke.

Вот удобный класс расширений, который упрощает проверку и вызов диспетчера вызовов.

Пример использования: (вызов из окна WPF)

this Dispatcher.InvokeIfRequired(new Action(() =>
{
    logTextbox.AppendText(message);
    logTextbox.ScrollToEnd();
}));

Класс расширения:

using System;
using System.Windows.Threading;

namespace WpfUtility
{
    public static class DispatcherExtension
    {
        public static void InvokeIfRequired(this Dispatcher dispatcher, Action action)
        {
            if (dispatcher == null)
            {
                return;
            }
            if (!dispatcher.CheckAccess())
            {
                dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
                return;
            }
            action();
        }
    }
}
0
ответ дан Jeson Martajaya 25 August 2018 в 19:51
поделиться

Еще одно полезное использование для Dispatcher.Invoke - это немедленное обновление пользовательского интерфейса в функции, выполняющей другие задачи:

// Force WPF to render UI changes immediately with this magic line of code...
Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);

Я использую это, чтобы обновить текст кнопки до « Обработка ... "и отключить его при выполнении запросов WebClient.

38
ответ дан Lauraducky 25 August 2018 в 19:51
поделиться

Я также обнаружил, что System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() не всегда является диспетчером целевого контроля, точно так же, как dotNet пишет в своем ответе. У меня не было доступа к диспетчеру управления, поэтому я использовал Application.Current.Dispatcher, и он решил проблему.

2
ответ дан Paulus Limma 25 August 2018 в 19:51
поделиться

По какой-то причине ответ Кандиде не строился. Это было полезно, однако, поскольку это заставило меня найти это, которое отлично работало:

System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
    {
       //your code here...
    }));
11
ответ дан Sarah 25 August 2018 в 19:51
поделиться

Это работает для меня.

        new Thread(() =>
        {

        Thread.CurrentThread.IsBackground = false;
        Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate {

          //Your Code here.

        }, null);
        }).Start();
0
ответ дан sony vizio 25 August 2018 в 19:51
поделиться

Вам нужно обновить пользовательский интерфейс, поэтому используйте

Dispatcher.BeginInvoke(new Action(() => {GetGridData(null, 0)})); 
11
ответ дан Taryn 25 August 2018 в 19:51
поделиться

Я продолжал получать ошибку, когда добавлял каскадные comboboxes в свое приложение WPF и разрешал ошибку с помощью этого API:

    using System.Windows.Data;

    private readonly object _lock = new object();
    private CustomObservableCollection<string> _myUiBoundProperty;
    public CustomObservableCollection<string> MyUiBoundProperty
    {
        get { return _myUiBoundProperty; }
        set
        {
            if (value == _myUiBoundProperty) return;
            _myUiBoundProperty = value;
            NotifyPropertyChanged(nameof(MyUiBoundProperty));
        }
    }

    public MyViewModelCtor(INavigationService navigationService) 
    {
       // Other code...
       BindingOperations.EnableCollectionSynchronization(AvailableDefectSubCategories, _lock );

    }

Подробнее см. в https: // msdn .microsoft.com / запроса / dev14.query APPID = Dev14IDEF1 & амп;? л = EN-US & Amp; K = K (System.Windows.Data.BindingOperations.EnableCollectionSynchronization); к (TargetFrameworkMoniker-.NETFramework, версия% 3Dv4.7); к (DevLang-CSharp) & амп; й = истинно [/ д2]

0
ответ дан user8128167 25 August 2018 в 19:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: