7

我在后面的代码中动态创建 WPF 元素,并且对于Grid我正在构建的每一行,它由一个CheckBox和一个动态数字组成TextBoxes。需要的交互如下:

  • 如果TextBoxes一行中的所有值都为0,则将该CheckBox IsChecked属性设置为true并禁用它。
  • 如果其中之一TextBoxes从 更改0,则启用 CheckBox并设置IsCheckedfalse
  • 如果用户单击CheckBox,则将所有关联设置TextBoxes0并禁用CheckBox

我能够使用以下代码完成最后一个的第一部分:

Binding setScoreToZeroIfIsNormalChecked = new Binding("IsChecked");
setScoreToZeroIfIsNormalChecked.Source = this.NormalCheckBoxControl;
setScoreToZeroIfIsNormalChecked.Converter = m_NormalCheckBoxJointScoresConverter;
tempJointScoreControl.JointScoreContainer.SetBinding(ContainerBase.SingleAnswerProperty, setScoreToZeroIfIsNormalChecked);

和转换器:

public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    if (value is bool && targetType == typeof(Answer))
    {
        if ((bool)value)
        {
            Answer answer = new Answer();
            answer.Value = "0";
            answer.DisplayValue = "0";
            return answer;
        }
        else
            return null;
    }
    else
    {
        return null;
    }
}

但是,在尝试创建另一个转换器来完成其他功能时,我遇到了转换器相互踩踏的问题,因为所有功能都基于该CheckBox.IsChecked属性。

无论如何使用一个或两个多重绑定转换器来完成上述所有操作?我真的很想避免为了做到这一点而不得不创建一大堆事件并维护它们。

4

2 回答 2

13

这相对容易。一切都应该围绕 CheckBox IsChecked 属性解决。原因很简单,它是双向属性。所以要么你可以修改它,要么 CheckBox 可以修改它。

所以你做什么,你使用 MultiBinding,如下所示:

    MultiBinding multiBinding = new MultiBinding();
    multiBinding.Converter = multiBindingConverter;

    multiBinding.Bindings.Add(new Binding("Text") { Source = txtbox1});
    multiBinding.Bindings.Add(new Binding("Text") { Source = txtbox2});

    multiBinding.NotifyOnSourceUpdated = true;//this is important. 
    checkBox.SetBinding(CheckBox.IsCheckedProperty, multiBinding);

在您的 multiBindingConverter 中,您将 object[] 值作为第一个参数,您需要将其转换为 IList 并对其进行迭代 && 进行计算,如果您应该返回 true/false。(IsChecked=true 或 false)

现在将 CheckBox IsEnabled 绑定到 CheckBox IsChecked 属性,并使用 BooleanInverterConverter。(如果 CheckBox 被选中,则应禁用,反之亦然)

最后一步是让 TextBoxes 监听 CheckBox 的实际 IsChecked 属性。如果它是 TRUE,它们都应该显示 0 值,否则它们可以显示他们想要的。

因此,制作一个新的 MultiBinding。

    MultiBinding multiBinding = new MultiBinding();
    multiBinding.Converter = textboxMultiBindingConverter;

    multiBinding.Bindings.Add(new Binding("IsChecked") { Source = checkbox1});
    multiBinding.Bindings.Add(new Binding("Text") { Source = textbox1});

    multiBinding.NotifyOnSourceUpdated = true;//this is important. 
    textbox1.SetBinding(TextBox.Text, multiBinding);

textboxMultiBindingConverter 中的想法是如果 value[0]==FALSE 则返回 Text(value[1]) 或如果 value[0]==TRUE 则返回“0”。

于 2012-08-21T15:26:47.310 回答
1

如果您使用 MVVM,这个问题可以很容易地解决。

您将有一个 ViewModel 表示网格中的一行。每个文本框都有一个属性,复选框有一个属性。

此外,您将拥有一个包含 Grid 的 View 的 ViewModel,并且此 ViewModel 将公开一组行 ViewModel。

您所在行的 ViewModel:

public class AnswersViewModel : ViewModelBase // From MvvmLight
{
    public bool IsAnswered
    {
        get { return _isAnswered; }
        set
        {
            if(value == _isAnswered)
                return;
            _isAnswered = value;
            if(_isAnswered)
            {
                Answer1 = "0";
                Answer2 = "0";
            }

            RaisePropertyChanged("IsAnswered");
        }
    }

    public string Answer1
    {
        get { return _answer1; }
        set
        {
            if(value == _answer1)
                return;

            _answer1 = value;
            RaisePropertyChanged("Answer1");

            if(_answer1 == "0" && _answer2 == "0")
            {
                _isAnswered = true;
                RaisePropertyChanged("IsAnswered");
            }
        }
    }

    // The implementation of Answer2 is similar to Answer1
}

视图的视图模型:

public class FooViewModel : ViewModelBase
{
    public ObservableCollection<AnswersViewModel> Answers
    {
        get { return _answers; }
    }
}

您的视图将包含 GridItemsSource="{Binding Answers}"和 ControlTemplate 用于绑定到属性的项目AnswersViewModel

禁用复选框我将通过样式中的触发器进行处理。

于 2012-08-21T14:40:55.313 回答