private ObservableCollection<string> _memLogEvents;
public ObservableCollection<string> MemLogEvents
{
get { return _memLogEvents; }
set
{
_memLogEvents = value;
OnPropertyChanged(nameof(MemLogEvents));
}
}
// .... Some code hereprivate void GetMemLogEvent(object sender, MemLogEventArgs eventArgs)
{
MemLogEvents.Add(eventArgs.Log);
OnPropertyChanged(nameof(MemLogEvents));
}
GetMemLogEvent вызывается на каждуб новую строку в логе
Все работает, но есть два вопроса:
— Из сеттера метод OnPropertyChanged никогда не вызывается, навсолько я понимаю. Присваивание там идет только раз. Из GetMemLogEvent этот же метод вызывается постоянно. Если убрать OnPropertyChanged отовсюду логи так и продолжают появляться в ListBox. Откуда ListBox берет уведомление о изиенившемся содержимом?
— Как настроить, чтобы ListBox автоматом скроллился вниз до упора? Я попробовал использовать Extender для ListBox, что нашел, но безрезультатно.
Здравствуйте, RainBoy, Вы писали: RB> — Из сеттера метод OnPropertyChanged никогда не вызывается, навсолько я понимаю. Присваивание там идет только раз. Из GetMemLogEvent этот же метод вызывается постоянно. Если убрать OnPropertyChanged отовсюду логи так и продолжают появляться в ListBox. Откуда ListBox берет уведомление о изиенившемся содержимом?
Потому, что OnPropertyChanged не имеет отношения к добавлению/удалению элементов. Этим занимается INotifyCollectionChanged, который реализуеся в ObservableCollection
RB> — Как настроить, чтобы ListBox автоматом скроллился вниз до упора? Я попробовал использовать Extender для ListBox, что нашел, но безрезультатно.
Я бы попробовал вызывать ScrollIntoView, когда нужно.
Re[2]: WPF - Почему работает без OnPropertyChanged?
V>Потому, что OnPropertyChanged не имеет отношения к добавлению/удалению элементов. Этим занимается INotifyCollectionChanged, который реализуеся в ObservableCollection
Я менял ObservableCollection на обычный List, который не реализует INotifyCollectionChanged — тот же результат, все работает.
V>Я бы попробовал вызывать ScrollIntoView, когда нужно.
Спасибо, посмотрю
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[3]: WPF - Почему работает без OnPropertyChanged?
Здравствуйте, RainBoy, Вы писали:
RB> Я менял ObservableCollection на обычный List, который не реализует INotifyCollectionChanged — тот же результат, все работает.
И при этом не вызывали OnPropertyChanged(nameof(MemLogEvents)) и всё работало? Тогда не знаю
Re[4]: WPF - Почему работает без OnPropertyChanged?
Здравствуйте, RainBoy, Вы писали:
RB> — Из сеттера метод OnPropertyChanged никогда не вызывается, навсолько я понимаю. Присваивание там идет только раз. Из GetMemLogEvent этот же метод вызывается постоянно. Если убрать OnPropertyChanged отовсюду логи так и продолжают появляться в ListBox. Откуда ListBox берет уведомление о изиенившемся содержимом?
ItemsSource="{Binding MemLogEvents}"
ListBox привязан к полю MemLogEvents вашего ViewModel, а не к экземпляру объекта ViewModel. Поэтому при добавлении элемента в него (MemLogEvents), там "внутри ObservableCollection" срабатывает свой OnPropertyChanged, которое и приводит к обновлению ListBox. Пойдет такая версия?
Re[2]: WPF - Почему работает без OnPropertyChanged?
L> ListBox привязан к полю MemLogEvents вашего ViewModel, а не к экземпляру объекта ViewModel. Поэтому при добавлении элемента в него (MemLogEvents), там "внутри ObservableCollection" срабатывает свой OnPropertyChanged, которое и приводит к обновлению ListBox. Пойдет такая версия?
Не совсем понимаю, где это "там внутри".
Да и если поменять Observable на обычный List<> все продолжает работать.
Я только разбираюсь, для меня это непонятно.
Здравствуйте, RainBoy, Вы писали:
RB> — Из сеттера метод OnPropertyChanged никогда не вызывается, навсолько я понимаю. Присваивание там идет только раз. Из GetMemLogEvent этот же метод вызывается постоянно. Если убрать OnPropertyChanged отовсюду логи так и продолжают появляться в ListBox. Откуда ListBox берет уведомление о изиенившемся содержимом?
Про ObservableCollection уже объяснили, а про List<T> верится с трудом. Тут лучше полные исходники с примером кинуть.
RB> — Как настроить, чтобы ListBox автоматом скроллился вниз до упора? Я попробовал использовать Extender для ListBox, что нашел, но безрезультатно.
Binding в WPF не работает со списками напрямую, а использует абстракцию ICollectionView. Под капотом каждая прибиндинная коллекция получает свой collection view. Его можно запросить, вызвав GetDefaultView. При помощи collection view можно управлять UI списка из view model без привязки к конкретному типу контрола. Для этого надо устанавливать CurrentItem, используя любой из методов MoveCurrentTo*. В твоем случае вроде подходит MoveCurrentToLast. Правда, я советую, если нужно явное управление текущим элементом, стоит сразу делать свойство с типом ICollectionView, а в модели обернуть List через ListCollectionView.
Re[2]: WPF - Почему работает без OnPropertyChanged?
Здравствуйте, MxMsk, Вы писали:
MM>Здравствуйте, RainBoy, Вы писали:
RB>> постоянно. Если убрать OnPropertyChanged отовсюду логи так и продолжают появляться в ListBox. Откуда ListBox берет уведомление о изиенившемся содержимом? MM>Про ObservableCollection уже объяснили, а про List<T> верится с трудом. Тут лучше полные исходники с примером кинуть.
using Esri.ArcGISRuntime;
using System;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using ICC.Common;
using ICC.RunManager.ViewModels;
namespace ICC.RunManager
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// datacontext assigned in XAML
//MainWindowViewModel viewModel = new MainWindowViewModel();
//this.DataContext = viewModel;
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICC.Common;
namespace ICC.RunManager.ViewModels
{
class MainWindowViewModel: BaseViewModel
{
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly Logger _logger;
private List<string> _memLogEvents;
public List<string> MemLogEvents
{
get { return _memLogEvents; }
set
{
_memLogEvents = value;
//OnPropertyChanged(nameof(MemLogEvents));
}
}
/// <summary>
/// Default constructor
/// </summary>
public MainWindowViewModel()
{
_logger = Logger.GetInstance();
// subscribe viewModel to the log events
_logger.MemLog += this.GetMemLogEvent;
// init log collection
_memLogEvents = new List<string>();
// grab all previous logs
List<MemLogEventArgs> memLogList = _logger.GetMemLogList(true);
foreach (var memLogItem in memLogList)
{
this.GetMemLogEvent(this, memLogItem);
}
}
private void GetMemLogEvent(object sender, MemLogEventArgs eventArgs)
{
MemLogEvents.Add(eventArgs.Log);
OnPropertyChanged(nameof(MemLogEvents));
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICC.Common;
namespace ICC.RunManager.Classes
{
public class BaseClass
{
private readonly Logger _logger = Logger.GetInstance();
private readonly AppHelper _appHelper = new AppHelper();
public void Run()
{
_logger.WriteLine("");
_logger.WriteLine("****************************************************************************************");
_logger.WriteLine("* *");
_logger.WriteLine("* Application started *");
_logger.WriteLine("* ICC Run Manager *");
_logger.WriteLine("* *");
_logger.WriteLine("****************************************************************************************");
_logger.WriteLine("");
_logger.WriteLine("Application Name: " + _appHelper.GetApplicationName() + ".exe ver. " + _appHelper.GetApplicationVersionInfo().ProductVersion);
_logger.WriteLine("Run Path: " + AppSettings.ApplicationPath);
_logger.WriteLine("");
}
public void Close()
{
_logger.WriteLine("");
_logger.WriteLine("****************************************************************************************");
_logger.WriteLine("* *");
_logger.WriteLine("* Application terminated *");
_logger.WriteLine("* *");
_logger.WriteLine("****************************************************************************************");
_logger.WriteLine("");
_logger.CloseLogFile();
}
}
}
Комментируя все OnPropertyChanged все равно работает