Есть следующий код XAML:
<TreeView x:Name="MyTreeitems" ItemsSource="{Binding Path=Items}" FontSize="12" FontWeight="Normal">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local2:TreeModel}" ItemsSource="{Binding Path=RelatedItems}">
<StackPanel Orientation="Horizontal">
<Image x:Name="nodeImg" Width="16" Height="16" Source="{Binding CollapsedImageSource}" />
<TextBlock Margin="2,0,0,0" Text="{Binding Name}"/>
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=SubItems}">
<StackPanel Orientation="Horizontal">
<Image x:Name="nodeImg" Width="16" Height="16" Source="{Binding CollapsedImageSource}" />
<TextBlock Margin="2,0,0,0" Text="{Binding Name}" />
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=SubsubItems}">
<StackPanel Orientation="Horizontal">
<Image x:Name="nodeImg" Width="16" Height="16" Source="{Binding CollapsedImageSource}" />
<TextBlock Margin="2,0,0,0" Text="{Binding Name}" />
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" MouseDown="lbCarotages_PreviewMouseDown">
<Image x:Name="nodeImg" Width="16" Height="16" Source="{Binding LeftImageSource}" />
<TextBlock Text="{Binding Path=Description}"/>
<Image Width="16" Margin="0 0 5 0" Source="{Binding Path=Name, ConverterParameter=Curve, Converter={StaticResource convCurveDefinedToImage}}"/>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.Resources>
Формирую Items = new ObservableCollection();
TreeModel:
public class TreeModel : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value;
OnPropChng("Name");
}
}
public string Description { get; set; }
public BitmapImage CollapsedImageSource { get; set; }
public BitmapImage ExpandedImageSource { get; set; }
private readonly ObservableCollection<TreeModel1> _relatedItems = new ObservableCollection<TreeModel1>();
public ObservableCollection<TreeModel1> RelatedItems
{
get { return _relatedItems; }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropChng(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
public class TreeModel1
{
public string Name { get; set; }
public string Description { get; set; }
public BitmapImage CollapsedImageSource { get; set; }
public BitmapImage ExpandedImageSource { get; set; }
private readonly ObservableCollection<TreeModel2> _subItems = new ObservableCollection<TreeModel2>();
public ObservableCollection<TreeModel2> SubItems
{
get
{
return _subItems;
}
}
}
public class TreeModel2
{
public string Name { get; set; }
public string Description { get; set; }
public BitmapImage CollapsedImageSource { get; set; }
public BitmapImage ExpandedImageSource { get; set; }
private readonly ObservableCollection<TreeModel3> _subsubItems = new ObservableCollection<TreeModel3>();
public ObservableCollection<TreeModel3> SubsubItems
{
get
{
return _subsubItems;
}
}
}
public class TreeModel3
{
public string Name { get; set; }
public BitmapImage LeftImageSource { get; set; }
public string Description { get; set; }
public bool IsDefined { get; set; }
}
Тогда дерево отображается идеально.
Но когда меняю что-нить в Items, элементарно Items[0].Name = "новое наименование" TreeView не изменяется.
Не могу разобраться что к чему.
Хорошим дополнением к ответам о реализации INotifyPropertyChanged
на моделях будет совет о задании значений свойств в сеттере через метод SetProperty
, как это сделано в Prism.
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
RaisePropertyChanged(propertyName);
return true;
}
Идея в том, чтобы пробрасывать событие изменения свойства только в случае его реального изменения (а не по факту вызова сеттера). В самом деле, в некоторых случаях лишние вызовы события могут создавать лаги интерфейса.
Пример использования:
public object Prop
{
get
{
return _prop;
}
set
{
SetProperty(ref _prop, value);
}
}
наследуем классы от интерфейса INotifyPropertyChanged
добавляем event public event PropertyChangedEventHandler PropertyChanged;
и метод
protected bool NotifiyPropertyChanged<T>(ref T oldValue, T newValue, [CallerMemberName]string property = "")
{
if (oldValue == null && newValue == null) return false;
if (oldValue != null && newValue != null)
if (oldValue is byte[] && newValue is byte[])
if ((oldValue as byte[]).Count() == (newValue as byte[]).Count())
if ((newValue as byte[]).SequenceEqual((oldValue as byte[])))
return false;
if (!(oldValue is byte[]) || !(newValue is byte[]))
if (Equals(oldValue, newValue))
return false;
oldValue = newValue;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
return true;
}
при изменении любого из свойств вызывать его. Например:
protected string m_Name = "";
public string Name {
get {return m_Name; }
set { NotifiyPropertyChanged(ref m_Name, value); }
}
в Вашем случае не все классы наследуются от интерфейса INotifyPropertyChanged
UPD: спасибо Gardes за CallerMemberName
UPD: dm.dymov за <T>
UPD: Добавлен Equals для byte[]
Дополнение к ответу @Дмитрий Чистик
Еще одна реализация интерфейса INotifyPropertyChanged, более удобная. Не приходиться заботится о передаче имени свойства в метод и соблюдении правильности написания.
public class BaseVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Использовать так:
public class TreeModelVM : BaseVM
{
private string _name = string.Empty;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged();
}
}
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Подскажите как можно решить данный кейс для iOS 9+, Android 44+ и WP 8
Доброго времени суток! Возник вопрос при экспорте чисел decimal в файл ExcelЗадача следующая: из базы в datagridview на форме записываются данные, потом...
Необходимо инициализировать порядка 1000 таймеровКаждый таймер должен обрабатывать свой метод, метод в аргументе принимает грубо говоря...