【问题标题】:Binding a ComboBox entirely in XAML在 XAML 中完全绑定 ComboBox
【发布时间】:2011-08-04 09:44:48
【问题描述】:

我想绑定一个 Silverlight 控件上的 ComboBox。听起来很简单,但我发现因为 ItemsSource 的数据异步来自 Web 服务,所以只有在数据返回后,我才需要使用后面的代码绑定 SelectedValue。

数据进入的集合实现了 INotifyCollectionChanged 和 INotifyPropertyChanged,所以它应该都可以工作,并且确实组合框正确加载,但没有预先选择值。

我认为正在发生的是 SelectedValue 在集合加载之前被绑定 - 当组合框为空时 - 所以没有选择任何内容,然后当数据进入时,组合框被填充,但它不是再次检查选定的值。

因此,如果我使用后面的代码来连接事件并在代码中创建绑定,那么虽然我有这个工作,但我想将这一切都移到 XAML 中,例如:

<ComboBox HorizontalAlignment="Stretch" Margin="5,3,9,127" Name="cboCategoryID"  Grid.Row="4" Grid.Column="1"
           ItemsSource="{StaticResource Categories}"
           SelectedValue="{Binding CategoryID, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" 
           SelectedValuePath="CategoryID" 
           DisplayMemberPath="Caption"
           VerticalAlignment="Center">
</ComboBox>

这会正确加载项目,但不会绑定所选值。如果我将以下代码放在代码隐藏中,一切正常:

public MainControl()
{
    InitializeComponent();

    CategoryCollection cats = new CategoryCollection();
    cats.Dispatcher = this.Dispatcher;
    cats.LoadComplete += new EventHandler(cats_LoadComplete);
    cboCategoryID.ItemsSource = cats;
    cats.LoadAll();
}

private void cats_LoadComplete(object sender, EventArgs e)
{
    cboCategoryID.SetBinding(ComboBox.SelectedValueProperty, new System.Windows.Data.Binding("CategoryID"));
}

有没有办法做到这一点而不求助于背后的代码?

【问题讨论】:

    标签: silverlight binding


    【解决方案1】:

    看看这个简单的示例: XAML:

    <UserControl
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" xmlns:local="clr-namespace:StackoverflowQuestions.Silverlight" xmlns:sdk1="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="StackoverflowQuestions.Silverlight.MainPage"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
    
        <UserControl.Resources>
            <DataTemplate x:Key="Item">
                <TextBlock Text="{Binding PropertyToBeWatched}" />
            </DataTemplate>
        </UserControl.Resources>
    
        <Grid x:Name="LayoutRoot" Background="White">
            <!--<sdk:DataGrid ItemsSource="{Binding MyList}" RowStyle="{StaticResource Style1}">
                <sdk:DataGrid.Columns>
                    <sdk:DataGridTextColumn Binding="{Binding PropertyToBeWatched}" Header="Property1"/>
                </sdk:DataGrid.Columns>
            </sdk:DataGrid>-->
            <ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" Height="50" VerticalAlignment="Top" ItemTemplate="{StaticResource Item}" />
        </Grid>
    </UserControl> 
    

    代码隐藏: 公共部分类 MainPage : UserControl, INotifyPropertyChanged { 私有 ObservableCollection _myList; 私有 CustomClass _selectedItem;

            public event PropertyChangedEventHandler PropertyChanged;
    
            public ObservableCollection<CustomClass> MyList
            {
                get { return _myList ?? (_myList = new ObservableCollection<CustomClass>()); }
                set
                {
                    _myList = value;
                    RaisePropertyChanged("MyList");
                }
            }
    
            public CustomClass SelectedItem
            {
                get { return _selectedItem; }
                set
                {
                    _selectedItem = value;
                    RaisePropertyChanged("SelectedItem");
                }
            }
    
            protected void RaisePropertyChanged(string propertyname)
            {
                var handler = PropertyChanged;
                if (handler != null)
                    handler(this, new PropertyChangedEventArgs(propertyname));
            }
    
            public MainPage()
            {
                InitializeComponent();
                this.DataContext = this;
    
                MyList.Add(new CustomClass() { PropertyToBeWatched = "1"});
                MyList.Add(new CustomClass() { PropertyToBeWatched = "2" });
                MyList.Add(new CustomClass() { PropertyToBeWatched = "2" });
                MyList.Add(new CustomClass() { PropertyToBeWatched = "2" });
    
                SelectedItem = MyList[1]; //Here is where it happens
            }
    
        }
    

    通过将 ComboBox 的 SelectedItem 绑定到一个实体上,我们可以实现你想要的。这当然是双向的。

    希望这会有所帮助。 :D

    【讨论】:

    • 这是使用后面的代码,我希望避免这种情况。并且手动设置 SelectedItem 不是有点违背绑定的目的吗?
    • 为什么会破坏绑定的目的? viewmodel 被允许在 MVVM 模式中操作数据,这正是它的目的,对吧?
    【解决方案2】:

    您已经在使用通知更改的集合,因此如果您将 SelectedValue 绑定到的值正在通知更改,那么您所要做的就是在从 web 服务加载值之后设置该属性。它应该自动更新组合框,允许您完全在 xaml 中进行绑定。

    public myObject CategoryID { get {....} 
                                 set {
                                  this.categoryID = value;
                                  RaisePropertyChanged("CategoryID");}
    
    
    public void DataLoadedHandler()
    {
        CategoryID = 34; // this will cause the binding to update
    }
    

    【讨论】:

    • 是的,这可行,但我宁愿不必手动设置属性的值。这有点违背了绑定它的目的
    • 您必须从某个地方设置/获取“categoryid”。如果您不设置,模型应该如何知道它是?
    • 哦,我明白了。是的,你是对的。 DataContext 是从 Web 服务下载的,因此在返回结果时设置属性。但发生这种情况时,无法访问 UI 层。
    • @ChOOk 如果它可以访问数据层,您所要做的就是制作一个 depnd 道具并在代码中设置它,在 xaml 中将选定的项目绑定到它
    【解决方案3】:

    你在使用 mvvm 吗?如果是这样,你可以尝试在 web 服务的回调中设置 ItemsSource 和 SelectedItem,或者看看 Kyle 的这篇文章。

    http://blogs.msdn.com/b/kylemc/archive/2010/06/18/combobox-sample-for-ria-services.aspx

    【讨论】:

    • 我的 web 服务没有这样的回调,至少没有一个可以看到 UI 层的回调。不过,我会查看您发布的链接,看起来扩展库可能会有所帮助。
    猜你喜欢
    • 1970-01-01
    • 2021-10-01
    • 2023-03-09
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    相关资源
    最近更新 更多