views:

28

answers:

2

Is there any way that one can force databindings to be initialized on controls right after they are created?

My problem is that I've created a own UserControl derived control which must do some time consuming processing before it is shown. More exactly, create thumbnails of video media using the MediaPlayer component of .Net. I'm displaying my control in a custom made MenuItem control.

As it works now, the control gets initialized right before it is displayed (when a select the parent MenuItem), which starts the time consuming work and forcing me to display some kind of "processing item" information until the control has completed the work.

I need to find a way to make the databinding of filenames to execute as soon as the main window is shown instead of right before my control is displayed. Is it possible?

I've created a small app to demonstrate my problem:

Window1.xaml

<Window x:Class="TestBinding.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">

  <Window.Resources>
    <Style x:Key="MyMenuStyle" TargetType="MenuItem">
      <Setter Property="Header" Value="{Binding MenuHeader}"/>
    </Style>
  </Window.Resources>

  <Grid>
    <Menu>
      <MenuItem Header="Data">
        <MenuItem Header="Submenus" ItemsSource="{Binding SubMenus}" ItemContainerStyle="{StaticResource MyMenuStyle}" />
      </MenuItem>
    </Menu>
  </Grid>
</Window>

Window1.xaml.cs

using System.Collections.ObjectModel;
using System.Windows;

namespace TestBinding
{
  public partial class Window1 : Window
  {
    public Window1()
    {
       InitializeComponent();
       DataContext = new BindingViewModel();
    }
  }

  class BindingViewModel
  {
    public ObservableCollection<MyMenuItems> SubMenus { get; set; }

    public BindingViewModel()
    {
      SubMenus = new ObservableCollection<MyMenuItems>();
      SubMenus.Add(new MyMenuItems("Menu 1"));
      SubMenus.Add(new MyMenuItems("Menu 2"));
      SubMenus.Add(new MyMenuItems("Menu 3"));
    }
  }

  public class MyMenuItems
  {
    private string _menuHeader;
    public string MenuHeader
    {
      get
      {
        return _menuHeader;
      }
      set
      {
        _menuHeader = value;
      }
    }

    public MyMenuItems(string header)
    {
      _menuHeader = header;
    }
  }
}

If you run this program and set a breakpoint on the line return _menuHeader; you will notice that this executes as you select the parent menu item. I would like the program to complete the bindings of the sub menu items as soon as possible after the main window is shown giving the program some time to process the values given by the binding property.

A: 

Have you tried PriorityBinding?

<PriorityBinding>
    <Binding Path="SlowestProperty" IsAsync="True" />
    <Binding Path="MediumSpeedProperty" IsAsync="True" />
    <Binding Path="FastestProperty" />
</PriorityBinding>

The Bindings are processed from top to bottom, so be sure to set the IsAsync property (to run those asynchronously) - otherwise, it will just hang on the first one until complete, then on the second one, and finally the third one, freezing the UI in the process. Put the bindings in slowest to fastest order (top to bottom) to kick them off in that order.

As values are returned, higher priority values replace lower priority values (but, not the other way around, should the "slowest" one return first).

Wonko the Sane
Thank you for the suggestion but this does not solve my problem. I've added some code to demostrate my problem. Do you have any more ideas?
The Squirrel
A: 

So what I understand the problem as is (in your example) the MenuHeader get property would have to calculate something that would take a few seconds, subsequently returning after it finishes the calculation?

If that is the case, what you could do is do the complicated calculation in the constructor of MyMenuItems and just cache the value for when the MenuHeader property is finally read. This will probably hang up your program at start up, and therefore you should in the constructor spawn a new thread for the loading of the cached property value.

Carrotman