简体   繁体   中英

XAML WinRT ComboBox Set SelectedItem

I have a combo box that is bound to an ObservableList (observable list inherits from ObservableCollection). Here is my Carrier object:

public class Carrier
{
    /// <summary>
    /// The carrier's name as it should be displayed to customers
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// This is the domain that email-to-text messages should be sent to. 
    /// </summary>
    public string TextBase { get; set; }

    /// <summary>
    /// Unique identifier for carriers
    /// </summary>
    public int CarrierId { get; set; }
}

My problem is, in my ViewModel, I am trying to set the value of the selected item and it is not being set in the UI. When I choose an option from the combobox, it is correctly modifying my viewmodel, though (so I know the binding is working).

Here is my xaml:

                <ComboBox ItemsSource="{Binding ElementName=UserInformationPage, Path=DataContext.PhoneCarriers}" 
                      Style="{StaticResource ComboBox}"
                      Width="250"
                      DisplayMemberPath="Name"
                      SelectedItem="{Binding Path=SelectedCarrier, Mode=TwoWay}"
                      SelectedValuePath="CarrierId"
                      />

and here is my viewmodel:

    public Carrier SelectedCarrier
    {
        get { return _selectedCarrier != null ? PhoneCarriers.First(c => c.CarrierId == _selectedCarrier.CarrierId) : PhoneCarriers.First(); }
        set
        {
            if (_selectedCarrier == null || _selectedCarrier.CarrierId != value.CarrierId)
            {
                Set(ref _selectedCarrier, value);
                if (User != null)
                    User.Phone.Carrier = value;
            }
        }
    }

    public UserDemographicsViewModel()
    {
        MessengerInstance.Register<SelectedUser>(this, m =>
        {
            User = m.User;
            CheckCanShowPassword();
            CheckCanResetPassword();
        });

        NavigationService.Navigated += (s, e) =>
        {
            if (e.Parameter is User)
            {
                User = e.Parameter as User;
                if (User.Phone != null)
                {
                    SelectedCarrier = User.Phone.Carrier;
                }
            }
        };

        IsPasswordTextShown = false;
        TogglePasswordCommand = new RelayCommand(() => IsPasswordTextShown = !IsPasswordTextShown); //flip the state of password shown
        SaveUserCommand = new RelayCommand<User>(SaveUser, u => CanSaveUser());
        ResetPasswordCommand = new RelayCommand(TryResetPassword, () => User != null && User.UserId != 0); //we have a user and its not a new user



        var repo = IoCContainer.GetContainer().Resolve<IAccountRepository>();
        var loggedInUser = App.Session.Get<User>("AuthenticatedUser");
        PhoneCarriers = new ObservableList<Carrier>(repo.GetPhoneCarriers(loggedInUser.AccountId));

    }

As I said, I know I am bound correctly to the SelectedCarrier property, but for some reason, the drop down is showing blank for the value when SelectedCarrier does match a value in the PhoneCarriers collection.

Update

I tried simplifying my SelectedCarrier property with the following:

    public Carrier SelectedCarrier
    {
        get { return _selectedCarrier; }
        set
        {
            if (_selectedCarrier == null || _selectedCarrier.CarrierId != value.CarrierId)
            {
                _selectedCarrier = value;
                RaisePropertyChanged("SelectedCarrier");
                if (User != null)
                    User.Phone.Carrier = value;
            }
        }
    }

I know I have a selected carrier because, when debugging, if I change the dropdown value, I can see the value of _selectedCarrier before it is changed to the new value (and it hits the breakpoint fine). The value is just not displayed in the user interface.

So the problem had to do with my xaml but I am not sure why it didn't work. When I changed:

<ComboBox ItemsSource="{Binding ElementName=UserInformationPage, Path=DataContext.PhoneCarriers}" 
                  Style="{StaticResource ComboBox}"
                  Width="250"
                  DisplayMemberPath="Name"
                  SelectedItem="{Binding Path=SelectedCarrier, Mode=TwoWay}"
                  SelectedValuePath="CarrierId"
                  />

to:

<ComboBox ItemsSource="{Binding PhoneCarriers}" 
                      Style="{StaticResource ComboBox}"
                      Width="500"
                      SelectedValuePath="CarrierId"
                      DisplayMemberPath="Name"
                      SelectedItem="{Binding SelectedCarrier, Mode=TwoWay}"

                      />

It started showing the SelectedItem in the dropdown on load.

I would try to simplify the code to see if it works fine with a simple property that is just using a backing field without any additional logic. I assume your Set() method raises change notifications fine.

I suspect the carrier that you're setting isn't the same as the one that you're getting and I don't know all the details of how bindings work internally, but I'd suspect that could be a problem if what you set isn't the same as what you get immediately after. Put breakpoints in the setter and getter and make sure the binding tries to get the new value after you've set it. Perhaps these could be different instances, but the type might need to override Equals() and GetHashCode() methods so the instances from different sources look the same. Overall, putting logic into a bindable property getter that's beyond simply accessing a backing field is a risky move.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM