views:

181

answers:

1

I have the following class (abreviated for simplicity). The app it multi-threaded so the Set and Get are a bit more complicated but should be ok.

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);
        }
        //
    }
}

}

Next I have my main form as the following:

<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>

As you can see I set the DataContext to FeedEngine and Bind IsEnabled to Processing. I have also tested the boolConverter separately and it functions (just applies ! (Not) to a bool).

Here is my Main window code behind in case it helps to debug.

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();
        }

    }
}

Hope someone can see where I missed a step.

Thanks.

+1  A: 

The most obvious issue is that you're not using DependencyProperty correctly. For any DependencyProperty the wrapper property should stick to the boilerplate calls to GetValue and SetValue and never contain other code. The primary reason for this is that some usage scenarios (including XAML) only use the wrapper property as an indicator that the property can be accessed (try removing it) and the actual get/set instead make direct calls to GetValue/SetValue. Any additional actions that would normally be done in a setter should be put into a PropertyChanged handler attached as an additional parameter in the Register call.

It looks like what you want is to set Processing from your background thread and read it from the binding in the UI. Since a DependencyProperty is owned by its creating thread (in this and most cases the UI thread) you'll need that Dispatcher.BeginInvoke code when setting the value but it should be moved somewhere else - like into Poll(). The same would be true if you were using INotifyPropertyChanged instead of a DependencyObject, which you could do based on the code here.

John Bowen
Made the change and still no difference. The property on the button never changes. Here is an example of the change in poll public void Poll() { while (Running) { this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { Processing = true; }));and of course I removed the Dispatcher.Invoke calls from the property get and set itself.
Robert Ross