我有一些问题,当按钮从另一个线程更改时,WPF没有完全重新绘制按钮控件,我不知道如何强制它进行完全重绘。
情况是收到消息后(通过WCF - 但源不重要,除了它是一个外部线程)我更新前景颜色和按钮的可见性。 WPF立即重新绘制按钮面上的文本,但在我单击应用程序的任何位置之前,按钮的表面不会重新绘制。
我尝试在按钮上调用InvalidateVisual(),但这没有帮助。我认为我不理解后台线程如何强制重绘。但令人沮丧的是,当我从同一个消息收据中更新它们时,某些内容正在重新粉刷,而我正在使用的所有其他控件(文本和图像控件)也会得到正确的重新绘制。
我现在尝试通过Invoke()向应用程序的Dispatcher发送一条空消息,但是也没有运气。
所以我正在寻找有关如何告诉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”功能,它就会起作用。
答案 0 :(得分:0)
从代码中设置按钮本身的属性,特别是另一个线程/回调,是进入一个不稳定状态的痛苦世界的入口。
您应该做的是将按钮的属性绑定到代码中的属性,然后让回调更改这些外部属性。
我知道你发布的代码有点模仿你在程序中真正想要做的事情,而且我无法真正遵循你的逻辑,但是这里有一个完整的程序,它的运行方式类似于你的例子,并显示了什么我在说。如果我错过了标记,请告诉我。
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);
}
}
}
请注意,在XAML中绑定Button属性要简单得多,但接下来我们将进入另一个主题UserControls和DataContexts。我会看一下继承Button类来实现你想要的功能。
答案 1 :(得分:0)
我建议阅读MSDN杂志上的文章(Build More Responsive Apps With The Dispatcher),该文章介绍了在使用BackgroundWorker时WPF如何与Dispatcher配合使用。
答案 2 :(得分:0)
根据我的编辑,我在XAML中的按钮CanExecute绑定和我在回调中设置背景颜色之间存在冲突。我真的不需要CanExecute,所以摆脱它解决了我的问题。