绑定不适用于ViewModel

时间:2016-05-18 10:03:14

标签: c# wpf xaml mvvm

我想根据布尔值更改矩形的填充。我有以下课程。

扩展INotifyPropertyChanged的基类:

public class PropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

型号:

public class ChangingVariable : PropertyChangedBase
{
    public ChangingVariable()
    {
        Variable = true;
    }

    private bool _variable;

    public bool Variable
    {
        get
        {
            return _variable;
        }

        set
        {
            if (_variable.CompareTo(value) != 0)
            {
                _variable = value;
                OnPropertyChanged();
            }
        }
    }
}

视图模型:

public class BooleanRectangleViewModel : PropertyChangedBase
{
    public ChangingVariable Model { get; set; }
}

这是我的工作的视图(填充为灰色):

XAML:

<UserControl.DataContext>
    <viewModels:BooleanRectangleViewModel x:Name="ViewModel"/>
</UserControl.DataContext>

<Rectangle x:Name="Rectangle">
    <Rectangle.Style>
        <Style TargetType="{x:Type Rectangle}">
            <Setter Property="Fill" Value="Gray" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Model.Variable}" Value="true">
                    <Setter Property="Fill" Value="GreenYellow" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Rectangle.Style>
</Rectangle>

CS:

public partial class BooleanRectangleView
{
    public BooleanRectangleView()
    {
        InitializeComponent();
        ViewModel.Model = new ChangingVariable();
    }
}

但是当我更改它以使数据上下文是Model而不是ViewModel时,它可以工作(Fill为绿色):

XAML:

<UserControl.DataContext>
    <models:ChangingVariable x:Name="ViewModel" />
</UserControl.DataContext>

<Rectangle x:Name="Rectangle">
    <Rectangle.Style>
        <Style TargetType="{x:Type Rectangle}">
            <Setter Property="Fill" Value="Gray" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Variable}" Value="true">
                    <Setter Property="Fill" Value="GreenYellow" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Rectangle.Style>
</Rectangle>

CS:

public partial class BooleanRectangleView
{
    public BooleanRectangleView()
    {
        InitializeComponent();
        ViewModel = new ChangingVariable();
    }
}

为什么它不适用于中间的ViewModel?

3 个答案:

答案 0 :(得分:2)

你想要的是颜色转换的bool,所以我会写这个类:

public class BooleanToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var isTrue = (bool) value;

        if (isTrue)
            return new SolidColorBrush(Colors.Green);

        return new SolidColorBrush(Colors.Red);
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

然后在你的XAML绑定中建议这个转换器。有关使用valueconverters的完整文档,请查看此处: http://www.wpf-tutorial.com/data-binding/value-conversion-with-ivalueconverter/

答案 1 :(得分:1)

据我所知,当您在模板或样式中进行绑定时,最好使用RelativeSource。我不是绝对肯定,但你可以尝试:

<Rectangle x:Name="Rectangle">
    <Rectangle.Style>
        <Style TargetType="{x:Type Rectangle}">
            <Setter Property="Fill" Value="Gray" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding DataContext.Model.Variable, RelativeSource={RelativeSource AncestorType=UserControl}}" Value="true">
                    <Setter Property="Fill" Value="GreenYellow" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Rectangle.Style>
</Rectangle>



更新

我对WPF / MVVM也很陌生,但我想分享一下我在短短两到三个月内学到的东西,这可能有助于其他人解决绑定问题。

每当绑定不起作用时,最可能的原因是绑定引擎无法找到绑定源或源属性。实现INotifyPropertyChanged(或使用DependencyProperty)只是提供了一种方法,可以在源属性的值发生更改时通知绑定。如果删除该部分,绑定将像OneTime模式一样工作。原因很简单 - 绑定引擎足够智能,知道它必须从source属性中获取值才能使target属性起作用。

例如,您有<Border BorderBrush="{Binding MyBorderColor}" ....>。当您的控件即将渲染时,控件需要知道边框的颜色,否则无法继续渲染。绑定引擎被强制搜索源属性MyBorderColor。如果绑定失败,则BorderBrush目标属性将不会获得值,这将导致Border使用任何默认值或继承值。如果MyBorderColor没有实施&#39; INotifyPropertyChanged&#39;也不是DependencyProperty,那么如果MyBorderColor在运行时期间更改值一段时间,它将不会反映在BorderBrush中,因为绑定引擎不知道源属性已更改。

答案 2 :(得分:1)

您的属性Model是自动属性,即它不实现getter或setter和OnPropertyChanged。尝试从

更改Model属性
public ChangingVariable Model { get; set; }

private ChangingVariable model;
public ChangingVariable Model 
{ 
   get
   {
      return model;
   }
   set
   {
      model = value;
      OnPropertyChanged("Model");
   }

原因是自动属性不会通知UI他们已经更改。即使底层属性正在更改。你必须基本上为Model调用OnPropertyChanged方法。希望这会有所帮助。