在不使用 Refresh() 方法的情况下刷新 XAML 项



我正在使用C#WPF。

我试图弄清楚是否有办法更新 XAML 元素,而不必使用您在以下代码中看到的 Refresh() 方法。

现在,我将包含与 C# doPlay() 方法相关的代码,该方法通过线程和 XAML 代码在 MainWindow 中启动。

任何人都可以建议一种无需使用 Refresh() 方法即可更新进度条的方法吗?

   private void doPlay()
    {
        Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Red"));
        Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Blue"));
        Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Yellow"));
        Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Cyan"));
        Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Black"));
        Transfers.Add(new Transfer(Utils.RandomString(6), Utils.RandomString(6), Transfer.Type_t.download, "Brown"));
        Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
        {
            TransfersXAML.ItemsSource = Transfers;
        }));
        Random rnd = new Random();
        for (var i = 0; i < 100 * Transfers.Count; i++)
        {
            var next = rnd.Next(0, Transfers.Count);
            mre.WaitOne();
            int index =  next;
            if (Transfers[index].CurrentStep < 100)
            {
                Thread.Sleep(100);
                Transfers[index].CurrentStep++;
                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
                {
                    TransfersXAML.Items.Refresh();
                }));
            }
            else i--;
        }
     }

XAML 相对代码:

        <UniformGrid x:Name="DownLeftPanel" Grid.Column="2" Grid.Row="2">
            <ListBox x:Name="TransfersXAML" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Transfers}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <ProgressBar Height="30" Minimum="0" Maximum="{Binding NSteps}"
                                     Value="{Binding CurrentStep}" Foreground="{Binding Color}" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
                <ListBox.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="Get info" Click="GetTransferInfoClick" />
                        <MenuItem Header="Cancel" Click="CancelTransferClick" />
                    </ContextMenu>
                </ListBox.ContextMenu>
            </ListBox>
        </UniformGrid>

我试图简单地从 BeginInvoke 中删除操作,但通过这种方式不再显示栏,即从第一个发布的代码中删除这些说明:

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
     TransfersXAML.Items.Refresh();
}));

这个问题与以下问题有关:网络线程阻塞 GUI,特别是参考问题本身下方的评论。

如果Transfers类实现 INotifyPropertyChanged 接口并在 CurrentStep 属性的 setter 中引发 PropertyChanged 事件,则只需在后台线程上设置此属性,而无需调用 Refresh() 方法:

for (var i = 0; i< 100 * Transfers.Count; i++)
{
    var next = rnd.Next(0, Transfers.Count);
    mre.WaitOne();
    int index = next;
    if (Transfers[index].CurrentStep < 100)
    {
        Thread.Sleep(100);
        Transfers[index].CurrentStep++;
    }
    else i--;
}

最新更新