Первый шаг - выяснить, какой рубин вызывается: which ruby
Ваша система говорит: /usr/bin/ruby
Это НЕ прокладка, используемая rbenv, которая ( на MacOS) должно выглядеть так: /Users/<username>/.rbenv/shims/ruby
Прокладка - это фактически сценарий, который действует как перенаправление на версию рубина, которую вы установили. rbenv global 1.9.3
rbenv local --unset
rbenv shell --unset
Я рекомендую, чтобы при устранении неполадок вы удаляли конкретную «локальную» версию проекта, а также версию оболочки с оболочкой и просто проверяли с помощью параметра «глобальной» версии, который определяется в текстовом файле в ~ / .rbenv / verion, который будет просто номером версии «1.9.3» в вашем случае. Вы можете сделать «ls -laG» в корне вашей папки проекта (а не в домашней папке), чтобы убедиться, что там больше нет файла «.ruby-version».
Вы можете использовать «rbenv версии ", чтобы определить, какая версия rbenv установлена для использования (и расположение и имя файла, который устанавливает это).
rbenv versions
НИ ОДНА ИЗ ЭТОГО ВОПРОСОВ: пока вы не правильно установите путь.
Используйте это, чтобы убедиться, что ваш MacOS будет подчиняться вам: eval "$(rbenv init -)"
Далее следуют: which ruby
Чтобы убедиться это выглядит так: /Users//.rbenv/shims/ruby
Затем добавьте строку в свой профиль, чтобы она запускалась каждый раз при открытии нового окна терминала: ~/.bash_profile
eval "$(rbenv init -)"
Есть и другие способы изменения пути, не стесняйтесь заменить любой из них, а не запускать rbenv init.
ПРИМЕЧАНИЕ: переустановите Rails с помощью: gem install rails
Если вы пытались для запуска Ruby on Rails, вам нужно сначала запустить все это, а затем снова установить рельсы. Ранняя установка Rails будет использовать жестко закодированный путь к неправильному рубину, а некоторые другие вещи будут не в том месте, поэтому просто установите драгоценный камень еще раз.
P. S. Если ваш MacOS не будет подчиняться вам (* упомянуто выше), вам, возможно, придется найти другой способ изменить свой путь, но вряд ли это будет проблемой, потому что «Mac просто работают»;)
Попробуйте создать свойство IsSelected
для каждого из ваших элементов данных и привязать ListBoxItem.IsSelected
к этому свойству
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
Я продолжал искать легкое решение для этого, но не повезло.
Решение, которое имеет Rachel, хорошо, если у вас уже есть свойство Selected на объекте в вашем ItemsSource. Если вы этого не сделаете, вам нужно создать модель для этой бизнес-модели.
Я пошел другим путем. Быстрый, но не идеальный.
В вашем ListBox создайте событие для SelectionChanged.
<ListBox ItemsSource="{Binding SomeItemsSource}"
SelectionMode="Multiple"
SelectionChanged="lstBox_OnSelectionChanged" />
Теперь внесите это событие в код, расположенный за вашей страницей XAML.
private void lstBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listSelectedItems = ((ListBox) sender).SelectedItems;
ViewModel.YourListThatNeedsBinding = listSelectedItems.Cast<ObjectType>().ToList();
}
Тада. Сделано.
Это было сделано с помощью преобразования SelectedItemCollection в список .
Я не мог заставить решение Рейчел работать так, как я этого хотел, но я нашел ответ Sandesh о создании пользовательского свойства зависимости , чтобы отлично работать для меня. Мне просто пришлось написать аналогичный код для ListBox:
public class ListBoxCustom : ListBox
{
public ListBoxCustom()
{
SelectionChanged += ListBoxCustom_SelectionChanged;
}
void ListBoxCustom_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedItemsList = SelectedItems;
}
public IList SelectedItemsList
{
get { return (IList)GetValue(SelectedItemsListProperty); }
set { SetValue(SelectedItemsListProperty, value); }
}
public static readonly DependencyProperty SelectedItemsListProperty =
DependencyProperty.Register("SelectedItemsList", typeof(IList), typeof(ListBoxCustom), new PropertyMetadata(null));
}
В моей модели просмотра я просто ссылался на это свойство, чтобы получить список, выбранный мной.
Не удовлетворенными ответами, я пытался найти один сам ... Ну, похоже, это больше похоже на хак, а затем на решение, но для меня это хорошо работает. Это решение использует MultiBindings особым образом. Сначала это может показаться тонкой кода, но вы можете использовать его с минимальными усилиями.
Сначала я реализовал «IMultiValueConverter»
public class SelectedItemsMerger : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
SelectedItemsContainer sic = values[1] as SelectedItemsContainer;
if (sic != null)
sic.SelectedItems = values[0];
return values[0];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { value };
}
}
и контейнер SelectedItems Contraper / Wrapper:
public class SelectedItemsContainer
{
/// Nothing special here...
public object SelectedItems { get; set; }
}
Теперь мы создаем привязку для нашего ListBox.SelectedItem (Singular). Примечание. Вам необходимо создать статический ресурс для «Конвертера». Это можно сделать один раз для каждого приложения и повторно использовать для всех списков, которым нужен конвертер.
<ListBox.SelectedItem>
<MultiBinding Converter="{StaticResource SelectedItemsMerger}">
<Binding Mode="OneWay" RelativeSource="{RelativeSource Self}" Path="SelectedItems"/>
<Binding Path="SelectionContainer"/>
</MultiBinding>
</ListBox.SelectedItem>
В ViewModel я создал контейнер, с которым я могу привязываться. Важно инициализировать его новым (), чтобы заполнить его значениями.
SelectedItemsContainer selectionContainer = new SelectedItemsContainer();
public SelectedItemsContainer SelectionContainer
{
get { return this.selectionContainer; }
set
{
if (this.selectionContainer != value)
{
this.selectionContainer = value;
this.OnPropertyChanged("SelectionContainer");
}
}
}
И все. Может быть, кто-то видит некоторые улучшения? Что вы думаете об этом?
Вот еще одно решение. Это похоже на ответ Бена , но привязка работает двумя способами. Хитрость заключается в обновлении выбранных элементов ListBox
при изменении связанных элементов данных.
public class MultipleSelectionListBox : ListBox
{
public static readonly DependencyProperty BindableSelectedItemsProperty =
DependencyProperty.Register("BindableSelectedItems",
typeof(IEnumerable<string>), typeof(MultipleSelectionListBox),
new FrameworkPropertyMetadata(default(IEnumerable<string>),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnBindableSelectedItemsChanged));
public IEnumerable<string> BindableSelectedItems
{
get => (IEnumerable<string>)GetValue(BindableSelectedItemsProperty);
set => SetValue(BindableSelectedItemsProperty, value);
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
BindableSelectedItems = SelectedItems.Cast<string>();
}
private static void OnBindableSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is MultipleSelectionListBox listBox)
listBox.SetSelectedItems(listBox.BindableSelectedItems);
}
}
К сожалению, я не смог использовать IList
в качестве типа BindableSelectedItems. Это отправлено null
в свойство моей модели представления, тип которого IEnumerable<string>
.
Вот XAML:
<v:MultipleSelectionListBox
ItemsSource="{Binding AllMyItems}"
BindableSelectedItems="{Binding MySelectedItems}"
SelectionMode="Multiple"
/>
Есть одна вещь, о которой следует помнить. В моем случае из представления можно удалить ListBox
. По какой-то причине это приводит к тому, что свойство SelectedItems
изменяется на пустой список. Это, в свою очередь, приводит к изменению свойства модели представления в пустой список. В зависимости от вашего варианта использования это может быть нежелательно.
Выключает привязку флажка к свойству IsSelected и помещению текстового блока и флажка в панель стека делает трюк!
Это было серьезной проблемой для меня, некоторые из ответов, которые я видел, были либо слишком хакерскими, либо требовали сброса значения свойства SelectedItems
, нарушающего любой код, связанный со свойствами OnCollectionChanged. Но мне удалось получить работоспособное решение, изменив сбор непосредственно и в качестве бонуса он даже поддерживает SelectedValuePath
для коллекций объектов.
public class MultipleSelectionListBox : ListBox
{
internal bool processSelectionChanges = false;
public static readonly DependencyProperty BindableSelectedItemsProperty =
DependencyProperty.Register("BindableSelectedItems",
typeof(object), typeof(MultipleSelectionListBox),
new FrameworkPropertyMetadata(default(ICollection<object>),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnBindableSelectedItemsChanged));
public dynamic BindableSelectedItems
{
get => GetValue(BindableSelectedItemsProperty);
set => SetValue(BindableSelectedItemsProperty, value);
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
if (BindableSelectedItems == null || !this.IsInitialized) return; //Handle pre initilized calls
if (e.AddedItems.Count > 0)
if (!string.IsNullOrWhiteSpace(SelectedValuePath))
{
foreach (var item in e.AddedItems)
if (!BindableSelectedItems.Contains((dynamic)item.GetType().GetProperty(SelectedValuePath).GetValue(item, null)))
BindableSelectedItems.Add((dynamic)item.GetType().GetProperty(SelectedValuePath).GetValue(item, null));
}
else
{
foreach (var item in e.AddedItems)
if (!BindableSelectedItems.Contains((dynamic)item))
BindableSelectedItems.Add((dynamic)item);
}
if (e.RemovedItems.Count > 0)
if (!string.IsNullOrWhiteSpace(SelectedValuePath))
{
foreach (var item in e.RemovedItems)
if (BindableSelectedItems.Contains((dynamic)item.GetType().GetProperty(SelectedValuePath).GetValue(item, null)))
BindableSelectedItems.Remove((dynamic)item.GetType().GetProperty(SelectedValuePath).GetValue(item, null));
}
else
{
foreach (var item in e.RemovedItems)
if (BindableSelectedItems.Contains((dynamic)item))
BindableSelectedItems.Remove((dynamic)item);
}
}
private static void OnBindableSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is MultipleSelectionListBox listBox)
{
List<dynamic> newSelection = new List<dynamic>();
if (!string.IsNullOrWhiteSpace(listBox.SelectedValuePath))
foreach (var item in listBox.BindableSelectedItems)
{
foreach (var lbItem in listBox.Items)
{
var lbItemValue = lbItem.GetType().GetProperty(listBox.SelectedValuePath).GetValue(lbItem, null);
if ((dynamic)lbItemValue == (dynamic)item)
newSelection.Add(lbItem);
}
}
else
newSelection = listBox.BindableSelectedItems as List<dynamic>;
listBox.SetSelectedItems(newSelection);
}
}
}
Связывание работает так же, как вы ожидали бы, что MS сделана сама :
<uc:MultipleSelectionListBox
ItemsSource="{Binding Items}"
SelectionMode="Extended"
SelectedValuePath="id"
BindableSelectedItems="{Binding mySelection}"
/>
Он не был тщательно протестирован, но прошел проверку первого взгляда. Я пытался использовать его повторно, используя динамические типы в коллекциях.
IsSelected
для моделирования объектов? Я сделал это и немного запутался, особенно когда один и тот же экземпляр модельного объекта появляется в нескольких местах (в дереве). Когда один выбран, все они будут выбраны. Это не всегда желательно. Также мне кажется, что модель «загрязнена» View stuff. Каков ваш опыт? – paul 13 March 2013 в 11:59IsSelected
наDataContext
– Rachel 27 June 2013 в 16:54