Заполните один комбинированный список на основе выбора другого - PullRequest
3 голосов
/ 12 августа 2010

Я изучаю wpf mvvm и боролся с тем, что, по моему мнению, возможно, просто, но не смог решить самостоятельно.

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

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

Я попытался добавить вызов в установщик свойств SelectedString, но, похоже, он никогда не вызывался. Я уверен, что упускаю что-то простое, но мне нужен кто-то, чтобы помочь поднять завесу!

Я пробовал предложения на других постах, но пока что безуспешно.

Вот xaml для представления:

<Window x:Class="ThrowAwayMVVMApp.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Main Window" Height="400" Width="800">

    <DockPanel>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="60*" />
                <RowDefinition Height="282*" />
            </Grid.RowDefinitions>
            <!-- Add additional content here -->
            <ComboBox ItemsSource="{Binding MyStrings}" SelectedItem="{Binding Path=SelectedString, Mode=TwoWay}" Height="23" HorizontalAlignment="Left" Margin="18,24,0,0" Name="comboBox1" VerticalAlignment="Top" Width="204" />
            <TextBlock Text="{Binding SelectedString}" Height="23" HorizontalAlignment="Left" Margin="276,24,0,0" Name="textBlock1" VerticalAlignment="Top" Width="227" Background="#FFFAE7E7" />
            <ComboBox ItemsSource="{Binding ResultStrings}"  Height="23" HorizontalAlignment="Left" Margin="543,25,0,0" Name="comboBox2" VerticalAlignment="Top" Width="189" />
        </Grid>
    </DockPanel>
</Window>

Вот вид модели:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        this.MyStrings = new ObservableCollection<string>
            {
                "One",
                "Two",
                "Three",
                "Four",
                "Five"
            };
    }

    public ObservableCollection<string> MyStrings { get; set; }
    public ObservableCollection<string> ResultStrings { get; set; }

    public string SelectedString
    {
        get { return (string)GetValue(SelectedStringProperty); }
        set 
        { 
            SetValue(SelectedStringProperty, value);
            this.ResultStrings = getResultStrings(value);
        }
    }

    // Using a DependencyProperty as the backing store for SelectedString.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectedStringProperty =
        DependencyProperty.Register("SelectedString", typeof(string), typeof(MainViewModel), new UIPropertyMetadata(""));


    private ObservableCollection<string> getResultStrings(string input)
    {
        ObservableCollection<string> result = null;

        if (input == "Three")
        {
            result = new ObservableCollection<string> { "Six", "Seven", "Eight" };
        }
        else
        {
            result = new ObservableCollection<string> { "Nine", "Ten", "Eleven" };
        }

        return result;
    }
}

Ответы [ 2 ]

2 голосов
/ 12 августа 2010

Реализация свойства зависимостей SelectedString неверна: вы должны зарегистрировать PropertyChangedCallback, чтобы получать уведомления при прямом доступе к DP, а не с набором свойств CLR (см. http://msdn.microsoft.com/en-us/library/system.windows.propertychangedcallback.aspx);. Таким образом, вы можете изменить связанную коллекцию, даже если DP используется напрямую.

При привязке к свойству зависимости (например, SelectedString), привязка WPF не использует установщик свойства CLR, поэтому getResultStrings не вызывается.

Кстати, я бы рассмотрел использование подхода POCO на моделях представления, реализующего INotifyPropertyChanged: DP - это трудная задача для записи и добавления большого количества шума для виртуальных машин (кроме неприятной зависимости от System.Windows).

Посмотрите этот пост в блоге для подробного сравнения: http://kentb.blogspot.com/2009/03/view-models-pocos-versus.html

0 голосов
/ 13 августа 2010

Попробуйте

private string selectedString;
public string SelectedString
{
    get { return selectedString; }
    set 
    { 
        if (selectedString == value) return;
        selectedString = value;
        // Required for the UI to know the change was successful
        RaisePropertyChanged("SelectedString");
        LoadStringResults(value);
    }
}

private ObservableCollection<string> resultStrings;
public ObservableCollection<string> ResultStrings
{
    get { return resultStrings; }
    set 
    { 
        if (resultStrings== value) return;
        resultStrings= value;
        // Required for databinding to know that ResultStrings changed
        // Previously you changed this property without updating the UI
        RaisePropertyChanged("ResultStrings");
    }
}

private void LoadStringResults(string input)
{
    ObservableCollection<string> result = null;

    if (input == "Three")
    {
        result = new ObservableCollection<string> { "Six", "Seven", "Eight" };
    }
    else
    {
        result = new ObservableCollection<string> { "Nine", "Ten", "Eleven" };
    }

    ResultStrings = result;
}
...