我在用户控件中有以下XAML:
<UserControl.Resources>
<ObjectDataProvider x:Key="DataSources"
ObjectInstance="{x:Static data:Sql.SqlDataSourceEnumerator.Instance}"
MethodName="GetDataSources"
IsAsynchronous="True"/>
</UserControl.Resources>
…
<ComboBox Name="cboServer" IsEditable="True"
ItemsSource="{Binding Source={StaticResource DataSources}, Mode=OneWay}"
DisplayMemberPath="ServerName" />
<ComboBox Name="cboInstance" IsEditable="True"
ItemsSource="{Binding Source={StaticResource DataSources}, Mode=OneWay}"
DisplayMemberPath="InstanceName" />
这有效,但现在我要做的是根据第一个框过滤第二个框;因此,当选择服务器时,将过滤实例以仅显示该服务器的实例。
有没有办法在不必手动填充第二个控件的情况下执行此操作?
答案 0 :(得分:1)
通常你可以使用CollectionViewSource进行这样的过滤,但不幸的是,这看起来不会在这里工作,因为SqlDataSourceEnumerator.GetDataSources()返回一个DataTable,并且那些用于那些的集合视图类型看起来不像支持过滤。
我相信其他一些答案是建议的,最好的方法是用你自己的视图模型类替换ObjectDataProvider,它可以适当地过滤事物。如果特定服务器具有多个实例,这也可以让您执行过滤掉重复服务器名称的操作。
这可能适合您或至少让您入门:
public class ViewModel : INotifyPropertyChanged
{
private string _selectedServerName;
private DataTable _dataSources;
public IEnumerable<string> ServerNames
{
get
{
if (_dataSources == null)
{
_dataSources = SqlDataSourceEnumerator.Instance.GetDataSources();
}
return _dataSources.Rows.Cast<DataRow>()
.Where(row => !row.IsNull("ServerName"))
.Select(row => (string)row["ServerName"]).Distinct();
}
}
public string SelectedServerName
{
get { return _selectedServerName; }
set
{
_selectedServerName = value;
NotifyOfPropertyChange("SelectedServerName");
NotifyOfPropertyChange("Instances");
}
}
public IEnumerable<string> Instances
{
get
{
if (_dataSources == null || _selectedServerName == null) return new string[0];
return _dataSources.Rows.Cast<DataRow>()
.Where(row => !row.IsNull("InstanceName") && _selectedServerName.Equals(row["ServerName"]))
.Select(row => (string)row["InstanceName"]);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyOfPropertyChange(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
然后,您需要按如下方式更改XAML(将ViewModel上的名称空间声明替换为适合您项目的名称):
<UserControl.Resources>
<WpfApplication1:ViewModel x:Key="ViewModel" />
</UserControl.Resources>
<ComboBox Name="cboServer"
IsEditable="True"
ItemsSource="{Binding ServerNames, Source={StaticResource ViewModel}, Mode=OneWay, IsAsync=True}"
SelectedItem="{Binding SelectedServerName, Source={StaticResource ViewModel}, Mode=TwoWay}"/>
<ComboBox Name="cboInstance"
IsEditable="True"
ItemsSource="{Binding Instances, Source={StaticResource ViewModel}, Mode=OneWay}" />
请注意,您将cboServer上的ItemsSource和SelectedItem属性绑定到ViewModel上的属性,并且SelectedItem绑定是双向的。这会将选定的服务器名称反馈给ViewModel,然后ViewModel将通知WPF Instances属性已更改。 Instances属性过滤掉与所选服务器名称不匹配的任何行。
答案 1 :(得分:0)
您需要将第一个ComboBox的选定值绑定到ObjectDataProvider上的参数,以将其提供给选定的服务器。要查看一个非常好的示例,请查看Paul Sheriff博客上的this article。
答案 2 :(得分:0)
您的ComboBox绑定到ObjectDataProvider的实例 要进行过滤,第一个ComboBox必须更新表示SelectedServer的属性,第二个ComboBox必须绑定到一个属性,该属性表示所需的特定过滤实例列表。 在您的XAML中:
<ComboBox Name="cboServer"
ItemsSource="{Binding Source={StaticResource DataSources}, Mode=TwoWay,
Path=SelectedServer}" />
<ComboBox Name="cboInstance"
ItemsSource="{Binding Source={StaticResource DataSources}, Mode=OneWay,
Path=FilteredInstances}" />
在ObjectDataProvider类中:
// get a list a instances of the current selected server
public IEnumerable<string> FilteredInstances
{
get
{
return SelectedServer.Instances;
}
}
private Server _selectedServer;
public Server SelectedServer
{
get
{
return _selectedServer;
}
set
{
_selectedServer = value;
OnPropertyChanged("SelectedServer");
// update the list of instances when the selected server changes
OnPropertyChanged("FilteredInstances");
}
}
我希望我的解释尽可能清楚。