WFP: Как правильно привязать DependencyProperty к графическому интерфейсу - PullRequest
0 голосов
/ 04 мая 2010

У меня есть следующий класс (сокращено для простоты). Приложение многопоточное, так что 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 и Bind 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 Ответ

1 голос
/ 04 мая 2010

Наиболее очевидная проблема заключается в том, что вы не используете DependencyProperty правильно. Для любого DependencyProperty свойство оболочки должно соответствовать шаблонным вызовам GetValue и SetValue и никогда не содержать другого кода. Основная причина этого заключается в том, что в некоторых сценариях использования (включая XAML) свойство оболочки используется только в качестве индикатора того, что к свойству можно получить доступ (попробуйте удалить его), а фактическое получение / установка вместо этого делает прямые вызовы GetValue / SetValue. Любые дополнительные действия, которые обычно выполняются в установщике, должны быть помещены в обработчик PropertyChanged, присоединенный как дополнительный параметр в вызове Register.

Похоже, что вы хотите установить обработку из фонового потока и прочитать ее из привязки в пользовательском интерфейсе. Поскольку DependencyProperty принадлежит его потоку создания (в этом и большинстве случаев в потоке пользовательского интерфейса), вам потребуется этот код Dispatcher.BeginInvoke при установке значения, но его следует переместить куда-нибудь еще - например, в Poll (). То же самое было бы верно, если бы вы использовали INotifyPropertyChanged вместо DependencyObject, что вы можете сделать на основе приведенного здесь кода.

...