Двусторонняя привязка ComboBox к статическому свойству

------- ИЗМЕНИТЬ------

Итак, я решил, что мой код правильный, как и фрагменты кода из всех ваших ответов. Спасибо за это. Моя проблема в том, что мой dev-machine работает под управлением .NET4.5, который ведет себя по-другому! Та же самая программа (скомпилированная с .NET4.0) корректно работает на машине с .NET4.0, но не на машине с .NET4.5!

Итак, вот мой пересмотренный вопрос .

------- ИЗМЕНИТЬ------

Во-первых, простой пример двусторонней привязки поля со списком к моему контексту данных:

Посмотреть модель:

public class MainWindowViewModel
{
    public List<String> MyElements { get; set; }
    public string SelectedElement { get; set; }

    public MainWindowViewModel()
    {
        MyElements = new List<string>() {"a", "b", "c"};
        SelectedElement = "a";
    }
}

и программный код

private readonly MainWindowViewModel _viewModel = new MainWindowViewModel();
public MainWindow()
{
    InitializeComponent();
    DataContext = _viewModel;
}

и мой xaml

<ComboBox
        ItemsSource="{Binding MyElements, Mode=OneWay}"
        SelectedItem="{Binding SelectedElement}" />

Это отлично работает, и если я выберу элемент в поле со списком, он будет привязан к моей модели представления.

Хорошо, теперь я хочу сделать мою viewModel статической, но по-прежнему двусторонней привязки selectedItem. Я пробую это:

public class MainWindowViewModel
{
    public static List<String> MyElements { get; set; }
    public static string SelectedElement { get; set; }

    static MainWindowViewModel()
    {
        MyElements = new List<string>() {"a", "b", "c"};
        SelectedElement = "a";
    }
}

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

<Window.Resources>
    <me:MainWindowViewModel x:Key="model"/>
</Window.Resources>

<StackPanel>
    <ComboBox
        ItemsSource="{Binding Source={x:Static me:MainWindowViewModel.MyElements}, Mode=OneWay}"
        SelectedItem="{Binding Source={StaticResource model}, Path=SelectedElement}" />
</StackPanel>

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

ИЗМЕНИТЬ:

Если я использую точно такую ​​же строку привязки для TextBox и изменяю текст в поле, это отражается в свойстве.

<TextBox Text="{Binding Source={StaticResource model}, Path=SelectedElement}"/>

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


person Martin Booka Weser    schedule 13.07.2012    source источник
comment
Проверив ваш код еще раз, я должен сказать, что он работает для меня. Я изменил public static string SelectedElement для записи вывода трассировки при вызове установщика, и он вызывается каждый раз при изменении выбранного элемента. Вы все равно можете заменить привязку ItemsSource статической ссылкой, как предложил @Baboon.   -  person Clemens    schedule 13.07.2012
comment
У меня установлен .NET4.5. Возможно ли, что здесь что-то изменилось? Конечно, у меня есть след и в моей собственности. Просто опустил его здесь для простоты. И да, я знаю, что я обычно также реализую INotifyPropertyChanged, чтобы привязать изменения свойства к ComboBox.   -  person Martin Booka Weser    schedule 13.07.2012


Ответы (2)


Проверено только что в тестовом проекте, работает нормально

public class ViewModel
{
    static ViewModel()
    {
        Items=new ObservableCollection<string>();
        SelectedItem = "222";
        Items.Add("111");
        Items.Add("222");
        Items.Add("333");
        Items.Add("444");
        Items.Add("555");
    }
    private static string _selectedItem;
    public static string SelectedItem
    {
        get { return _selectedItem; }
        set { _selectedItem = value;
            MessageBox.Show("Item " + value + " was selected");
        }
    }

    private static ObservableCollection<string> _items;
    public static ObservableCollection<string> Items
    {
        get { return _items; }
        set { _items = value; }
    }
}

и XAML

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="200" Width="300">
<Grid>
    <Grid.Resources>
        <my:ViewModel x:Key="viewM"/>
    </Grid.Resources>
    <ComboBox Height="23" HorizontalAlignment="Left" Margin="101,12,0,0" Name="comboBox1" VerticalAlignment="Top" Width="146" 
               ItemsSource="{Binding Source={x:Static my:ViewModel.Items}, Mode=OneWay}"
              SelectedItem="{Binding Source={StaticResource viewM}, Path=SelectedItem}" />
    </Grid>
</Window>

Я загрузил пример.

person Artiom    schedule 13.07.2012
comment
только что проверил (не ваш прикрепленный 7z, а скопировал фрагмент кода): ваш MessageBox появляется только один раз в начале. Если я выберу другой элемент в флажке, ничего не произойдет, и свойство SelectedItem не изменится. - person Martin Booka Weser; 13.07.2012
comment
работает каждый раз для меня. Не знаю, что не так. Работает с первого раза - person Artiom; 13.07.2012
comment
Не могли бы вы загрузить пример проекта, чтобы посмотреть, что там происходит? - person Artiom; 13.07.2012

Вы путаетесь между экземплярами и статическими свойствами: вам не нужно привязывать статический объект.

<ComboBox
        ItemsSource="{x:Static me:MainWindowViewModel.MyElements}"
        SelectedItem="{x:Static me:MainWindowViewModel.SelectedElement}" />

И вам все же придется реализовать INotifyPropertyChanged.

Связывание — это разрешение правильного экземпляра, из которого вы хотите получить данные.
Если экземпляр не имеет смысла, то и привязка не нужна.

person Louis Kottmann    schedule 13.07.2012
comment
Будет ли это обновлять свойство MainWindowViewModel.SelectedElement при изменении ComboBox.SelectedItem? Я думаю, что вопрос здесь заключается в двустороннем аспекте связывания. - person Clemens; 13.07.2012
comment
Да, должно. По умолчанию SelectedItem имеет значение «TwoWay». - person Louis Kottmann; 13.07.2012
comment
Но у тебя нет привязки. SelectedItem по умолчанию привязывает двустороннюю связь, но двусторонней связи без привязки не бывает. - person Clemens; 13.07.2012