数据绑定偶尔表现为执行多个BackgroundWorkers的绑定列表

时间:2013-10-10 19:01:35

标签: .net wpf mvvm asynchronous backgroundworker

我正在将IList绑定到ListBox。列表中的每个项都执行一个运行后台工作程序的方法。此类具有Progress属性,然后绑定到ListBox的DataTemplate。 progress属性实现了INotifyPropertyChange。

显然,这个想法相对简单:运行多个后台作业并将每个作业的进度报告给用户。我还试图提供其他属性,如“JobStepText”或“IsBusy”。

我正在使用MVVM模式。 ViewModel创建列表并启动异步作业。

这很有效,但是我似乎遇到了同步问题,因为有时工作已经完成,并且on change事件永远不会进入UI。它的行为是完全随机的 - 有时它会在这里和那里发生,有时则不然。

过去几天我一直在谷歌搜索这个,我只是对如何解决这个问题感到难过。

   <DataTemplate x:Key="ProgressTemplate">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="30"></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>

            <Image Height="20" Stretch="Uniform" Source="{Binding Failed, Converter={StaticResource ProgressConverter}}"></Image>
            <Image Height="20" RenderTransformOrigin="0.5, 0.5" Name="Spinner" Stretch="Uniform" Source="/Aps.SaasHr.M3Migration.Wpf;component/Images/spinner.jpg" Visibility="{Binding Failed, Converter={StaticResource ProgressConverter}}">
                <Image.Triggers>
                    <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                        <EventTrigger.Actions>
                            <BeginStoryboard Storyboard="{StaticResource Spin360}" />
                        </EventTrigger.Actions>
                    </EventTrigger>
                </Image.Triggers>
                <Image.RenderTransform>
                    <RotateTransform Angle="0" />
                </Image.RenderTransform>
            </Image>

            <ProgressBar Grid.Column="1" Height="40" IsEnabled="True"  Value="{Binding Progress, Mode=OneWay}">

            </ProgressBar>

            <Border Grid.Column="1" Padding="5" VerticalAlignment="Center" TextBlock.Foreground="Black" TextBlock.FontWeight="Black" TextBlock.FontSize="18">
                <StackPanel  Orientation="Horizontal"  >
                    <TextBlock FontSize="18" Foreground="White" Text="{Binding Config.ClassType, StringFormat='{}{0}\\'}" ></TextBlock>
                    <TextBlock FontSize="18" Text="{Binding Config.Name}" ></TextBlock>
                    <TextBlock Grid.Row="0" Text="{Binding Progress, StringFormat=' (%{0})', Mode=OneWay}"></TextBlock>
                    <TextBlock VerticalAlignment="Center" Text="{Binding CurrentText}" FontSize="12" Padding="3"></TextBlock>
                </StackPanel>
            </Border>

        </Grid>
    </DataTemplate>

以下是启动工人的原因。在像LogText这样的异步操作属性中设置。

public void ProcessAsync(Action<RunWorkerCompletedEventArgs> complete)
    {
        _worker.RunWorkerCompleted += (o, e) =>
        {
            IsBusy = false;
            if (e.Error != null)
            {
                Failed = true;
                AddLogText("An unexpected error occured: " + e.Error.ToString());
            }
            else
            {
                Progress = 100;
                Failed = false;
            }
            OnPropertyChanged("LogText");
            complete(e);
        };
        IsBusy = true;
        _worker.RunWorkerAsync();
    }

来自列表的子类(具有后台工作者的工作者类)

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

    #endregion


    public string LogText
    {
        get { return _logText; }
        set
        {
            _logText = value;
            OnPropertyChanged("LogText");
        }
    }

1 个答案:

答案 0 :(得分:0)

我很抱歉这样说,但我认为你目前的做法听起来很可怕。在我看来,数据类型类应该只是数据的持有者。那里不应该有这种功能,特别是没有多线程的功能......你只是在问你现在遇到的麻烦。

而不是那种方法,如何在视图模型中实现多线程功能,只需在后台线程报告时更新集合项的Progress(以及任何其他属性),例如。通常的方式?如果你这样做,你会发现你遇到的问题要少得多。