Когда Вы видите '... Еще 113', который означает, что остающиеся строки 'вызванный' исключением идентичны остающимся строкам от той точки на родительского исключения.
, Например, Вы будете иметь
com.something.XyzException
at ...
at ...
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:242)
at ... <the other 113 lines are here>...
Caused by: <the above>.
, Эти два отслеживания стека 'встречаются' в AbstractBatcher.executeBatch, строка 242, и затем с тех пор восходящая трассировка вызовов совпадает с переносящимся исключением.
Да для скаляров, нет для коллекций. Для коллекций вам понадобится специализированная коллекция, которая будет маршалирована для вас, или вручную маршалируется в поток пользовательского интерфейса самостоятельно через Dispatcher
.
Возможно, вы читали, что INotifyCollectionChanged.CollectionChanged
должен запускаться в потоке пользовательского интерфейса, потому что это просто неверно для INotifyPropertyChanged.PropertyChanged
. Ниже приведен очень простой пример, который доказывает, что WPF упорядочивает изменения свойств.
Window1.xaml.cs :
using System.ComponentModel;
using System.Threading;
using System.Windows;
namespace WpfApplication1
{
public partial class Window1 : Window
{
private CustomerViewModel _customerViewModel;
public Window1()
{
InitializeComponent();
_customerViewModel = new CustomerViewModel();
DataContext = _customerViewModel;
var thread = new Thread((ThreadStart)delegate
{
while (true)
{
Thread.Sleep(2000);
//look ma - no marshalling!
_customerViewModel.Name += "Appended";
_customerViewModel.Address.Line1 += "Appended";
}
});
thread.Start();
}
}
public abstract class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class CustomerViewModel : ViewModel
{
private string _name;
private AddressViewModel _address = new AddressViewModel();
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
OnPropertyChanged("Name");
}
}
}
public AddressViewModel Address
{
get { return _address; }
}
}
public class AddressViewModel : ViewModel
{
private string _line1;
public string Line1
{
get { return _line1; }
set
{
if (_line1 != value)
{
_line1 = value;
OnPropertyChanged("Line1");
}
}
}
}
}
Window1.xaml :
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBox Text="{Binding Name}"/>
<TextBox Text="{Binding Address.Line1}"/>
</StackPanel>
</Window>
Я считаю, что с 2.0 и предыдущими версиями .NET вы бы получили InvalidOperationException из-за сходства потоков при выполнении вышеупомянутого примера (ссылка, размещенная bitbonk, датирована 2006 годом).
Теперь, в версии 3.5, кажется, что WPF выполняет маршалинг изменений свойств фонового потока в диспетчере за вас.
Короче говоря, все зависит от того, на какую версию .NET вы нацеливаетесь. Надеюсь, это проясняет любую путаницу.
Один из моих коллег по Lab49 писал об этом в 2007 году здесь: