我想在打开时刷新Silverlight 4组合框的内容。
这似乎是一件愚蠢的事情,但我不能为我的生活找到一个直接的答案。
我在Silverlight 4应用程序中有一个表单,其中有一个列出销售订单编号的组合框。很多人会同时打开这个表单,所以我希望它回拨给Web服务ON OPEN并刷新其内容。
我发现最接近的是这个:
http://blogs.msdn.com/b/kylemc/archive/2010/06/18/combobox-sample-for-ria-services.aspx
..我无法工作但无论如何也无法帮助我。该示例中没有任何内容允许我在打开时重新填充下拉列表。
我正在使用MVVM并使用Interactivity类将组合框的Open事件泵入我的ViewModel。在那里,我调用webservice并重置组合框'ItemsSource绑定的底层属性。不起作用 - 下拉列表闪烁一秒钟,然后打开,空白。
更新:
XAML:
<ComboBox x:Name="cmbOrderNumber" Width="125"
ItemsSource="{Binding ActiveSalesOrderNumbers, Mode=TwoWay}"
IsEnabled="{Binding OrderSelectorEnabled}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<inf:InvokeDelegateCommandAction Command="{Binding SalesOrderSelectedCommand}" CommandParameter="{Binding ElementName=cmbOrderNumber, Path=SelectedValue}"></inf:InvokeDelegateCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="DropDownOpened">
<inf:InvokeDelegateCommandAction Command="{Binding SalesOrderOpenedCommand}"></inf:InvokeDelegateCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
C#:
public void OnSalesOrderOpenedCommand(object o)
{
_companyContext.Load(_companyContext.GetSales_Order_Numbers_FromDateQuery(_lastSalesOrderRequest), q =>
{
if (!q.HasError)
{
q.Entities.ToList().ForEach(e =>
{
ActiveSalesOrderNumbers.Add(e.Sales_Order_Number);
});
_lastSalesOrderRequest = DateTime.Now;
}
else
{
throw new Exception("Error updating sales order number list.");
}
}, null);
}
事件被触发,我看到数据按预期从服务返回,并将新项添加到ActiveSalesOrderNumbers
,这是一个ObservableCollection。下拉列表不会更新,也不会有新记录。
答案 0 :(得分:1)
您的商品清单是什么样的?如果您的ItemsSource
被绑定到ViewModel上的ObservableCollection<T>
,那么您应该能够添加/删除该集合中的项目,并且ComboBox
项目将正确更新。 ComboBox因设置一次后真正搞砸了你的绑定而臭名昭着。我建议不要尝试替换整个ItemsSource,而是使用ObservableCollection<T>
,Clear()
然后使用Add(...)
。
我正在做一个项目,因为我已经做了这件事,所以我可以验证它是否有效。
编辑:
MainPage.xaml中
<ComboBox
x:Name="comboBox"
ItemsSource="{Binding ActiveSalesOrderNumbers}"
HorizontalAlignment="Center"
Width="200"
Height="27"
Margin="30">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel
Orientation="Horizontal">
<TextBlock>
<Run Text="{Binding SalesOrderNumber}"/>
<Run Text="{Binding LastModified}"/>
</TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="DropDownOpened">
<ei:CallMethodAction MethodName="OnSalesOrderOpenedCommand" TargetObject="{Binding DataContext, ElementName=comboBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
MainPage.xaml.cs中
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.DataContext = new MainPageViewModel();
}
}
MainPageViewModel.cs
public class MainPageViewModel : NotifyObject
{
private readonly SalesOrderRepository _repository;
public MainPageViewModel()
: this(new SalesOrderRepository())
{
}
public MainPageViewModel(SalesOrderRepository repository)
{
_repository = repository;
this.ActiveSalesOrderNumbers = new ObservableCollection<SalesOrder>();
}
private ObservableCollection<SalesOrder> _activeSalesOrderNumbers;
public ObservableCollection<SalesOrder> ActiveSalesOrderNumbers
{
get { return _activeSalesOrderNumbers; }
set
{
_activeSalesOrderNumbers = value;
NotifyPropertyChanged(() => ActiveSalesOrderNumbers);
}
}
public void OnSalesOrderOpenedCommand()
{
_repository.GetSalesOrderNumbers(result =>
{
this.ActiveSalesOrderNumbers.Clear();
result.ToList().ForEach(e => { this.ActiveSalesOrderNumbers.Add(e); });
});
}
}
public class SalesOrder : NotifyObject
{
private string _salesOrderNumber;
public string SalesOrderNumber
{
get { return _salesOrderNumber; }
set
{
_salesOrderNumber = value;
NotifyPropertyChanged(() => SalesOrderNumber);
}
}
private DateTime _lastModified;
public DateTime LastModified
{
get { return _lastModified; }
set
{
_lastModified = value;
NotifyPropertyChanged(() => LastModified);
}
}
}
public class SalesOrderRepository
{
public void GetSalesOrderNumbers(Action<IEnumerable<SalesOrder>> reply)
{
List<SalesOrder> orders = new List<SalesOrder>();
for (int i = 0; i < 10; i++)
{
orders.Add(new SalesOrder { SalesOrderNumber = i.ToString(), LastModified = DateTime.Now });
}
reply(orders);
}
}
NotifyObject.cs
public abstract class NotifyObject : INotifyPropertyChanged
{
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged = delegate { };
/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName">The property that has a new value.</param>
protected void NotifyPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="property">The property.</param>
protected void NotifyPropertyChanged<TProperty>(Expression<Func<TProperty>> property)
{
var lambda = (LambdaExpression)property;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression)lambda.Body;
memberExpression = (MemberExpression)unaryExpression.Operand;
}
else memberExpression = (MemberExpression)lambda.Body;
NotifyPropertyChanged(memberExpression.Member.Name);
}
/// <summary>
/// Warns the developer if this object does not have
/// a public property with the specified name. This
/// method does not exist in a Release build.
/// </summary>
[Conditional("DEBUG")]
public void VerifyPropertyName(string propertyName)
{
// If you raise PropertyChanged and do not specify a property name,
// all properties on the object are considered to be changed by the binding system.
if (String.IsNullOrEmpty(propertyName))
return;
// Verify that the property name matches a real,
// public, instance property on this object.
if (this.GetType().GetProperties().Where(p => p.Name == propertyName).FirstOrDefault() == null)
{
throw new ArgumentException(String.Format("Invalid property name: {0}", propertyName));
}
}
}
答案 1 :(得分:0)
为了能够在代码隐藏文件中绑定一个源,你需要使该文件成为DepencyProperty才能工作,例如:
#region Title (DependenyProperty)
public String Title
{
get { return (String)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(String), typeof(TopicListItem), new PropertyMetadata(null));
#endregion String (DependenyProperty)
至少这是我理解它的作用。而不是string
,而是创建您需要创建的集合对象。告诉我们它是怎么回事。