Simplifited solution graph. 当我尝试将ListViewItem添加到浏览器时,它会抛出System.InvalidOperationException:调用者无法访问对象,因为它属于另一个线程。
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddItems(string ID)
{
Browser.Dispatcher.Invoke(() =>
{
IEnumerable<ListViewItem> Items = Helper.GetCached(ID);
lock (((ICollection)Items).SyncRoot)
{
if (Items != null)
{
foreach (var Item in Items)
{
Browser.Items.Add(Item);//System.InvalidOperationException
}
}
}
});
}
帮助实施:
internal static class Helper
{
static object @lock = new object();
static readonly Dictionary<string, List<ListViewItem>> Cached = new Dictionary<string, List<ListViewItem>>();
static readonly List<HintFilter> HintFilters = new List<HintFilter>();
internal static void AddHintFilterService(HintFilter Filter)
{
lock (((ICollection)HintFilters).SyncRoot)
{
if (!HintFilters.Contains(Filter))
HintFilters.Add(Filter);
}
}
internal static void ClearHintFilters()
{
lock (((ICollection)HintFilters).SyncRoot)
{
HintFilters.Clear();
}
}
#region Services
static readonly List<IService> Services = new List<IHintParserService>();
internal static void ServicesParserEntry()
{
System.Timers.Timer ServicesUpdate = new System.Timers.Timer(1000)
{
AutoReset = true,
Enabled = true
};
ServicesUpdate.Elapsed += ServicesUpdate_Elapsed;
ServicesUpdate.Start();
}
static void ServicesUpdate_Elapsed(object sender, ElapsedEventArgs e)
{
lock (((ICollection)Services).SyncRoot)
{
if (!Services.Any())
return;
foreach (var Service in Services)
{
if (Service.NeedReparse())
ThreadPool.QueueUserWorkItem(Parse, Service);
}
}
}
internal static List<ListViewItem> GetCached(string ID)
{
lock (((IDictionary)Cached).SyncRoot)
{
if (Cached.Keys.Contains(ID))
return Cached[ID];
else
return null;
}
}
internal static void ClearCached()
{
lock (((IDictionary)Cached).SyncRoot)
{
Cached.Clear();
}
}
internal static void AddService(IService Service)
{
lock (((ICollection)Services).SyncRoot)
{
if (!Services.Contains(Service))
Services.Add(Service);
}
}
internal static void RemoveService(IService Service)
{
lock (((ICollection)Services).SyncRoot)
{
if (!Services.Contains(Service))
throw new InvalidOperationException("Unable to remove service:" + Service.ID());
Services.Remove(Service);
}
}
static object ParseLock = new object();
static void Parse(object O)
{
lock (ParseLock)
{
var Service = O as IService;
if (!Service.NeedReparse())
return;
lock (((IDictionary)Cached).SyncRoot)
{
if (Cached.Keys.Contains(Service.ID()))
Cached.Remove(Service.ID());//clear
}
var Hints = Service.Parse();
Cache(Hints, Service.ID());
}
}
static void Cache(List<Hint> Hints, string ID)
{
Thread CacheThread = new Thread(() =>
{
//Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
List<ListViewItem> CachedHints = new List<ListViewItem>();
foreach (Hint H in Hints)
{
CachedHints.Add(Cache(H));
}
lock (((IDictionary)Cached).SyncRoot)
{
Cached.Add(ID, CachedHints);
}
});
CacheThread.SetApartmentState(ApartmentState.STA);//MTA can't create UI elements
CacheThread.Start();
CacheThread.Join();
}
internal static ListViewItem Cache(Hint Hint)
{
ListViewItem Item = new ListViewItem()
{
MaxHeight = 40,
MinHeight = 0,
Margin = new Thickness(0)
};
WrapPanel Wrapper = new WrapPanel();
BitmapImage FilterContent = null;
if (!string.IsNullOrEmpty(Hint.GroupName))
{
var HintFilter = HintFilters.FirstOrDefault(f => f.GroupName == Hint.GroupName);
if (HintFilter != null)
{
FilterContent = HintFilter.Image;
}
}
if (FilterContent != null)
{
var Img = new Image()
{
Width = 30,
Height = 24,
Source = FilterContent
};
Wrapper.Children.Add(Img);
}
TextBlock Text = new TextBlock()
{
Text = Hint.Display,
VerticalAlignment = VerticalAlignment.Bottom,
Margin = new Thickness(0),
Height = 24
};
Wrapper.Children.Add(Text);
Wrapper.Margin = new Thickness(0);
Wrapper.MinHeight = 24;
Item.Content = Wrapper;
return Item;
}
#endregion
}
我的问题是:如何正确引用图形? Mabey我应该尝试复制元素并将它们用于浏览器。解决方案并不小,因此很难提供所有细节。
调用堆栈:
[插件]请求元素更新
[PluginWrapperMethod]
[CurrentMethod]