C # .NET4 WPF - установить выбранный элемент списка со строкой - PullRequest
2 голосов
/ 19 июля 2010

Я новичок в мире платформ C # и .net, так что будьте спокойны за меня. Этот форум помог мне решить несколько проблем, с которыми я столкнулся во время работы над проектом, но теперь я застрял на этом несколько дней. То, что я пытаюсь достичь, это установить выбранный элемент комбинированного списка, передав ему строку. Сценарий таков: У меня есть datatable, и я устанавливаю источник элементов комбо в этот datatable.DefaultView. Также я установил DisplayMemberPath комбо, и пока все в порядке, элементы отображаются в выпадающем списке. Помимо этого у меня есть строка с некоторым значением, которое у меня есть и внутри выпадающего списка. Итак, я пытаюсь установить выбранный элемент комбо, как это:

combo.SelectedItem = mystring;

Как вы можете догадаться, это не работает. Странно, когда я делаю это:

combo.Items.Add(mystring);
combo.SelectedItem = mystring;

Это работает. Вот почему я в замешательстве!

EDIT:

Я только что нашел решение:

combo.ItemsSource = datatable.DefaultView;
combo.DisplayMemberPath = "yourpath";
combo.SelectedValuePath = "yourpath";
combo.SelectedValue = mystring;

Таким образом, задача заключалась в том, чтобы установить свойства SelectedValuePath и SelectedValue. Я не знаю, хорошая ли это практика программирования, но это именно то, что мне нужно.

Ответы [ 2 ]

3 голосов
/ 19 июля 2010

Вы делаете что-то не так.

Вот демонстрационное приложение, которое показывает это (проект должен называться «StringCombo»).

<Window
x:Class="StringCombo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
ResizeMode="CanResize">
<Window.DataContext>
    <ViewModel
        xmlns="clr-namespace:StringCombo" />
</Window.DataContext>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <ComboBox
        Name="OldeFashonedCombo" />
    <Button
        Grid.Column="1"
        Content="Select Olde Waye"
        Click="Button_Click" />
    <ComboBox
        Grid.Row="1"
        ItemsSource="{Binding Strings}"
        SelectedItem="{Binding SelectedString}" />
    <Button
        Grid.Row="1"
        Grid.Column="1"
        Content="Select New Way"
        Command="{Binding SelectString}" />
</Grid>
</Window>

У нас есть две комбо и две кнопки. Один использует старый метод winforms codebehind для управления комбо, а другой использует новый шаблон MVVM.

В обоих сценариях пользователь нажимает кнопку, он устанавливает SelectedValue для комбо и обновляет комбо на пользовательском интерфейсе.

Вот версия кода:

public MainWindow()
{
    InitializeComponent();
    OldeFashonedCombo.Items.Add("One");
    OldeFashonedCombo.Items.Add("Two");
    OldeFashonedCombo.Items.Add("Three");
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    OldeFashonedCombo.SelectedItem = "Two";
}

Обратите внимание, я не использую тот же "экземпляр" из "Два"; в этом нет необходимости, поскольку строки «интернированы», или один и тот же экземпляр автоматически используется повторно на платформе .NET. object.ReferenceEquals("Two","Two") всегда верно.

Итак, я добавляю строки в коллекцию Items, а когда нажимаю кнопку, я устанавливаю SelectedItem на «Two». SelectedItem - это фактический экземпляр в коллекции Items, который должен быть выбран. SelectedValue - отображаемое значение; Вы можете выбрать это с помощью IIRC, но я бы не стал делать это в качестве лучшей практики.

Вот версия MVVM:

public sealed class ViewModel : INotifyPropertyChanged
{
    public ObservableCollection<string> Strings { get; private set; }

    public ICommand SelectString { get; private set; }

    public string SelectedString { get; set; }

    public ViewModel()
    {
        Strings = new ObservableCollection<string>();
        Strings.Add("Foo");
        Strings.Add("Bar");
        Strings.Add("Baz");
        SelectString = new SelectStringCommand
        {
            ExecuteCalled = SelectBar
        };
    }

    private void SelectBar()
    {
        SelectedString = "Bar";
        // bad practice in general, but this is just an example
        PropertyChanged(this, new PropertyChangedEventArgs("SelectedString"));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

/// <summary>
/// ICommands connect the UI to the view model via the commanding pattern
/// </summary>
public sealed class SelectStringCommand : ICommand
{
    public Action ExecuteCalled { get; set; }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        ExecuteCalled();
    }
}

Опять же, из-за интернирования мне не нужно использовать один и тот же "экземпляр" строки. Чтобы увидеть, как ViewModel подключается к пользовательскому интерфейсу, проверьте привязки в ComboBox и кнопке (если вы еще не изучили этот вопрос, я настоятельно рекомендую отключить кодовый код для MVVM. Для его понимания может потребоваться немного больше усилий) вне, но его НАМНОГО лучше в долгосрочной перспективе).

ANYHOW, если вы запустите это приложение, вы увидите, что ОБА версии работают должным образом. Когда вы нажимаете кнопку, поле со списком обновляется правильно. Это говорит о том, что ваш код не так как-то иначе. Не уверен, что, так как вы не дали нам достаточно деталей, чтобы определить это. Но если вы запустите пример и сравните его с вашим кодом, вы сможете понять это.

0 голосов
/ 19 июля 2010

Я думаю, что использование findby будет работать так, что-то вроде

combo.ClearSelection();
combo.Items.FindByValue(mystring).Selected = true;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...