XAML绑定BitmapImage的ViewModel属性

30
我在更新列表框时遇到了问题,我的应用程序使用的是Caliburn Micro框架。我的情况如下: 我将可绑定集合类型的属性绑定到列表框上:
视图模型代码如下:
private BindableCollection<UserInfo> _friends;

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

在视图模型中,我创建了一个虚拟的服务方法,返回 List 类型的新鲜数据,并使用这些数据更新绑定到列表框上的 Friends 属性。

我在调度计时器的滴答事件中每 3 秒调用一次虚拟服务方法。

 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;
        }

    }

如果我不对列表框应用任何样式,它的表现很好。

视图:

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

如果我在列表框中绑定了来自UserInfo的ProfilePhoto(typeof BitmapeImage)属性并应用了一些样式。

此处是样式:

        <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>

我遇到了这个错误:

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)
如果我在listbox/listbox item上创建另一种样式,其中只绑定了字符串或布尔属性,它可以正常工作。只有当绑定bitmapImage属性时才会出现问题。BitmapImage属性是这样初始化的:
ProfilePhoto = new BitmapImage(new Uri("http://pokec.azet.sk/vanes90?i9=1f104a294997", UriKind.RelativeOrAbsolute))

URI是图片的网址或文件的路径。

有什么问题吗?感谢帮助和建议。

样式很好,但只有在我不使用另一个线程中的方法调用刷新数据时才有效。

1个回答

71
如果你在非UI线程上创建BitmapImage,那么这可能是导致问题的原因。你可以冻结BitmapImage,以确保它可从任何线程访问:
var bitmapImage = new BitmapImage(...);
bitmapImage.Freeze();

5
太好了!你是怎么发现这个的? - Padu Merloti
由于BitmapImage继承自System.Windows.Freezable - "冻结的可冻结对象也可以在线程之间共享,而未冻结的可冻结对象则不行。" - http://msdn.microsoft.com/en-us/library/ms750509(v=vs.110).aspx - codekaizen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接