在后台线程中添加控件?

时间:2016-12-12 06:10:12

标签: c# wpf

我试图在用户登录后创建一些控件。

我有一个带有3个标签的TabControl:第一个登录,第二个是需要显示大量磁贴的地方(MahApps.Metro Tile)。每个瓷砖代表一个酒店房间。

第三个标签显示一个不确定的进度条。当用户登录时,将显示此选项卡。

我是怎么做到的:

    //User is logged in, so display the progress bar and add controls
    tabControl.SelectedIndex = 2; // display the progress bar tab

    private void populateHotel(Hotel hotel)
    {
        List<Room> rooms = hotel.rooms;
        Tile tile;
        tile_wrapper.Children.Clear();
        foreach (Room room in rooms)
        {
            sql.insertHotelRoom(room);
            tile = new Tile();
            tile.Title = room.room_num;
            tile.Content = room.name_fa;              
            tile.FontFamily = titleRooms.FontFamily; // titleRooms is a textbox
            tile.TitleFontSize = item1.TitleFontSize; // item1 is an already created tile
            tile.FontSize = item1.FontSize;
            tile_wrapper.Children.Add(tile);

        }
        // Now display the rooms tab
        tabControl.SelectedIndex = 1;
    }

问题是,这会冻结UI线程并冻结所有内容,包括进度条,直到它创建所有切片。

如何进行添加控制以使进度条仍然响应?

2 个答案:

答案 0 :(得分:1)

您正在做的是将插入Hotel的业务代码与显示它的UI代码混合在一起。混合业务代码和UI代码并不是一个好主意。除了产生的可维护性问题之外,它还会导致您的问题,因为UI必须等待您的insertHotelRoom操作,并且无法对用户输入作出反应。

您应该做的第一件事是分开您的顾虑:

private List<Room> insertHotelRooms(Hotel hotel)
{
    List<Room> rooms = hotel.rooms;
    foreach (Room room in rooms)
    {
        sql.insertHotelRoom(room);
        rooms.Add(room);
    }
    return rooms;
}


private void populateHotelTab(List<Room> rooms)
{
    Tile tile;
    tile_wrapper.Children.Clear();
    foreach (Room room in rooms)
    {
        tile = new Tile();
        tile.Title = room.room_num;
        tile.Content = room.name_fa;              
        tile.FontFamily = titleRooms.FontFamily; // titleRooms is a textbox
        tile.TitleFontSize = item1.TitleFontSize; // item1 is an already created tile
        tile.FontSize = item1.FontSize;
        tile_wrapper.Children.Add(tile);

    }
    // Now display the rooms tab
    tabControl.SelectedIndex = 1;
}

现在,您可以在任务中运行该操作,并将UI操作分派回UI线程:

Task insertRoomsTask = Task.Run( () => {
    List<Room> rooms = insertRooms(hotel);
    tile_wrapper.Dispatcher.Invoke(() => populateHotelTab(rooms));
});

答案 1 :(得分:0)

//User is logged in, so display the progress bar and add controls
tabControl.SelectedIndex = 2; // display the progress bar tab

private void populateHotel(Hotel hotel)
{
    List<Room> rooms = hotel.rooms;
    Tile tile;
    tile_wrapper.Children.Clear();

    // Use a count variable to keep track of how many rooms have been processed
    int count = 0;

    foreach (Room room in rooms)
    {
        // Update the value of the progress bar
        progressbar1.Value = count++ * 100 / rooms.Count;
        // Cause the progress bar to refresh
        progressbar1.Refresh();

        sql.insertHotelRoom(room);
        tile = new Tile();
        tile.Title = room.room_num;
        tile.Content = room.name_fa;              
        tile.FontFamily = titleRooms.FontFamily; // titleRooms is a textbox
        tile.TitleFontSize = item1.TitleFontSize; // item1 is an already created tile
        tile.FontSize = item1.FontSize;
        tile_wrapper.Children.Add(tile);

    }
    // Now display the rooms tab
    tabControl.SelectedIndex = 1;
}