WPF--用ObservableCollection异步更新UI [重复]。

问题描述 投票:1回答:1

我有三个不同的 ObservableCollections 绑定到我的视图中。我把它们传递给函数,它们在循环中被编辑,我想在我的视图中显示这些集合的每一个变化。

所有的绑定都能正常工作,我唯一的问题是只有在函数结束时UI才会更新,所以我只能在更改后才能显示这些集合。

这是我的函数,它是解决TSP问题的NearestNeighbour算法的实现,我想在我的视图中打印解决它的每一步。

public int TSP(ObservableCollection<City> VisitedCities, ObservableCollection<Edge> CurrentEdges, ObservableCollection<Edge> FinalEdges)
{
    int bestDistance = 0;
    City currentCity = cities.First();
    cities.RemoveAt(0);
    VisitedCities.Add(new City(currentCity.X, currentCity.Y, currentCity.Number));
    int minWeight = int.MaxValue;
    City tmp = currentCity;
    do
    {
        foreach(City city in cities)
        {
           if (minWeight > neighbourMatrix[currentCity.Number, city.Number] && neighbourMatrix[currentCity.Number,city.Number] !=0)
           {
               minWeight = neighbourMatrix[currentCity.Number, city.Number];
               tmp = city;
           }
            CurrentEdges.Add(new Edge(currentCity.X, currentCity.Y, city.X, city.Y, neighbourMatrix[currentCity.Number, city.Number]));
        }
        FinalEdges.Add(new Edge(currentCity.X, currentCity.Y, tmp.X, tmp.Y, neighbourMatrix[currentCity.Number, tmp.Number]));
        bestDistance += neighbourMatrix[currentCity.Number, tmp.Number];
        CurrentEdges.Clear();
        VisitedCities.Add(new City(tmp.X, tmp.Y, tmp.Number));
        currentCity = new City(tmp.X, tmp.Y, tmp.Number);
        cities.Remove(tmp);
        minWeight = int.MaxValue;

    } while (cities.Any());
    FinalEdges.Add(new Edge(VisitedCities.Last().X, VisitedCities.Last().Y, VisitedCities.First().X, VisitedCities.First().Y, neighbourMatrix[VisitedCities.Last().Number, VisitedCities.First().Number]));
    return bestDistance;
}        

我有一个想法,使用 ComponentDispatcher 当我更换了我的 do{...}while() 但正如你所看到的,我还需要另一个循环来进行计算,因此我只能打印当前的顶点,以及每一步通往下一个顶点的路径。因此,我只能打印当前顶点,以及每一步通往下一个顶点的路径。我想同时打印当前检查过的每一条边。foreach(..) 循环。

谁能帮我解决这个问题?我还想实现A*算法和模拟退火,所以解决方案不应该只限于使用该函数。

c# asynchronous observablecollection dispatcher
1个回答
-1
投票

Shefff,

使用BackgroundWorker和Dispatcher刷新ObservableCollection绑定的示例代码。

DataGrid XAML

    <DataGrid HorizontalAlignment="Left" 
              Height="203" 
              Margin="175,126,0,0"
              DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}}" 
              ItemsSource="{ Binding Path=Persons }" 
              VerticalAlignment="Top" 
              Width="378" >
        <DataGrid.Resources>
            <Style TargetType="DataGridRow">
                <EventSetter Event="MouseDoubleClick" Handler="Row_DoubleClick"/>
            </Style>
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
            <DataGridTextColumn Header="LastName" Binding="{Binding LastName}"/>
            <DataGridTextColumn Header="Age" Binding="{Binding Age}"/>
        </DataGrid.Columns>
    </DataGrid>

代码背后

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Row_DoubleClick(object sender, MouseButtonEventArgs e)
    {
        var dbClickedRow = (DataGridRow)sender;
        MessageBox.Show(((Person)dbClickedRow.DataContext).Name);
    }

    public ObservableCollection<Person> Persons { get; set; } = new ObservableCollection<Person>();

    private void Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i < 500; i++)
        {
            Thread.Sleep(1000);
            Dispatcher.Invoke(() => Persons.Add(new Person { Age = i, Name = "SomeName" + i, LastName = "SomeLastName" + i }));
        }
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        Persons.Add(new Person { Name = "Gustavo", LastName = "Oliveira", Age = 35 });
        Persons.Add(new Person { Name = "Another", LastName = "Person", Age = 23 });
        Persons.Add(new Person { Name = "Neymar", LastName = "Junior", Age = 28 });

        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += Worker_DoWork;
        worker.RunWorkerAsync();
    }
}

public class Person
{
    public string Name { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}
© www.soinside.com 2019 - 2024. All rights reserved.