2009-12-15 3 views
3

Использование стиля MVVM Я успешно связал ObservableCollection<string> с ListBox, показывая значения как RadioButton s. Управление ведет себя точно так, как ожидалось.WPF Bind Textbox IsEnabled to Listbox SelectedItem

Теперь у меня есть вопрос относительно некоторых TextBox й лет, связанных с этим ListBox: Я хочу, чтобы каждый раз, когда SelectedItem в ListBox равен определенное значение (например ValueForEnabled) в TextBox эсов быть включены в противном случае они должны быть отключены.

Я знаю, что мне нужно привязать к SeletedItem из ListBox (по имени lbSource), но как это делается?

Я хочу что-то вроде этого (псевдо-код):

<TextBox ... 

    IsEnabled="{Binding ElementName=lbSource, Path=SelectedItem='ValueForEnabled', 
       Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
       ...    
/> 

ответ

6

ОК! Решил его (по-другому) сам! Для тех, кто хочет знать:

<TextBox 
... 
usual property definitions 
... 
         > 
       <TextBox.Style> 
        <Style> 
         <Setter Property="TextBox.IsEnabled" Value="False"/> 
         <Style.Triggers>        
          <DataTrigger Binding="{Binding ElementName=lbSource , Path=SelectedItem}" Value="ValueForEnabled"> 
           <Setter Property="TextBox.IsEnabled" Value="true"/> 
          </DataTrigger>       
         </Style.Triggers>      
        </Style>     
       </TextBox.Style> 
      </TextBox> 
2

Один способ кожи этого кота будет путем преобразования строки (в ListBox) в Ьоо перейти в IsEnabledProperty ...

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

public class StringToBoolConverter : IValueConverter 
{ 
    #region IValueConverter Members 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     if (value == null) 
      return false; 

     string keyword = value.ToString(); 
     if (keyword.Equals(parameter.ToString(), StringComparison.CurrentCultureIgnoreCase)) 
      return true; 
     return false; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 

    #endregion 
} 

Обратите внимание, как вам не нужно реализовать метод ConvertBack? Это потому, что вам нужно всего лишь повернуть строки в BOOLS, а не наоборот ...

Таким образом, вы можете объявить экземпляр вашего преобразователя в XAML, как

<Window 
    ... 
    xmlns:local="clr-namespace:WpfApplication1"> 

    <Window.Resources> 
     <local:StringToBoolConverter x:Key="stringToBoolConverter" /> 
    </Window.Resources> 

И, наконец, вы можете привязать TextBox к SelectedValue в ListBox, как и:

<TextBox Grid.Row="0" Width="90" Height="30" 
     IsEnabled="{Binding ElementName=lbSource, Path=SelectedValue, Converter={StaticResource stringToBoolConverter}, ConverterParameter=ValueForEnabled}"> 
</TextBox> 

Примечание: Это будет работать только если ListBox содержит строки, и вы можете быть уверены, что свойство SelectedValue является строкой ...

+0

Интересный подход! Я бы хотел избежать использования преобразователей (это может показаться глупым, но я чувствую, что мой код каким-то образом ... разбросан вокруг, но я, конечно, использовал бы их, если бы не было сделано иначе - как). Плюс для ответа быстро! Большое спасибо! –

2

Лично я считаю, что если вы используете MVVM, то вы должны иметь код останется в вашей ViewModel. так что если ваш VM, как это:

public class MyViewModel 
{ 
    public ObservableCollection<string> myColl {get;set;} 
    public string SelectedString {get;set;} 

    public bool IsEnabled 
    { 
    get { return SelectedString == "Desired string value";} 
    } 
} 

Вы тогда просто свяжи Textboxes IsEnabled свойство вашей собственности IsEnabled на вашем ViewModel

Поэтому я говорю, что это ваши требования могут измениться, когда иметь что Textboxes включен, и если вы делаете это таким образом, вы не должны трогать вид (где код/​​логика не должна находиться)

Так что теперь вы делаете это на ваш взгляд, и то это

<TextBox IsEnabled={Binding IsEnabled} Text={Binding SelectedString}/> 

Hope Я понимаю вашу проблему и что это помогает

+0

Сначала я подумал: «Зачем это так»? потому что вы предлагаете не помещать какую-либо «логику» (например, я делаю) в XAML, а в виртуальную машину. Включение (или отсутствие) текстового поля тесно связано с XAML (я имею в виду, если я хочу «настроить» свойство UI-элемента, я сделаю это в XAML, поэтому я увижу, что есть что-то (или нет)). Итак (как я понимаю) вы передаете решение в другое место на той же арене! Единственное, что мне не нравится, это позволить VM-коду «загромождать». Спасибо, Хосе! –

+0

Ваша виртуальная машина должна иметь весь код, ваш взгляд должен перевести это на некоторое видимое представление (иногда с использованием конвертеров). Это может быть отключение, создание невидимого, появление какого-либо уведомления. Вашей виртуальной машине все равно, что это такое, но она должна знать, что существует определенное состояние. Затем представление связывается с этим свойством. Наиболее близким к коду, который должен быть в представлении, является Преобразователь, потому что это отделяет ваш вид от вашей виртуальной машины. Например. конвертер boolean to visibility позволяет вашей виртуальной машине иметь логическое свойство, в то время как представление переводит это логическое значение в «Свернутое» или «Видимое »21. – Jose

+0

. Ваш взгляд в основном просто визуальный переводчик. Он переводит списки в поле со списком, список или список. Строка, int, long, DateTime в текстовое поле. Конечно, ваш «Просмотр» и «ВМ» «соединены», но только в том смысле, что ваше мнение должно знать, что он переводит. Ваш вид должен знать ViewModel, но ViewModel никогда не должен знать о вашем представлении, когда это происходит, разделение проблем, которые вызывает MVVM, серьезно скомпрометировано. Я должен был бы поместить виртуальную машину в приложение Winforms и не требовать какого-либо изменения кода, просто переписывая новый желаемый вид, но WPF проще :) – Jose