44

更新

经过一番调查。问题似乎是 SelectedValue/SelectedItem 在项目源完成加载之前发生。如果我坐在断点处等待几秒钟,它会按预期工作。不知道我将如何解决这个问题。

结束更新

我有一个在 WPF 中使用 MVVM 和 ComboBox 的应用程序。下面是 ViewModel 示例。我遇到的问题是,当我们离开页面并迁移回 ComboBox 时,没有选择当前选中的值。

查看模型

public class MyViewModel
{
     private MyObject _selectedObject;
     private Collection<Object2> _objects;
     private IModel _model;

     public MyViewModel(IModel model)
    {
         _model = model;
         _objects = _model.GetObjects();
    }

    public Collection<MyObject> Objects
    {
         get
         {
              return _objects;
         }
         private set
         {
              _objects = value;
         }
     }

     public MyObject SelectedObject
     {
          get
          {
              return _selectedObject;
          }
          set
          {
               _selectedObject = value;
          }
      }
 }

为了这个例子,假设 MyObject 有两个属性(Text 和 Id)。我的 ComboBox 的 XAML 看起来像这样。

XAML

<ComboBox Name="MyComboBox" Height="23"  Width="auto" 
    SelectedItem="{Binding Path=SelectedObject,Mode=TwoWay}" 
    ItemsSource="{Binding Objects}"
    DisplayMemberPath="Text"
    SelectedValuePath="Id">

当我回到页面并重新组装对象时,无论我以哪种方式配置它,ComboBox 都不会选择该值。该对象通过属性中的 get 返回正确的对象。

我不确定这是否只是 ComboBox 和 MVVM 模式工作方式的问题。我们正在做的文本框绑定工作正常。

4

18 回答 18

43

设置IsSynchronizedWithCurrentItem="True"对我有用!

于 2012-06-26T06:58:57.873 回答
27

您是否尝试过在视图模型中实现INotifyPropertyChanged,然后在设置PropertyChanged时引发事件SelectedItem

如果这本身不能解决问题,那么您将能够PropertyChanged在导航回页面时自己手动引发事件,这足以让 WPF 重新绘制自身并显示正确的选定项目。

于 2009-03-19T20:33:28.383 回答
21

您需要将 ItemsSource 属性放在 SelectedItem 属性之前。几天前我看到一个博客提到了这个问题。

于 2011-01-13T02:45:09.390 回答
11

我遇到过类似的问题,并通过确保我正确实施IEquatable来解决。当绑定发生时,它会尝试查看对象是否匹配,因此请确保您正确实施了相等检查。

于 2009-03-19T21:50:55.733 回答
10

在这种情况下,selecteditem 绑定不起作用,因为对象的哈希 id 不同。

一种可能的解决方案是:

根据选中的项目 id,恢复 itemsource 集合上的对象并将选中的项目属性设置为它。

例子:

<ctrls:ComboBoxControlBase SelectedItem="{Binding Path=SelectedProfile, Mode=TwoWay}" ItemsSource="{Binding Path=Profiles, Mode=OneWay}" IsEditable="False" DisplayMemberPath="Name" />

绑定到 ItemSource 的属性是:

public ObservableCollection<Profile> Profiles
{
   get { return this.profiles; }
   private set { profiles = value; RaisePropertyChanged("Profiles"); }
}

绑定到 SelectedItem 的属性是:

public Profile SelectedProfile 
{
    get { return selectedProfile; }
    set
    {
        if (this.SelectedUser != null)
        {
            this.SelectedUser.Profile = value; 
            RaisePropertyChanged("SelectedProfile");  
        } 
    } 
}

恢复代码为:

    [Command("SelectionChanged")]
    public void SelectionChanged(User selectedUser)
    {
        if (selectedUser != null)
        {
            if (selectedUser is User)
            {
                if (selectedUser.Profile != null)
                {
                    this.SelectedUser = selectedUser;
                    this.selectedProfile = this.Profiles.Where(p => p.Id == this.SelectedUser.Profile.Id).FirstOrDefault();
                    MessageBroker.Instance.NotifyColleagues("ShowItemDetails"); 
                }
            }
        }            
    }

我希望它对你有帮助。我花了很多时间寻找答案,但我找不到。

于 2012-10-03T19:32:49.427 回答
4

离开当前页面时,CollectionView与 的ItemsSource属性相关联的内容将ComboBox被清除。并且因为该ComboBox IsSyncronizedWithCurrent属性默认为true,所以SelectedItemSelectedValue属性被重置。
这似乎是绑定中的内部数据类型问题。正如上面其他人建议的那样,如果您SelectedValue通过绑定到视图模型上的 int 属性来代替,它将起作用。您的捷径是覆盖EqualsMyObject 上的运算符,以便在比较两个 MyObject 时比较实际Id属性。

另一个提示:如果您确实重组了您的视图模型并使用SelectedValue,请仅在SelectedValuePath=Idwhere Idis时使用它int。如果使用字符串键,则绑定到的Text属性,ComboBox而不是SelectedValue.

于 2011-02-17T20:01:11.963 回答
3

我之前也注意到了这种行为。我注意到 SelectedIndex 属性不会导致相同的错误。如果您可以重组 ViewModel 以公开所选项目的索引并绑定到该索引,那么您应该很高兴。

于 2009-03-20T21:30:28.347 回答
2

我有同样的问题。事情是。所选项目不知道它应该使用集合中的哪个对象。因此,您必须对所选项目说要使用集合中的项目。

public MyObject SelectedObject
 {
      get
      {
          Objects.find(x => x.id == _selectedObject.id)
          return _selectedObject;
      }
      set
      {
           _selectedObject = value;
      }
 }

我希望这有帮助。

于 2010-05-14T15:21:56.680 回答
2

对于这个问题,我有一个非常简单的答案。首先将以下代码添加到视图 IsSynchronizedWithCurrentItem="True"。

接下来,当您将 ViewModel 中的新对象分配给该属性时,应将 SelectedObject 保存到该属性而不是私有成员。

viewmodel 属性应该是这样的

    public Role SelectedObject 
    {
        get { return object; }
        set
        {
            if (value != null)
            {
                if (!object.Equals(value))
                {
                    object = value;
                    OnPropertyChanged(() => SelectedObject );
                }
            }
        }
    }

这应该可以解决问题。

于 2011-08-04T17:57:09.587 回答
2

我通过在 UserControl_Loaded 事件中添加调度程序解决了这个问题

 Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
 {
     combobox.SelectedIndex = 0;
 }));
于 2014-08-16T20:48:07.533 回答
1

IsSyncronizedWithCurrent=False 将使其工作。

于 2010-12-08T07:38:35.423 回答
1

我与这个问题斗争了一段时间。在我的情况下,我使用复杂类型(列表)作为项目源,并使用 KeyType 作为选定值。在加载事件中,KeyType 被设置为 null。这导致一切都崩溃了。键更改时,不会更新任何子元素。事实证明,当我添加检查以确保 KeyType 的建议值不为空时,一切都按预期工作。

    #region Property: SelectedKey
    // s.Append(string.Format("SelectedKey : {0} " + Environment.NewLine, SelectedKey.ToString()));

    private KeyType _SelectedKey = new KeyType();
    public KeyType SelectedKey
    {
        get { return _SelectedKey; }
        set
        {
            if(value != null )
                if (!_SelectedKey.Equals(value))
                {
                    _SelectedKey = value;
                    OnPropertyChanged("SelectedKey");
                }
        }
    }
    #endregion SelectedKey
于 2011-02-08T23:42:56.557 回答
1

SelectedValuePath和的类型SelectedValue必须完全相同。

例如,如果SelectedValuePathisInt16的类型和绑定到SelectedValueis的属性的类型int将不起作用。

我花了几个小时来找到它,这就是为什么我在问了这么多时间之后在这里回答这个问题。也许像我这样有同样问题的可怜人可以看到它。

于 2011-04-21T10:19:02.057 回答
1

我在显示颜色列表( List<Brush> )的 ComboBox 时遇到了这个问题。
选择颜色是可能的,但在选择关闭时它没有显示(尽管属性已更改!)

修复是覆盖ComboBox (Brush) 中选择的类型的 Equals(object obj) 方法,这并不简单,因为 Brush 是密封的。所以我写了一个包含 Brush 并实现 Equals的类EqualityBrush :

public class EqualityBrush
{
    public SolidColorBrush Brush { get; set; }

    public override bool Equals(object o)
    {
        if (o is EqualityBrush)
        {
            SolidColorBrush b = ((EqualityBrush)o).Brush;
            return b.Color.R == this.Brush.Color.R && b.Color.G == this.Brush.Color.G && b.Color.B == this.Brush.Color.B;
        }
        else
            return false;
    }
}

使用我的新 EqualityBrush 类的列表而不是普通的 Brush 类解决了问题!

我的组合框XAML如下所示:

<ComboBox ItemsSource="{Binding BuerkertBrushes}" SelectedItem="{Binding Brush, Mode=TwoWay}" Width="40">
    <ComboBox.Resources>
        <DataTemplate DataType="{x:Type tree:EqualityBrush}">
            <Rectangle Width="20" Height="12" Fill="{Binding Brush}"/>
        </DataTemplate>
    </ComboBox.Resources>
</ComboBox>

请记住,我在ViewModel中的“画笔”属性现在必须是 EqualityBrush 类型!

于 2012-01-11T16:52:32.487 回答
0

这可能是您将 DataContext 应用于页面的方式。在 WPF 中,每次导航到页面时,所有内容都会重新初始化,调用构造函数,加载方法,一切。因此,如果您在 View 中设置 DataContext ,您无疑会吹走用户选择的 SelectedItem。为了避免这种情况,请使用页面的 KeepAlive 属性。

<Page KeepAlive="True" ...>
   ...
</Page>

这将导致在导航回您已经访问过的页面时仅触发 Loaded 事件。因此,您需要确保在 Initialize(外部或构造函数内)而不是 Load 上设置 DataContext。

但是,这仅适用于页面的该实例。如果您导航到该页面的新实例,它将再次调用它的构造函数。

于 2009-03-21T14:42:54.513 回答
0

组合框.SelectionBoxItem.ToString()

于 2010-06-28T10:32:28.237 回答
0

使用 Loaded 事件:

private void cmb_Loaded(object sender, RoutedEventArgs e) {
    if (cmb.Items.Count > 0) cmb.SelectedIndex = 0;          
}

这个对我有用。

于 2011-02-01T13:48:59.500 回答
0

您还可以将 SelectedIndex 绑定到 ViewModel 中的属性并以这种方式操作 SelectedItem:

        public int SelectedIndex
        {
            get { return _selectedIndex; }
            set
            {
                _selectedIndex = value;
                OnPropertyChanged();
            }    
        }

在您的 XAML 中:

<ComboBox SelectedIndex="{Binding SelectedIndex,Mode=TwoWay}" ... >
于 2020-06-07T13:59:15.063 回答