我有以下课程(为了简单而省略)。它是多线程的应用程序,所以Set和Get有点复杂,但应该没问题。
namespace News.RSS
{
public class FeedEngine : DependencyObject
{
public static readonly DependencyProperty _processing = DependencyProperty.Register("Processing", typeof(bool), typeof(FeedEngine), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender));
public bool Processing
{
get
{
return (bool)this.Dispatcher.Invoke(
DispatcherPriority.Normal, (DispatcherOperationCallback)delegate { return GetValue(_processing); }, Processing);
}
set
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(SendOrPostCallback)delegate { SetValue(_processing, value); },
value);
}
}
public void Poll()
{
while (Running)
{
Processing = true;
//Do my work to read the data feed from remote source
Processing = false;
Thread.Sleep(PollRate);
}
//
}
}
}
接下来,我的主要表格如下:
<Window x:Class="News.Main"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converter="clr-namespace:News.Converters"
xmlns:local="clr-namespace:News.Lookup"
xmlns:rss="clr-namespace:News.RSS"
Title="News" Height="521" Width="927" Initialized="Window_Initialized" Closing="Window_Closing" >
<Window.Resources>
<ResourceDictionary>
<converter:BooleanConverter x:Key="boolConverter" />
<converter:ArithmeticConverter x:Key="arithConverter" />
...
</ResourceDictionary>
</Window.Resources>
<DockPanel Name="dockPanel1" SnapsToDevicePixels="False" >
<ToolBarPanel Height="37" Name="toolBarPanel" Orientation="Horizontal" DockPanel.Dock="Top" >
<ToolBarPanel.Children>
<Button DataContext="{DynamicResource FeedEngine}" HorizontalAlignment="Right" Name="btnSearch" ToolTip="Search" Click="btnSearch_Click" IsEnabled="{Binding Path=Processing, Converter={StaticResource boolConverter}}">
<Image Width="32" Height="32" Name="imgSearch" Source="{Resx ResxName=News.Properties.Resources, Key=Search}" />
</Button>
...
</DockPanel>
</Window>
如您所见,我将DataContext设置为FeedEngine并将IsEnabled绑定到Processing。我也分别测试了boolConverter并且它起作用(只适用于!(不)到bool)。
这是我的主窗口代码,以防它有助于调试。
namespace News
{
/// <summary>
/// Interaction logic for Main.xaml
/// </summary>
public partial class Main : Window
{
public FeedEngine _engine;
List<NewsItemControl> _newsItems = new List<NewsItemControl>();
Thread _pollingThread;
public Main()
{
InitializeComponent();
this.Show();
}
private void Window_Initialized(object sender, EventArgs e)
{
// Load current Feed data.
_engine = new FeedEngine();
ThreadStart start = new ThreadStart(_engine.Poll);
_pollingThread = new Thread(start);
_pollingThread.Start();
}
}
}
希望有人能看到我错过了哪一步。
感谢。
答案 0 :(得分:1)
最明显的问题是您没有正确使用DependencyProperty。对于任何DependencyProperty,包装器属性应该坚持对GetValue和SetValue的样板调用,并且永远不会包含其他代码。这样做的主要原因是某些使用场景(包括XAML)仅使用包装器属性作为可以访问属性的指示符(尝试删除它),而实际的get / set则直接调用GetValue / SetValue。通常在setter中执行的任何其他操作都应放入PropertyChanged处理程序中,作为Register调用中的附加参数附加。
看起来你想要的是从后台线程设置Processing并从UI中的绑定中读取它。由于DependencyProperty由其创建线程拥有(在这个和大多数情况下是UI线程),因此在设置值时需要使用Dispatcher.BeginInvoke代码,但是应该将其移动到其他地方 - 比如Poll()。如果您使用的是INotifyPropertyChanged而不是DependencyObject,则可以这样做,您可以根据此处的代码执行此操作。