简体   繁体   中英

Bind INotifyPropertyChanged class as Property in another class

I have a class that has a fairly long running process that I want the GUI to give progress on.

The class has a property called Progress that is a class implementing INotifyPropertyChanged. I'm using a BusyWorker and bind the class's Progress property to it's datacontext, but whenever the progress changes the BusyWorker does not show anything. I don't know if I'm making any sense here, so here's some code:

The class in question:

public class MyClass
{
  public Progress MyProgress { get; set; }

  public void Run()
  {
    MyProgress = new Progress();
    MyProgress.Status = "Initialising";
    // Do stuff, update progress, etc.
  }
}

public class Progress : INotifyPropertyChanged
{
  private string status;

  public string Status
  {
    get { return status; }
    set
    {
      status = value;
      OnPropertyChanged("Status");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

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

XAML:

// ...
<xctk:BusyIndicator HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="busyIndicator" VerticalAlignment="Stretch" BusyContent="{Binding}">
    <xctk:BusyIndicator.BusyContentTemplate>
        <DataTemplate>
            <StackPanel Margin="4">
                <TextBlock Text="{Binding Status}" FontWeight="Bold" HorizontalAlignment="Left"/>
            </StackPanel>
        </DataTemplate>
    </xctk:BusyIndicator.BusyContentTemplate>
</xctk:BusyIndicator>
// ...

XAML.CS:

MyClass test = new MyClass();
BusyIndicator.DataContext = test.MyProgress;
BusyIndicator.IsBusy = true;
test.Run();

If I run it like this, and stop at the OnPropertyChanged call, PropertChanged is always null. If I make a separate Progress object in my xaml.cs it works just fine, but I want my 'Run' method to handle this. Is this even possible?

The Problem is you are assigning Data Context before calling the run method which means by the time you are assigning data context "MyProgress" Object is "Null".. so data context is null before calling the "Run" method.. you are calling the Run method which creates an instance for "MyProgress" but since your "MyClass" is not "INotifyPropertyChanged" its not able to notify the data context change...

Solution is: Try creating MyProgress instance in the constructor of MyClass.. so by the time of assigning data context will not be null and the in the run method don't create any instance just update the status property..

Something like this

public class MyClass
{
  public Progress MyProgress { get; set; }

  public MyClass()
  {
    MyProgress = new Progress();
  }

  public void Run()
  {    
    MyProgress.Status = "Initialising";
    // Do stuff, update progress, etc.
  }
}
<xctk:BusyIndicator HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="busyIndicator" VerticalAlignment="Stretch" BusyContent="{Binding}">
<xctk:BusyIndicator.BusyContentTemplate>
    <DataTemplate>
        <StackPanel Margin="4">
            <TextBlock Text="{Binding Path=Status}" FontWeight="Bold" HorizontalAlignment="Left" DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=BusyIndicator}}"/>
        </StackPanel>
    </DataTemplate>
</xctk:BusyIndicator.BusyContentTemplate>

// ...

This works for me:

*.xaml

<xctk:BusyIndicator HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="busyIndicator" VerticalAlignment="Stretch" IsBusy="True">
                <xctk:BusyIndicator.BusyContentTemplate>
                    <DataTemplate>
                        <StackPanel Margin="4">
                            <TextBlock Text="{Binding Path=Test.MyProgress.Status, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" FontWeight="Bold" HorizontalAlignment="Left"/>
                        </StackPanel>
                    </DataTemplate>
                </xctk:BusyIndicator.BusyContentTemplate>
            </xctk:BusyIndicator>

*.xaml.cs:

public partial class MainWindow : Window
{
    public MyClass Test { get; set; }

    public MainWindow()
    {
        Test = new MyClass();
        InitializeComponent();
        Test.Run();
    }
}

public class MyClass
{
    public Progress MyProgress { get; set; }

    public void Run()
    {
        MyProgress = new Progress();
        MyProgress.Status = "Initialising";
        // Do stuff, update progress, etc.
    }
}

public class Progress : INotifyPropertyChanged
{
    private string status;

    public string Status
    {
        get { return status; }
        set
        {
            status = value;
            OnPropertyChanged("Status");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM