2016-09-22 6 views
-1

Я нашел несколько вопросов о силимаре, но это не совсем то, что мне нужно. Я хочу привязать значение стека "IsEnabled" для значения "! IsIterrupted" для моих элементов. Вот мой XAML файл:WPF: двухсторонняя привязка данных не работает

<ListView ItemsSource="{Binding Path=Items}"> 
     <ListView.ItemTemplate> 
      <DataTemplate> 
       <StackPanel IsEnabled="{Binding !IsInterrupted, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"> 
        <Button Command="{Binding Path=StopThreadCommand, Source={StaticResource viewModel}}" CommandParameter="{Binding Id}"/> 
       </StackPanel> 
      </DataTemplate> 
     </ListView.ItemTemplate> 
    </ListView> 

Это как элементы выглядит следующим образом:

public class ThreadDecorator : BaseThread , INotifyPropertyChanged 
{ 
    ... 
    public event PropertyChangedEventHandler PropertyChanged; 

    private bool _is_interrupted; 
    public bool IsInterrupted 
    { 
     get { return _is_interrupted; } 
     set 
     { 
      _is_interrupted = value; 
      OnPropertyChanged("IsInterrupted"); 
     } 
    } 

    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
    ... 
} 

И мой ViewModel:

public class ThreadsViewModel : DependencyObject 
{ 

    private ThreadsModel _model; 
    public ThreadsModel Model 
    { 
     get { return _model; } 
     set 
     { 
      _model = value; 
     } 
    } 

    public ICollectionView Items 
    { 
     get { return (ICollectionView)GetValue(ItemsProperty); } 
     set { SetValue(ItemsProperty, value); } 
    } 

    public static readonly DependencyProperty ItemsProperty = 
     DependencyProperty.Register("Items", typeof(ICollectionView), typeof(ThreadsViewModel), new PropertyMetadata(null)); 

    public StopThreadCommand StopThreadCommand { get; set; } 

    public ThreadsViewModel() 
    { 
     this.Model = new ThreadsModel(); 
     Items = CollectionViewSource.GetDefaultView(Model.Threads); 
     this.StopThreadCommand = new StopThreadCommand(this); 
    } 

    public void InterruptThread(int id) 
    { 
     _model.InterruptThread(id); 
    } 
} 

StopThreadCommand:

public class StopThreadCommand : ICommand 
{ 
    public ThreadsViewModel ViewModel {get; set;} 
    public StopThreadCommand(ThreadsViewModel viewModel) 
    { 
     this.ViewModel = viewModel; 
    } 

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

    public void Execute(object parameter) 
    { 
     this.ViewModel.InterruptThread((int)parameter); 
    } 
} 

Когда я нажмите кнопку «Стоп», IsInterrupted значение меняется с false на true, а stackpanel должен быть отключен, но пользовательский интерфейс не обновляется. Помоги пожалуйста!

+0

Каков контекст данных панели стека? Вы видите какие-либо ошибки привязки при выполнении этой функции? – Versatile

+0

'! IsInterrupted'? Вы уверены, что '!' Будет работать так, как вы ожидаете? 'Binding.Path' не является произвольным выражением C#. Это строка, именующая свойство DataContext (или свойство одного из его свойств, если «Foo.Bar»). –

+0

Вот несколько решений для привязки к обратному логическому: http://stackoverflow.com/a/1039681/424129 - на самом деле один парень даже написал замену «Binding», которая * делает * позволяет вам сбрасывать логические значения: http://stackoverflow.com/a/27324780/424129 –

ответ

1

Свойство по умолчанию Binding is Path, являющееся путем перехода к объекту/подсобке DataContext. Это не произвольное выражение C#. Итак, вы устанавливаете Binding.Path в "!IsInterrupted". !IsInterrupted не будет оцениваться с булевым обратным значением IsInterrupted; он ничего не оценит. Это достану тебе это в выходной отладочный поток:

System.Windows.Data Error: 40 : BindingExpression path error: '!IsInterrupted' property not found on 'object' 'ThreadDecorator' blah blah blah

<StackPanel 
    IsEnabled="{Binding !IsInterrupted, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"> 

Один из способов сделать это write a boolean-inverse value converter (украденной дословно ответ Криса Никол, находящегося на другом конце that link):

[ValueConversion(typeof(bool), typeof(bool))] 
public class InverseBooleanConverter: IValueConverter 
{ 
    #region IValueConverter Members 

    public object Convert(object value, Type targetType, object parameter, 
     System.Globalization.CultureInfo culture) 
    { 
     if (targetType != typeof(bool)) 
      throw new InvalidOperationException("The target must be a boolean"); 

     return !(bool)value; 
    } 

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

    #endregion 
} 

Использование:

<UserControl.Resources> 
    <local:InverseBooleanConverter x:Key="InverseBooleanConverter" /> 
</UserControl.Resources> 

<!-- stuff etc. --> 

IsEnabled="{Binding Path=IsReadOnly, Converter={StaticResource InverseBooleanConverter}}" 

Вы также можете написать стиль с DataTrigger, который устанавливает IsEnabled в False, если IsInterrupted это правда.

+0

Большое спасибо! Вы решили мою проблему –

Смежные вопросы