scott lafoy
scott lafoy

Reputation: 1013

When does binding actually happen

On a popup window I have a checkbox.IsChecked bound to a model, but I want to check its state from the xaml code behind when the window is displayed. When checking the checkbox by name in the code behind from the windows loaded event it is not set yet. There are some UI specific things that I need to do and that is why I need to know what the checkboxes value is when the window opens and i cannot perform this from the model that the checkbox.IsChecked is bound to.

The property on the model is set long before the popup window is opened, so it is not an issue of the binding not being there. I figured that once the Loaded event fires the window would be ready to use bindings and all, but this does not seem to be the case.

Xaml:

<RefinedRibbonControls:RefinedRibbonGroup Header="Show Graphs">
                    <StackPanel x:Name="panelVisibilities">
                        <CheckBox Content="Show/hide" x:Name="myCheckBox"                                 
                                  IsChecked="{Binding Path=Processor.Model.IsItemVisible}"
                                  Click="GraphVisibilityClickEvent"
                                  HorizontalAlignment="Left"/>
...etc

Property on model:

public bool IsItemVisible
        {
            get { return _isItemVisible ; }
            set
            {
                if (_isItemVisible != value)
                {
                    _isItemVisible = value;
                    _propertyChanger.FirePropertyChanged(this, m => m.IsItemVisible);
                }
            }
        }

Event in Xaml codebehind:

private void WindowLoadedEvent(object sender, RoutedEventArgs e)
        {
            if(myCheckBox.IsChecked.Value)
            {
                // Do UI Related Stuff
            }
         }

The binding works fine and the values show up when the window is displayed, the problem is I cannot get the value of the binding in the window loaded event.

Edit: Possible solution I have found but I am not sure if its the best way. I called the following method from the constructor on the xaml code behind.

private void SetupInitialVisibility()
        {
            //Fire after everything is loaded.
            Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(() =>
            {
                IEnumerable<CheckBox> elements = this.panelVisibilities.Children.OfType<CheckBox>().ToList();
                foreach (CheckBox checkBox in elements)
                {
                    if (checkBox.IsChecked != null && checkBox.IsChecked.Value == false)
                    {
                        //Do work
                    }
                }


            }));
        }

found at: https://stackoverflow.com/a/1746975/1253746

Upvotes: 2

Views: 1900

Answers (2)

Mike Fuchs
Mike Fuchs

Reputation: 12319

DataBinding should precede the Loaded event I think.

When and how do you set your DataContext? And you are positive that the viewmodel property is already set?

The following works, try to align your code with this if possible.

Xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <Grid>
        <CheckBox x:Name="myCheckBox" IsChecked="{Binding IsItemVisible}" />
    </Grid>
</Window>

Code Behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        this.Loaded += MainWindow_Loaded;
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        if (myCheckBox.IsChecked.Value)
        {
            //...
        }
    }
}

ViewModel:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private bool isItemVisible;
    public bool IsItemVisible { get { return isItemVisible; } set { isItemVisible = value; OnPropertyChanged("IsItemVisible"); } }


    public ViewModel()
    {
        this.IsItemVisible = true;
    }

    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

enter image description here

Upvotes: 1

user180326
user180326

Reputation:

Data binding is not done synchronously, but it is delayed. Check this msdn page on dispatcher priorities. It is done at a lower priority than normal window messages, but before rendering.

You could invoke a method on yourself with a lower priority than is defined for databinding, in this method you should be able to safely read the data bound value.

I would still find this ugly. I'd rather subscribe directly to PropertyChanged and check for this property, or even better, rewrite your "UI related code" as a data binding.

P.S. If you start consuming events, be sure to unsubscribe, or you might get memory leaks.

Upvotes: 3

Related Questions