Simplifited solution graph. When I'm trying to add ListViewItem to Browser it throws System.InvalidOperationException: caller can't access object because it belongs to another thread.
//[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
                }
            }
        }
    });
}
Helper implementation:
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
}
My question is: how to do it correctly referencing graph? Mabey I should try to make copy of elements and use them for Browser. The solution isn't small, so this will be hard to provide all details.
Call stack:
- [Plugin] Request elements update 
- [PluginWrapperMethod] 
- [CurrentMethod] 
