Call method in view model call which take/consume much of time - Multithreading in VM

Jan 13, 2011 at 9:56 PM

Hi I try solve this situation. I have WPF app with MVVM design.

In WPF app I use service from external assembly. It works good.

Problem is. I bind observable dictionary to listbox. Listbox can consist from 0 to 400 items. I have data template on listbox item it consist with image and som texbox. Listbox is like contact list in skype or google talk.

I call every 3-4 sec method from service, wich returns new data as dictionary. An with this data aj refresh Listbox.

My code look in view model like this:

 

   private DispatcherTimer _dispatcherTimer;
private MyObservableDictionary<string, UserInfo> _friends;
//temp
private MyObservableDictionary<string, UserInfo> _freshFriends;

//bind on listbox
public MyObservableDictionary<string, UserInfo> Friends
{
get { return _friends; }
set
{
_friends = value;
NotifyOfPropertyChange(() => Friends);
}
}

//in constructor of view model I have this:
_dispatcherTimer = new DispatcherTimer();
_dispatcherTimer.Tick += DispatcherTimer_Tick;
_dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
_dispatcherTimer.Start();

// on timer tick I call method from service
private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
{

//get new data from server
//method GetFriends take much of time
_freshFriends = _service.GetFriends(Account);

//delete old data
_friends.Clear();

//refresh
foreach (var freshFriend in _freshFriends)
{
Friends.Add(freshFriend);

}
}

 

As I said, problem is that method GetFriends from service take much of time and my app freezes.

How can solve this problem? In winforms app I use background worker, but this is my first WPF app with MVVM. It exist any "patern" or "design" how call method which consume much of time in view model class? Call this method in another thread?

Jan 14, 2011 at 8:43 AM

BackgroundWorker is available in WPF too! :)

Anyway, I would probably use the (almost) new System.Threading.Task

 

        
private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
{
    new System.Threading.Tasks.Task(() =>
    {
        //get new data from server
        //method GetFriends take much of time
        Dictionary<string, UserInfo> freshFriends = _service.GetFriends(Account);

        //delete old data
        Dispatcher.BeginInvoke((Action)(() =>
        {
            //refresh
            foreach (var freshFriend in freshFriends)
            {
                Friends.Add(freshFriend);

            }
        }));
    }).Start();
}

 

Unless you have a specific use for the _freshFriends collection, it is better to create a  local variable (note that I don't use an observable dictionary, since there is no need).

Jan 14, 2011 at 12:05 PM
Edited Jan 14, 2011 at 1:42 PM

Thank for advance, I try this:

View:

        <ListBox Name="Friends" 
                 SelectedIndex="{Binding Path=SelectedFriendsIndex,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                 SelectedItem="{Binding Path=SelectedFriend, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"
                 Style="{DynamicResource friendsListStyle}"
                 IsTextSearchEnabled="True" TextSearch.TextPath="Value.Nick"
                 Grid.Row="2" 
                 Margin="4,4,4,4"
                 PreviewMouseRightButtonUp="ListBox_PreviewMouseRightButtonUp"
                 PreviewMouseRightButtonDown="ListBox_PreviewMouseRightButtonDown" 
                 MouseRightButtonDown="ListBox_MouseRightButtonDown"
                 Micro:Message.Attach="[MouseDoubleClick]=[Action OpenChatScreen()]" >

VM:

 

In Dispatcher timer I call every 3 seconds in seperate thread new service method.

So I constructor of view model I have this:

 

        _dispatcherTimer = new DispatcherTimer();
        _dispatcherTimer.Tick += DispatcherTimer_Tick;
        _dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
        _dispatcherTimer.Start();

        _threadDispatcher = Dispatcher.CurrentDispatcher;


And Timer tick method is here:

    private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
    {
        new System.Threading.Tasks.Task(() =>
        {
            //get new data from server
            MyObservableDictionary<string, UserInfo> freshFriends = _service.GetFriends(Account);

            _threadDispatcher.BeginInvoke((System.Action)(() =>
            {
                //clear data, Friend is property which is binded on listobox control
                Friends.Clear();

                //here is problem - > refresh data
                foreach (var freshFriend in freshFriends)
                {
                    Friends.Add(freshFriend);

                }
            }));
        }).Start();

when I run app I get this error:

Must create DependencySource on same Thread as the DependencyObject.


   at System.Windows.Markup.XamlReader.RewrapException(Exception e, Uri baseUri)
   at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)
   at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlObjectWriter objectWriter)
   at System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(DependencyObject container, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)
   at System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren)
   at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)
   at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)
   at System.Windows.FrameworkElement.ApplyTemplate()
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Border.MeasureOverride(Size constraint)

 

I try replace dispatcher:

this _threadDispatcher = Dispatcher.CurrentDispatcher;

with this: _threadDispatcher = Application.Current.Dispatcher;

But it doesn’t help. Thank for advice.

 

 

 

 

Jan 14, 2011 at 2:13 PM

Can't you avoid the bindable collection when dealing with the service? It should require a Dispatcher, which totally defeats the asynchronous retrival you're aiming for... 

By the way, are you debugging in Release mode? If so, switch to Debug to enable tracing... you should be able to have a bit more information from this exception (possibly something about the source code generating the issue)... moreover, in Visual Studio, go to Debug -> Exceptions... and check the checkboxes next to Common Language Runtime Exceptions, so that the execution is stopped as soon as an exception (even catched) is thrown.

If possible post a bit more information about the service (at least the class definition and the GetFriends method signature), otherwise it is hard to understand what's going on and why you are using a bindable collection.

Jan 14, 2011 at 3:18 PM
BladeWise wrote:

Can't you avoid the bindable collection when dealing with the service? It should require a Dispatcher, which totally defeats the asynchronous retrival you're aiming for... 

By the way, are you debugging in Release mode? If so, switch to Debug to enable tracing... you should be able to have a bit more information from this exception (possibly something about the source code generating the issue)... moreover, in Visual Studio, go to Debug -> Exceptions... and check the checkboxes next to Common Language Runtime Exceptions, so that the execution is stopped as soon as an exception (even catched) is thrown.

If possible post a bit more information about the service (at least the class definition and the GetFriends method signature), otherwise it is hard to understand what's going on and why you are using a bindable collection.

Hi BladeWise,

If possible post a bit more information about the service (at least the class definition and the GetFriends method signature), otherwise it is hard to understand what's going on and why you are using a bindable collection.

Signature of GetFriends method is here:

        MyObservableDictionary<string, UserInfo> GetFriends(Account account);

I can change GetFriends method on signature Dictionary<string, UserInfo> GetFriends(Account account);.

This changes can solve problem ?

I think this part of code :_freshFriends = _service.GetFriends(Account) is no problem.

If I try this:

        private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
        {
            new System.Threading.Tasks.Task(() =>
            {
                 //_freshFriend is typeof MyObservableDictionary
                _freshFriends = _service.GetFriends(Account);
            }).Start();

        }

And it works.


Can't you avoid the bindable collection when dealing with the service? It should require a Dispatcher, which totally defeats the asynchronous retrival you're aiming for...

I try this:

        private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
        {
            new System.Threading.Tasks.Task(() =>
            {
                _freshFriends = _service.GetFriends(Account);
            }).Start();

            Friends = _freshFriends;

        }
But I get same error. Have any idea how can I avoid it?

By the way, are you debugging in Release mode? If so, switch to Debug to enable tracing... you should be able to have a bit more information from this exception (possibly something about the source code generating the issue)... moreover, in Visual Studio, go to Debug -> Exceptions... and check the checkboxes next to Common Language Runtime Exceptions, so that the execution is stopped as soon as an exception (even catched) is thrown.

I switch to debug mode, enable this options which you recomended.

Use this code:

        private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
        {
        new System.Threading.Tasks.Task(() =>
        {
            //get new data from server
            MyObservableDictionary<string, UserInfo> freshFriends = _service.GetFriends(Account);

            _threadDispatcher.BeginInvoke((System.Action)(() =>
            {
                //clear data, Friend is property which is binded on listobox control
                Friends.Clear();

                //here is problem - > refresh data
                foreach (var freshFriend in freshFriends)
                {
                    Friends.Add(freshFriend);

                }
            }));
        }).Start();

I get same exceptiom :

{"Must create DependencySource on same Thread as the DependencyObject."}

   at System.Windows.Markup.XamlReader.RewrapException(Exception e, Uri baseUri)
   at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)
   at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlObjectWriter objectWriter)
   at System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(DependencyObject container, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)
   at System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren)
   at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)
   at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)
   at System.Windows.FrameworkElement.ApplyTemplate()
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)

I need call only GetFriends method in another thread, it start be little complicated for someone who have only one year of C++ :) 

I exist way how call only GetFriends method in separate thread and with result update property wich is binded on listbox?

 

Jan 14, 2011 at 3:59 PM

Service is in external assembly and method GetFriends is here:

 

        public MyObservableDictionary<string, UserInfo> GetFriends(Account account)
        {
            try
            {
                var friends = new MyObservableDictionary<string, UserInfo>();
                var sortedFriends = new MyObservableDictionary<string, UserInfo>();

                var friendsNicks = LoadFriendsNicks(account);
                var friendsNicksWithSeperator = AddParameter(friendsNicks);
                var listOfUrl = GetUrlsForFriend(friendsNicksWithSeperator, 40);


                string invalidJsonStr = listOfUrl.Select(chunk => GetFriendsAsJson(account, chunk))
                .Where(tempStr => !string.IsNullOrEmpty(tempStr))
                .Aggregate("{", (current, tempStr) => current + tempStr.Remove(tempStr.Length - 1, 1).Remove(0, 1) + ",");


                invalidJsonStr = invalidJsonStr.Remove(invalidJsonStr.Length - 1, 1) + "}";

                string validJsonString = RemoveDoubleQuote(invalidJsonStr);

                string deserializableJsonString = ConvertToDeserializable(validJsonString, friendsNicks);

                var tempFriends = JsonConvert.DeserializeObject<MyObservableDictionary<string, UserInfo>>(deserializableJsonString);

                foreach (var tempFriend in tempFriends)
                {
                    friends.Add(tempFriend.Value.Nick, tempFriend.Value);
                }

                var query = friends.OrderByDescending(f => f.Value.StatusInfo.IsLogged).ThenBy(f => f.Value.Nick);

                foreach (var keyValuePair in query)
                {
                    sortedFriends.Add(keyValuePair.Key, keyValuePair.Value);
                }

                return sortedFriends;
            }
            catch (Exception exception)
            {
                throw exception;
            }

        }

Jan 14, 2011 at 3:59 PM

You still did not post the _service class signature... is it a DependencyObject?

Definitely I would change the GetFriends implementation to return a plain Dictionary<K,V> (not bindable), and I would add some more synchronization to avoid that a tick starts disturbing an already processed tick.

Oh, you can just use the CM API Execute.OnUIThread.

 

private bool _isExecuting;

private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
{
        if(_isExecuting)
            return;
        _isExecuting = true;
        new System.Threading.Tasks.Task(() =>
        {
            //get new data from server
            Dictionary<string, UserInfo> freshFriends = _service.GetFriends(Account);

            Execute.OnUIThread((System.Action)(() =>
            {
                //clear data, Friend is property which is binded on listobox control
                Friends.Clear();

                //here is problem - > refresh data
                foreach (var freshFriend in freshFriends)
                {
                    Friends.Add(freshFriend);

                }
            }));
        }).Start();

        _isExecuting = false;
}

Now, the code above should have no issues... unless there is something wrong in somewhere else place... the exception should be caused by the fact that you are trying to use a DependencyObject created on a thread as a Source of a Binding defined on an object instantiated ona  different thread... there is no way to understand what's wrong without a repro project, I'm afraid...

 

Jan 14, 2011 at 4:06 PM
Edited Jan 14, 2011 at 4:08 PM

Try with these changes...

public IDictionary<string, UserInfo> GetFriends(Account account)
        {
            try
            {
                var friends = new Dictionary<string, UserInfo>();
                var sortedFriends = new Dictionary<string, UserInfo>();

                var friendsNicks = LoadFriendsNicks(account);
                var friendsNicksWithSeperator = AddParameter(friendsNicks);
                var listOfUrl = GetUrlsForFriend(friendsNicksWithSeperator, 40);


                string invalidJsonStr = listOfUrl.Select(chunk => GetFriendsAsJson(account, chunk))
                .Where(tempStr => !string.IsNullOrEmpty(tempStr))
                .Aggregate("{", (current, tempStr) => current + tempStr.Remove(tempStr.Length - 1, 1).Remove(0, 1) + ",");


                invalidJsonStr = invalidJsonStr.Remove(invalidJsonStr.Length - 1, 1) + "}";

                string validJsonString = RemoveDoubleQuote(invalidJsonStr);

                string deserializableJsonString = ConvertToDeserializable(validJsonString, friendsNicks);

                var tempFriends = JsonConvert.DeserializeObject<Dictionary<string, UserInfo>>(deserializableJsonString);

                foreach (var tempFriend in tempFriends)
                {
                    friends.Add(tempFriend.Value.Nick, tempFriend.Value);
                }

                var query = friends.OrderByDescending(f => f.Value.StatusInfo.IsLogged).ThenBy(f => f.Value.Nick);

                foreach (var keyValuePair in query)
                {
                    sortedFriends.Add(keyValuePair.Key, keyValuePair.Value);
                }

                return sortedFriends;
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }

anyway, I must say that since this can be a complex scenario, you really need to provide a sample project explaining the issue... otherwise it's almost impossible to comprehend the scenario you are dealing with.

What I can say is that you are setting a binding using a DependencyObject  created from a thread different from the default Dispatcher... but if it is not the MyBindableCollection, then I have no idea what is it.

 

Jan 14, 2011 at 4:17 PM
Edited Jan 14, 2011 at 4:18 PM
You still did not post the _service class signature... is it a DependencyObject?

I  load service from external assembly in bootstraper class and inject with MEF in VM class.

In VM class I have this :

 

        private IPokecService _service;

        [ImportingConstructor]
        public MessengerViewModel(IShellViewModel shell,
            IPokecConnection conn,
            IPokecService service)
        {

          //...

            _service = service;
        }

This cause this problem? I try your idea now.

 

Jan 14, 2011 at 4:24 PM

Well, I honestly don't know... The only things created on a separate thread are the MyObservableDictionary and UserInfo... since I suppose that the UserInfo is a POCO (plain old CLR object), I must conclude that the only issue is with the observable dictionary... even if I cannot imagine where the binding that is issuing the error comes from...

Jan 14, 2011 at 4:54 PM

You have true in my view, I think  problem must be with MyObservableDictionary, I thinking about use some kind of ObservableColllection from Caliburn.Micro And bind property of this ObservableCollection to the listbox. Can be this solution?

Omited MyObservableDictionary and use some observable collection from Caliburn Micro (I dont’t that caliburn.micro), maybe I use this: http://msdn.microsoft.com/en-us/library/ms748365.aspx.

I try  your code, change GetFriend method, error is same :(.

Jan 14, 2011 at 4:56 PM

You can try to use the BindableCollection from Caliburn.Micro, but I suppose you are doing something wrong creating a DependencyObject on an incorrect thread.

I am really sorry, but unless you can provide a sample project, this is a s far as I can go... :(

Jan 14, 2011 at 5:30 PM
BladeWise wrote:

You can try to use the BindableCollection from Caliburn.Micro, but I suppose you are doing something wrong creating a DependencyObject on an incorrect thread.

I am really sorry, but unless you can provide a sample project, this is a s far as I can go... :(

It’s ok, you really help my, I know my questions are sometimes really stupid, but I don’t anybody who deal with  .NET especially with WPF/Calibur/MVVM.

I deall with .NET only one year. I can’t identify what in my view model class is  dependency object.

Also I try use ObservableCollection, something like this:

        public class FriendList : ObservableCollection<UserInfo>
        {         
        }

        private FriendList _friends;

        public FriendList Friends
        {
            get { return _friends; }
            set
            {
                _friends = value;
                NotifyOfPropertyChange(()=>Friends);
            }
        }

But I get same error. If you would  I can upload somewhere my project and if you have sometime time you can check it. I would be very glad to you because my project is now in ruins / trash :D

Jan 14, 2011 at 7:17 PM

Provide a download link and I'll try to see if there is something I can do. :)

Jan 14, 2011 at 7:58 PM
BladeWise wrote:

Provide a download link and I'll try to see if there is something I can do. :)

Thank BladeWise, here are the alternative for download.

http://netload.in/dateiPxLhAZWUNh/Repo.7z.htm

http://hotfile.com/dl/96792531/fba473e/Repo.7z.html

http://www.megaupload.com/?d=U8CHE2XM

http://rapidshare.com/files/442582433/Repo.7z

Zip file contains  txt READ ME   file with some "insttuction".

Jan 15, 2011 at 10:20 AM

Hi Miszko,
I had a look into your project.

Apparently there is some change to an object which gets notified on a thread different from the UI one.
Using CM's PropertyChangedBase (or its descendants, like Screen) and BindableCollection to build your observable
model usually avoids having to worry about thisk kind of problems, even when touching the model from a background thread.

In the part you pointed out you are using MyObservableDictionary, which doesn't have thread marshaling.
The dictionary update, however, is forced to run in the UI thread, so it *seems* be ok.
Since the error shows up during the WPF binding phase, it's hard to tell where it originates.
I have to investigate a little more. 

As a general advice, to help investigating an issue, you should try as much as possible to isolate the problem in a small project.
This is usually simpler for those who already known internal details of the application, while others have to dig into quite a lot of code (usually not related to the real issue) just to get to the intended point.
So I suggest, if it's possible for you, to try building an external, small repro exibiting the erroneus behaviour, replacing the services with fake ones.
You might start with the full solution and progressively cut out all the parts which are not relevant to the problem.
In my experience, doing this often helps you to discover the root source of the problem by yourself.

 

Jan 15, 2011 at 2:45 PM

Thank, Mr. Amendola.  Tomorrow I try use bindable collection from Caliburn Micro, maybe it solve this problem, if not  I try make only very little project as you advise with fake service and I will see where is a root of problem.

 

Jan 16, 2011 at 12:03 PM

Hi BladeWise and Marco Amendola,

 

Finally I identfied the problem which cause exception {"Must create DependencySource on same Thread as the DependencyObject."}.

As you both advised I create very simple project with shell and one screen.

In view model class I create fake service method (which returns "fresh" data) and this method I call in dispatcher timer tick event.

I use BindableCollection from CM’s instead MyObservableDictionary.

Here is it view model class with fake service method:

    [Export(typeof(IMessengerViewModel))]
    public class MessengerViewModel : Screen,IMessengerViewModel
    {

        private BindableCollection<UserInfo> _friends;

        public BindableCollection<UserInfo> Friends
        {
            get { return _friends; }
            set
            {
                _friends= value;
                NotifyOfPropertyChange(()=>Friends);
            }
        }

        private static UserInfo FakeUser()
        {
            var user = new UserInfo
            {
                Age = "16",
                Emphasis = true,
                IdUser = "11542",
                IsBlocked = false,
                IsFriend = true,
                LocationInfo = new Location
                {
                    CityName = "TN",
                    IdCity = 123456,
                    IdRegion = 1246,
                    RegionName = "TN",
                },
                StatusInfo = new Status
                {
                    IdChat = 12,
                    IsLogged = true,
                    LastLogin = "153151",
                    IsChating = true,
                    RoomName = "Car",
                },
                ProjectStatusInfo = new ProjectStatus(),
                IsIamFriend = true,
                PlusInfo = new Plus(),
                ProfilePhoto = new BitmapImage(new Uri("http://pokec.azet.sk/vanes90?i9=1f104a294997", UriKind.RelativeOrAbsolute))

            };

            return user;
        }

        private static IEnumerable<UserInfo> GetFakeFriends()
        {
            var list = new List<UserInfo>();

            for (int i = 0; i < 20; i++)
            {
                list.Add(FakeUser());
            }

            return list;
        }

        private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
        {
            if (_isExecuting)
                return;
            _isExecuting = true;
            new System.Threading.Tasks.Task(() =>
            {
                var freshFriends = GetFakeFriends();

                Execute.OnUIThread((System.Action)(() =>
                {
                    Friends.Clear();
                    foreach (var freshFriend in freshFriends)
                    {
                        Friends.Add(freshFriend);

                    }
                }));
            }).Start();

            _isExecuting = false;
        }

    }

 

If I bind property Friends on simple listbox without style it works good, no exception.

View:

    <Grid>
        <ListBox Name="Friends"
                 Grid.Row="2" 
                 Margin="4,4,4,4">
        </ListBox>
    </Grid>

But if I try aply some style on listbox, for example this style:

            <Style x:Key="friendsListStyle" TargetType="{x:Type ListBox}">
                <Setter Property="ItemTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <Grid Name="RootLayout">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="0.3*"></ColumnDefinition>
                                    <ColumnDefinition Width="*"></ColumnDefinition>
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="60"></RowDefinition>
                                </Grid.RowDefinitions>
                                <Image Margin="4,4,4,2" Source="{Binding Path=ProfilePhoto}" Grid.Column="0"/>
                            </Grid>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

 

Aplly style on listbox in view:

    <Grid>
        <ListBox Name="Friends"
                 Style="{StaticResource friendsListStyle}"
                 Grid.Row="2" 
                 Margin="4,4,4,4">
        </ListBox>
    </Grid>

I get the same exception as first:

Must create DependencySource on same Thread as the DependencyObject.

   at System.Windows.Markup.XamlReader.RewrapException(Exception e, Uri baseUri)
   at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)
   at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlObjectWriter objectWriter)
   at System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(DependencyObject container, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)
   at System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren)
   at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)
   at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)
   at System.Windows.FrameworkElement.ApplyTemplate()
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Border.MeasureOverride(Size constraint)

 

By my opion problem must be in style on listbox.

I try make another simple style on listbox without bind property typeof BitmapImage. I bind only string and bool properties on listbox item and it works.

So, my conclusion is that this problem cause binding property type of BitmapImage on listbox item.

I have service class, service method in external assembly.

Items (objects) of dictionary are created by deserialization json string in GetFriendsMethod.

Something like this:

                var Friends = JsonConvert.DeserializeObject<Dictionary<string, UserInfo>>(deserializableJsonString);

 

Properties ProfilePhoto for UserInfo class  look like this:

        public BitmapImage ProfilePhoto
        {
            get { return _profilePhoto; }
            set
            {
                _profilePhoto = value;
                NotifyPropertyChanged("ProfilePhoto");
            }
        }

This properties is initialized in construtor of UserInfo with this method:

        private BitmapImage CreateProfilePhoto()
{
var img = new BitmapImage();
img.BeginInit();

//default is image from file from folder //URL from web site, for example http://pokec.azet.sk/misiatko268?i9=dd1db210d005
img.UriSource = WithPhoto == 0 ? DefaultPhoto.GetDefaultPhoto(Sex) : new Uri(Photos.Normal, UriKind.Absolute); img.EndInit(); return img; }

I think this is problem.  Property ProfilePhoto is created in external assembly, in another thread and it is bind on UI control listbox.

What do you thinking about my opinion and conclusion?

I have one request how can I solve this problem? I would like have service in external assembly, I wouldn’t make big diferencess.

 

IMPORTANT:

I see if I create items of Bindadable collection in VM model class with fake service method:

        private static UserInfo FakeUser()
{
var user = new UserInfo
{
Age = "16",
Emphasis = true,
IdUser = "11542",
IsBlocked = false,
IsFriend = true,
LocationInfo = new Location
{
CityName = "TN",
IdCity = 123456,
IdRegion = 1246,
RegionName = "TN",
},
StatusInfo = new Status
{
IdChat = 12,
IsLogged = true,
LastLogin = "153151",
IsChating = true,
RoomName = "Car",
},
ProjectStatusInfo = new ProjectStatus(),
IsIamFriend = true,
PlusInfo = new Plus(),
ProfilePhoto = new BitmapImage(new Uri("http://pokec.azet.sk/vanes90?i9=1f104a294997", UriKind.RelativeOrAbsolute))

};

return user;
}

private static IEnumerable<UserInfo> GetFakeFriends()
{
var list = new List<UserInfo>();

for (int i = 0; i < 20; i++)
{
list.Add(FakeUser());
}

return list;
}

private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
{
if (_isExecuting)
return;
_isExecuting = true;
new System.Threading.Tasks.Task(() =>
{
var freshFriends = GetFakeFriends();

Execute.OnUIThread((System.Action)(() =>
{
Friends.Clear();
foreach (var freshFriend in freshFriends)
{
Friends.Add(freshFriend);

}
}));
}).Start();

_isExecuting = false;
}

 

I have same problem, because ProfilePhoto properties is created in another thread maybe?

Jan 16, 2011 at 2:50 PM

Yes, I think that the issue is caused by the BitmapImage instances.

If they are created asynchornously (on another thread), you have to Freeze them to be able to use them freely on other threads.

Another way to deal with images (and this is the one I am using right now for a project I'm developing) is to avoid to use BitmapSource at all, using just the Uri.

I prefer to define a special interface

public interface IHaveImageResource
{
       Uri ImageUri { get; set; }
}

and bind the Uri to an ImageSource property (default conversion can handle this scenarion). Otherwise, you can create your own converter and support smart caching for images (so that a new image source is not created every time you try to retrieve the specified image).

 

Jan 16, 2011 at 4:38 PM

Great! It seems you found the root cause.

I definitely agree with BladeWise solution about using Uri, which has the advantage of keeping the VM free from any UI-specific concern and dependencies.

Jan 16, 2011 at 6:16 PM

Re: BladeWise and Marco Amendola

 

Thank guys for cooperating and help. I choose the solution with Uri instead  Freeze method.

Before I don’t believe that create bitmapImage type in another thread can make this "big" problem.

I think BitmapImage is dependency object and this cause problems.

But as you advice create small repo project is the best way how find the root of problem.