User Interface Update with databind in WPF

I have a three layer tree view,

-MAIN
 ->: SUB1
   >: SUB2
   >: SUB2
 -X: SUB1
   X: SUB2
 SUB1
 SUB1

where,> and X represent graphs indicating the status of this particular element (determined from the backend).

I use the Observable dictionary to bind to this tree (and it has an ICollectionChanged event). The structure looks like this:


ObservableDictionary<string,CustomClass> mainitems;

public class CustomClass{
    ObservableDictionary<string, InnerClass> sub1item;
    // Bunch of properties and methods in this class
    // INotify not implemented
}

public class InnerClass{
    // Bunch of properties and methods in this class
    // INotify not implemented
    public SomeEnum Status{
        get{ return this.status; }
    }
}

The graphs mentioned above are bound using a custom converter that converts the state enumeration to a path so that it can be bound (i.e. <img source = "{Binding Path = something, Converter = {StaticResource someconverter}, Mode = OneWay "/>).

Question:

, CustomClass , . , INotify , , .

Edit: XAML :


<TreeView Name="tvInstance" ItemsSource="{Binding}" TreeViewItem.Selected="tviSelected" IsTextSearchEnabled="True">
    <TreeView.ItemContainerStyle>
        <Style>
            <Setter Property="TreeViewItem.IsExpanded" Value="{Binding Path=Value.Expanded, Mode=TwoWay}" />
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Path=Value.CustomClass}" ItemContainerStyle="{x:Null}">
                <StackPanel Orientation="Horizontal">
                <Label Content="{Binding Path=Key}"/>
            </StackPanel>
            <HierarchicalDataTemplate.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Path=Value.AnotherClass}">
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Path=Value.Status, Converter={StaticResource convertstatus} }"
                            Width="10" Height="10"/>
                        <Label Content="{Binding Path=Key}" />
                    </StackPanel>
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Path=Value, Converter={StaticResource convertstatus} }"
                            Width="10" Height="10"/>
                                <Label Content="{Binding Path=Key}" />
                            </StackPanel>
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

EDIT: INotifyProperty , CustomClass InnerClass, . ObservableDictionary WPF ( , ). !

, INotifyPropertyChanged , .

, , ObservableCollection . ( , O (n)).

, .

+3
5

, :

public class CustomClass : INotifyPropertyChanged
{
  public CustomClass()
  {
    sub1item = new ObservableDictionary<string, InnerClass>();
    // This next line may not be necessary... Changes might propogate up.
    sub1item.CollectionChanged += () => NotifyPropertyChange("Sub1Item");
  }

  private ObservableDictionary<string, InnerClass> sub1item;
  public ObservableDictionary<string, InnerClass> Sub1Item
  {
    get { return sub1item; }
    private set { sub1item = value; NotifyPropertyChange("Sub1Item"); }
  }

  public event PropertyChangedEventHandler PropertyChanged;

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

public class InnerClass : INotifyPropertyChanged
{
  public SomeEnum Status
  {
    get { return this.status; }
    private set { this.status = value; NotifyPropertyChange("Status"); }
  }

  public event PropertyChangedEventHandler PropertyChanged;

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

, , Status = something, this.status

: , , , . , , Sub1Item , , , . .

DataTemplate CustomClass, Sub1Item,

<DataTemplate DataType="{x:Type myClrNamespace:InnerClass}">
    <Grid>
        <TextBlock Text={Binding Path=Status}/>
    </Grid>
</DataTemplate>
...
<ListBox x:Name="listStatus"/>

# - : listStatus = mainlist[0].Sub1Item; TreeView ItemTemplate, .

+1

INofityCollectionChanged, WPF .

INotifyPropertyChanged.

  • , , , WPF , .

...

// Should implement INotifyPropertyChanged if the dictionary itself
// can be changed and not only its items
public class CustomClass {
    ObservableDictionary sub1item;
    // Bunch of properties and methods in this class
    // INotify not implemented
}


public class InnerClass : INotifyProperyChanged {
    // Bunch of properties and methods in this class
    // INotify not implemented
    public SomeEnum Status{
        get{ return this.status; }
    }

    public event PropertyChangedEventHandler PropertyChanged;



protected void NotifyPropertyChanged(string propertyName)
{
    if(PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}


// where ever this.status is changed directly,
// call NotifyPropertyChanged("Status")
// (at end of that method)
//
// if this.status is changed from outside class (if public),
// then add a public method NotifyStatusChanged() which calls
// NotifyPropertyChanged("Status")
//
// If Status property has a set{} then if new value != this.status,
// call NotifyPropertyChanged("Status") at end of setter

}
+1

, INotifyPropertyChanged, :

public class InnerClass: INotifyPropertyChanged
{
     private string _propertyName;

     //Implemented from INotifyPropertyChanged
     public event PropertyChangedEventHandler PropertyChanged;

     public string PropertyName
     {
        get { return _propertyName; }
        set 
        { 
              _propertyName = value;
              OnPropertyChanged("Name or Property Data"); 
        }
     }

     //Just using string as an example, send whatever data you'd like
     protected void PropertyChanged(string name)
     {
        //Check to make sure the event is wired.
        if(PropertyChanged != null)
        {
              //Fire event
              PropertyChanged(this, name);
        }
     }
}

, CustomClass. , , CustomClass , .

0

ObservableDictionary (Of TKey, TValue) - VB.NET

:

  • ObservableDictionary (Of TKey, TValue)
  • AddRange .
  • Generic EventArgs (Of TKey, TValue)
  • NotifyDictionaryChanging (Of ​​TKey, TValue) - CancelEventArgs, .
0
source

working example for a class like "Task"

public class Task: INotifyPropertyChanged

{

    //Implemented from INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

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

private line text;

    public string Text
    {
        get { return text; }
        set { 
            text = value;
            NotifyPropertyChanged("Text");

            }
    }

}

On the side of the note, it's worth remembering that you need to use a raervan ObservableCollection than a List to get the ItemSource dynamically updated when binding data to a set of types. The list does not notify.

0
source

Source: https://habr.com/ru/post/1710591/


All Articles