过滤WPF中的绑定控件

时间:2011-11-30 12:56:31

标签: .net wpf xaml data-binding

我在用户控件中有以下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" />

这有效,但现在我要做的是根据第一个框过滤第二个框;因此,当选择服务器时,将过滤实例以仅显示该服务器的实例。

有没有办法在不必手动填充第二个控件的情况下执行此操作?

3 个答案:

答案 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");
        }
    }

我希望我的解释尽可能清楚。