假设我们有一个WPF ComboBox,并希望使用ObjectDataProvider填充它。
<ObjectDataProvider ObjectType="{x:Type provider:DataProviderProxy}" x:Key="BLDataProvider">
</ObjectDataProvider>
<ObjectDataProvider x:Key="InstallDriverProvider"
ObjectInstance="{StaticResource BLDataProvider}"
MethodName="GetInstallDrivers"
IsAsynchronous="True">
</ObjectDataProvider>
<ComboBox Grid.Row="0" Grid.Column="1"
IsEditable="False"
AlternationCount="2"
IsTextSearchEnabled="True"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Source={StaticResource InstallDriverProvider}}"
SelectedItem="{Binding Path=InstallDriverPlugin, Mode=TwoWay}"
SelectedValue="{Binding Path=InstallDriverPlugin.Name, Mode=TwoWay}"
SelectedValuePath="id"
...
如果GetInstallDrivers()方法调用某个异步返回的服务器方法,就像来自Web服务的响应一样,如何填充组合框? 如何在响应到达后填充组合框?
答案 0 :(得分:1)
如果要异步填充组合框,那么使用ObjectDataProvider不是最佳选择。但是使用ViewModel(和MVVM模式),它具有组合框数据源作为可观察的集合成员属性。然后只需异步获取数据,然后将其发布到UI线程并填充集合。
答案 1 :(得分:0)
最后,我找到了一个有效的解决方案。也许它不是最好的,但它可以正常工作,并且维护工作集中在DataProvider上的一个位置。
我使用了multibinding,MultiValueConverter,DataObjectProvider。 首先,我使用 INotifyPropertyChanged,INotifyPropertyChanging 扩展并实现了我的代理类。之后我添加了一个属性来包含结果,然后更改了XAML。
public class DataProviderProxy : INotifyPropertyChanged, INotifyPropertyChanging
{
private BusinessLayer BL;
private List<Transfer.InstallDriverPlugin> _InstallDrivers = new List<Transfer.InstallDriverPlugin>();
public List<Transfer.InstallDriverPlugin> InstallDrivers
{
get
{
return _InstallDrivers;
}
set
{
if (_InstallDrivers != value)
{
RaisePropertyChanging("InstallDrivers");
_InstallDrivers = value;
RaisePropertyChanged("InstallDrivers");
}
}
}
...然后我放置了一个通用方法来向服务器发送请求并检索数据
public List<Transfer.InstallDriverPlugin> GetInstallDrivers()
{
RequestContext rq = App.BL.GetInstallPlugins("DATA_PROVIDER_InstallDrivers");
App.BL.Admin.SetRequestCustomData(rq, new object[] { });
return InstallDrivers;
}
...处理来自服务器的响应的方法
public void ProcessResponse(ResponseContext rc)
{
// Response filter
...
#region Parse result by command
switch (rc.Command)
{
case AgentCommands.GetInstallPlugins:
if (rc.UserToken == "DATA_PROVIDER_InstallDrivers")
{
App.BL.Admin.ConsumeRequest(rc);
InstallDrivers = (List<Transfer.InstallDriverPlugin>)rc.result;
}
break;
...在XAML中
<ObjectDataProvider ObjectType="{x:Type provider:DataProviderProxy}" x:Key="BLDataProvider">
</ObjectDataProvider>
<ObjectDataProvider x:Key="InstallDriverProvider"
ObjectInstance="{StaticResource BLDataProvider}"
MethodName="GetInstallDrivers"
IsAsynchronous="True">
</ObjectDataProvider>
<ComboBox Grid.Row="0" Grid.Column="1"
IsEditable="False"
AlternationCount="2"
IsTextSearchEnabled="True"
IsSynchronizedWithCurrentItem="True"
DataContext="{StaticResource BLDataProvider}"
SelectedItem="{Binding Path=InstallDriverPlugin, Mode=TwoWay}"
SelectedValue="{Binding Path=InstallDriverPlugin.Name, Mode=TwoWay}"
SelectedValuePath="id"
Background="LightGreen"
MinHeight="29"
KeyDown="ComboBoxKeyDownHandler"
SelectionChanged="ComboBox_SelectionChanged">
<ComboBox.ItemsSource>
<MultiBinding Converter="{StaticResource InstDrvConverter}">
<Binding Source="{StaticResource InstallDriverProvider}"/>
<Binding Path="InstallDrivers" Source="{StaticResource BLDataProvider}"/>
</MultiBinding>
</ComboBox.ItemsSource>
</ComboBox>
第一个绑定调用metod来检索异步返回结果并填充属性的日期。第二个绑定将组合框绑定到属性 InstallDrivers 。 最后,多值转换器始终采用第二个绑定的值,即属性。
public class InstallDriverConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return values[1];
}
catch
{
return null;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
我知道它不那么复杂,但有几个优点。几乎所有内容都在XAML中,管理是集中的,如果您已经开发了一个表单并希望填写类似的数据,那么您可以将其剪切掉。粘贴代码并重新使用它只需在XAML中进行一些自定义。