WFP:如何正确地将DependencyProperty绑定到GUI

时间:2010-05-04 02:13:12

标签: wpf dynamic binding dependency-properties

我有以下课程(为了简单而省略)。它是多线程的应用程序,所以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();
        }

    }
}

希望有人能看到我错过了哪一步。

感谢。

1 个答案:

答案 0 :(得分:1)

最明显的问题是您没有正确使用DependencyProperty。对于任何DependencyProperty,包装器属性应该坚持对GetValue和SetValue的样板调用,并且永远不会包含其他代码。这样做的主要原因是某些使用场景(包括XAML)仅使用包装器属性作为可以访问属性的指示符(尝试删除它),而实际的get / set则直接调用GetValue / SetValue。通常在setter中执行的任何其他操作都应放入PropertyChanged处理程序中,作为Register调用中的附加参数附加。

看起来你想要的是从后台线程设置Processing并从UI中的绑定中读取它。由于DependencyProperty由其创建线程拥有(在这个和大多数情况下是UI线程),因此在设置值时需要使用Dispatcher.BeginInvoke代码,但是应该将其移动到其他地方 - 比如Poll()。如果您使用的是INotifyPropertyChanged而不是DependencyObject,则可以这样做,您可以根据此处的代码执行此操作。