我正在尝试从第一个窗口(GUI_1)创建辅助窗口(GUI_2),并在GUI_1初始化时从GUI_2更新标签。 (就像加载屏幕一样)。
我尝试使用Task.Factory,Dispatcher,但我认为我缺少某些东西。
public MainWindow()
{
InitializeComponent();
Task.Factory.StartNew(() =>
{
DispatcherOperation op = Dispatcher.BeginInvoke((Action)(() => {
Window1 gui = new Window1();
gui.Show();
}));
});
}
有了这个,我的GUI_2就打开了但如果我试图更新标签,它只显示最后一个值。 (即:a for i = 0到10,thread.sleep只显示10个值)。
我怎样才能做到这一点?
编辑: 我试过这段代码:
public partial class Loading : Window
{
public static object uiContext;
private List<string> paths;
private List<Color> colors;
public Loading(List<string> _paths, List<Color> _colors)
{
InitializeComponent();
paths = _paths;
colors = _colors;
}
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
Storyboard s = (Storyboard)TryFindResource("sb");
s.Begin(); // Start animation
await Task.Run(() => EXCEL.Analogize(paths, this, colors));
Close();
}
public void UpdateWindow(string text, int percent)
{
Dispatcher.Invoke(() =>
{
progress_label.Content = text;
progress.Value = percent;
});
}
}
在我的EXCEL.Analogize我使用gui_loading.UpdateWindow(text,percent);
它正在运行,但如果我尝试对Windows类做同样的事情,它就不再更新了。
答案 0 :(得分:1)
可能是在GUI_2 UI任务中忙于加载,并且仅在完成时显示。尝试将更新放在其他任务上并与UI同步。
在GUI_2 ctor中
修改强>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
_SyncContext = SynchronizationContext.Current;
UpdateLabel();
}
SynchronizationContext _SyncContext = null;
private async void UpdateLabel()
{
await Task.Run(() =>
{
for (int i = 1; i < 11; i++)
{
Load(i);
Thread.Sleep(1000);
}
});
}
private void Load(int i)
{
SendOrPostCallback updateUI = new SendOrPostCallback(arg =>
{
yourLabelName.Content = $"{i}/10";
});
_SyncContext.Send(updateUI, null);
}
}
我从mainWindow构造函数调用这个窗口:
Window1 gui = new Window1();
gui.Show();
这是我测试过的,它对我有用。
编辑2
对的,这是可能的
一种方法是直接在构造函数中传递参数
比如Window1(string text);
,当您调用该窗口时,您会传递参数Window1(text);
第二种方式是(我更喜欢这个)制作接口(类似于IWindow)并在其中加入简单的Load方法
像这样
public interface IWindow
{
void Load(string text);
}
public partial class Window1 : Window , IWindow
{
//here you implement Load(string text) method.
然后你通过IWindow我的MainWindow构造函数与一些DI解决它(Autofac,Unity)Autofac 从mainWindow你可以实例化这样的东西:
// MainWindow构造函数
MainWindow(IWindow iWindow)
{
_iWindow = iWindow;
}
public IWindow _iWindow { get; private set; }
并在MainWindow中使用Load()方法
public void Load()
{
_iWindow.Load(textToPassAsParameter);
//this will call Load method from Window1
}
要调用该加载方法,您可以在xaml中执行此操作 ADD 名称空间
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
并从MainWindo调用Load方法(将从Window1调用Load)
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ei:CallMethodAction MethodName="Load"
TargetObject="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
检查依赖注入因为你将接口作为参数传递,它需要返回使用该接口的类(Window1)。
我强烈建议将MVVM和ViewModels用于ea View,而不是在后面执行代码。
编辑3
我认为你可以用xceed toolkit(NuGet包)来完成你想要的东西,并将BusyContent与一些正在改变的属性绑定(以显示加载进度)
围绕您正在加载
的区域命名空间
xmlns:extToolkit="http://schemas.xceed.com/wpf/xaml/toolkit"
环绕
<extToolkit:BusyIndicator Grid.Row="1"
BusyContent="Loading..."
IsBusy="{Binding IsBusy}">
<!-- your loading area -->
和IsBusy是MainWindow中的属性
private bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set
{
if (_isBusy != value)
{
_isBusy = value;
OnPropertyChanged();
}
}
}
在你的负载方法
中得到更新private void Load()
{
IsBusy = true;
// some load logic
//{
// IsBusy=false;
//}
}
并在MainWindow构造函数中调用该load方法。这样您就不需要Window1,因为此工具包将作为子项放在您的mainWindow中,并将作为进度条。
如果你在BusyContent="This is xceed progress bar..."
中写字,你会从xceed那里得到子装载窗口。