Search code examples
c#wpfdata-bindingwpf-controlslistboxitem

How to bind the IsEnabled Property of a WPF ListBoxItem to a Property of its Source Item?


I have a ListBox with an ObservableCollection as ItemSource:

public partial class HomePage : Page
{
    public ObservableCollection<DaemonFile> Files { get; private set; }
    private readonly MainWindow MainWindow;

    public HomePage(MainWindow MainWindow)
    {
        Files = new ObservableCollection<DaemonFile>();

        this.MainWindow = MainWindow;

        InitializeComponent();

        ListOfFiles.ItemsSource = Files;
    }
    ...
}

I have the following properties in my DaemonFile:

public class DaemonFile : INotifyPropertyChanged
{
    public enum ProcessStates : int
    {
        CREATED = 0,
        CONVERTED = 1,
        UPLOADING = 2,
        FINISHED = 3
    }
    private ProcessStates ProcessStateValue = ProcessStates.CREATED;
    public ProcessStates ProcessState 
    { 
        get { return this.ProcessStateValue; } 
        set 
        {
           if (value != this.ProcessStateValue)
           {
               this.ProcessStateValue = value;
               NotifyPropertyChanged();
           }
        } 
     }
    ...
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            mainWindow.WriteLine("Property " + propertyName + " Changed!");
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        } else
        {
            mainWindow.WriteLine("Cant fire event!");
        }
    }
}

The ProcessState gets updated asynchronously after the conversion of the file has finished.
I figured I need to bind this property and put it into a setter for IsEnabled.

        <Style x:Key="Item" TargetType="{x:Type ListBoxItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Grid Background="{TemplateBinding Background}">
                            <ContentPresenter 
                                    ContentTemplate="{TemplateBinding ContentTemplate}"
                                    Content="{TemplateBinding Content}"
                                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                    Margin="{TemplateBinding Padding}">
                            </ContentPresenter>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding ProcessState}" Value="0">
                    <Setter Property="IsEnabled" Value="False"/>
                </DataTrigger> 
            </Style.Triggers>
        </Style>   

How can I achieve that whenever a DaemonFile changes its ProcessState to 1 or higher the corresponding ListBoxItem switches to enabled?

  • I don't want a user to be able to upload a file before it has finished converting

I could also add an isEnabled property to my DaemonFile to simplify things a little. That doesn't solve my binding problem though.


Solution

  • You do not need that ControlTemplate.

    A simple DataTrigger should work:

    <Style x:Key="ItemStyle" TargetType="{x:Type ListBoxItem}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding ProcessState}" Value="0">
                <Setter Property="IsEnabled" Value="False"/>
            </DataTrigger>
        </Style.Trigers>
    </Style>
    

    Just in case:

    <ListBox x:Name="ListOfFiles"
             ItemContainerStyle="{StaticResource ItemStyle}" ...>