Триггерная перерисовка элемента управления WPF Button из внешнего потока - PullRequest
0 голосов
/ 17 сентября 2010

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

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

Я пытался вызвать InvalidateVisual () для кнопки, но это не помогло.Я думаю, что я не понимаю, как фоновый поток может вызвать перерисовку.Но расстраивает то, что что-то перекрашивается, и все другие элементы управления, которые я использую (текстовые и графические элементы управления), также перекрашиваются должным образом, когда я обновляю их из того же сообщения о получении.пустое сообщение Диспетчеру приложения через Invoke (), но там тоже не повезло.

Поэтому я ищу советы о том, как сообщить WPF, что ему нужно обновить остальную часть кнопки, а не только текст.

Редактировать

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

class myButton
{
   Button theButton

   void SetButton()
   {
     theButton.Forground = a new color
   }
}

main
{
   myButton.theButton = (Button on WPF canvass)

   RegisterCallback( mycallbackFunction) with WCF client endpoint
}


void myCallbackFunction(message)
{
   if message has button related stuff,  call myButton.SetButton
}

Редактировать 2

Решил мою проблему .. На самом деле это был конфликт между методом "CanExecute" и настройкой атрибутов кнопок в обратном вызове.Как только я удалил функцию «CanExecute», все заработало.

Ответы [ 3 ]

0 голосов
/ 18 сентября 2010

Я рекомендую прочитать статью ( Создание более отзывчивых приложений с помощью Dispatcher ) из журнала MSDN, в которой описано, как WPF работает с Dispatcher при использовании BackgroundWorker.

0 голосов
/ 18 сентября 2010

Согласно моему редактированию, у меня возник конфликт между связыванием кнопок CanExecute в XAML и установкой цвета фона в обратном вызове. Мне действительно не нужно было CanExecute, поэтому избавление от этого решило мою проблему.

0 голосов
/ 18 сентября 2010

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

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

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

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    /// 
    public class MyButton : INotifyPropertyChanged
    {
        private Button _theButton;
        public Button TheButton
        {
            get { return _theButton; }
            set
            { 
                _theButton = value;               

                //set text binding
                Binding textBind = new Binding("Text");
                textBind.Source = this;
                textBind.Mode = BindingMode.OneWay;
                _theButton.SetBinding(Button.ContentProperty, textBind);

                //set color binding
                Binding colorBind = new Binding("Brush");
                colorBind.Source = this;
                colorBind.Mode = BindingMode.OneWay;
                _theButton.SetBinding(Button.ForegroundProperty, colorBind);

                NotifyPropertyChanged("TheButton"); 
            }
        }


        public void Set(string text, Brush brush)
        {
            this.Text = text;
            this.Brush = brush;
        }

        private string _text;
        public string Text
        {
            get { return _text; }
            set { _text = value; NotifyPropertyChanged("Text"); }
        }

        private Brush _brush;
        public Brush Brush
        {
            get { return _brush; }
            set { _brush = value; NotifyPropertyChanged("Brush"); }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        internal void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }

    public partial class MainWindow : Window
    {
        MyButton _myButton = new MyButton();

        public MainWindow()
        {
            InitializeComponent();

            //button1 is defined in XAML markup
            _myButton.TheButton = this.button1; 

            //or else this could be your callback, same thing really
            Thread t = new Thread(SetButton);
            t.Start();
        }

        void SetButton()
        {    
           _myButton.Text = "wo0t!";
           _myButton.Brush = Brushes.Red;

              //or
            _myButton.Set("giggidy!", Brushes.Yellow);
        }

    }   

}

Обратите внимание, что связывание ваших свойств Button в XAML гораздо менее уродливо, но тогда мы перейдем к UserControls и DataContexts, что является другой темой. Я бы посмотрел на наследование класса Button для реализации нужных вам функций.

...