WPF:双向数据绑定不起作用

时间:2016-09-22 16:30:10

标签: c# wpf data-binding

我发现了一些silimar问题,但这些并不是我所需要的。 我想将stackpanel“IsEnabled”值绑定到我的项目的bool“!IsIterrupted”值。这是我的XAML文件:

<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,但UI不会更新。求救!

1 个答案:

答案 0 :(得分:1)

Binding is Path的默认属性,它是DataContext的属性/子属性的路径。它不是一个任意的C#表达式。因此,您要将Binding.Path设置为"!IsInterrupted"!IsInterrupted不会评估IsInterrupted的布尔逆;它不会评估任何东西。它会在调试输出流中找到你:

  

System.Windows.Data错误:40:BindingExpression路径错误:&#39;!IsInterrupted&#39;在&#39; object&#39;上找不到的属性&#39; ThreadDecorator&#39; blah blah blah

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

这样做的一种方法是write a boolean-inverse value converter(来自Chris Nicol的逐字逐句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