WPF用户控件绑定问题

时间:2009-10-22 18:25:02

标签: wpf user-controls binding

这应该是一个非常简单的案例,但我正试图让它发挥作用。这是设置:

我正在设计一个应用程序,它将为某些数据提供只读模式和编辑模式。所以我创建了一个用户控件,它是一个绑定到相同文本数据的文本框和文本块,并且基于EditableMode属性有条件可见(所以当它可编辑时,显示文本框,当它不显示文本块时)

现在,我希望在我的主窗口中有许多这些控件,并且它们都绑定了一个bool属性。当通过按钮更改该属性时,我希望所有TextBlock都变成TextBoxes或返回。

我的问题是控件在绑定时设置正确,如果我执行myUserControl.Editable = true。但是如果将它绑定到bool属性则不会改变。

以下是我的用户控件的代码:

<UserControl x:Class="CustomerCareTool.Controls.EditableLabelControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:CustomerCareTool.Converters"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<UserControl.Resources>
    <src:BoolToVisibility x:Key="boolToVisibility" Inverted="False" />
    <src:BoolToVisibility x:Key="invertedBoolToVisibility" Inverted="True" />
</UserControl.Resources>
<Grid>
    <TextBlock Name="textBlock" Text="{Binding Path=TextBoxValue}" Visibility="{Binding Path=EditableMode, Converter={StaticResource invertedBoolToVisibility}}"/>
    <TextBox Name="textBox" Visibility="{Binding Path=EditableMode, Converter={StaticResource boolToVisibility}}">
        <TextBox.Text>
            <Binding Path="TextBoxValue" UpdateSourceTrigger="PropertyChanged"/>
        </TextBox.Text>
    </TextBox>
</Grid>

我使用转换器将bool转换为可见性,并将bool转换为可见性。不确定这里是否需要。

这就是背后的代码:

public partial class EditableLabelControl : UserControl
{
    public EditableLabelControl()
    {
        InitializeComponent();
    }

    public string TextBoxValue
    {
        get { return (string)GetValue(TextBoxValueProperty); }
        set { SetValue(TextBoxValueProperty, value); }
    }

    public static readonly DependencyProperty TextBoxValueProperty =
        DependencyProperty.Register("TextBoxValue", typeof(string), typeof(EditableLabelControl), new UIPropertyMetadata());


    public bool EditableMode
    {
        get { return (bool)GetValue(EditableModeProperty); }
        set { SetValue(EditableModeProperty, value); }
    }

    public static readonly DependencyProperty EditableModeProperty =
        DependencyProperty.Register("EditableMode", typeof(bool),typeof(EditableLabelControl), new UIPropertyMetadata(false, EditableModePropertyCallBack));

static void EditableModePropertyCallBack(DependencyObject property,
DependencyPropertyChangedEventArgs args)
    {
        var editableLabelControl = (EditableLabelControl)property;
        var editMode = (bool)args.NewValue;

        if (editMode)
        {
            editableLabelControl.textBox.Visibility = Visibility.Visible;
            editableLabelControl.textBlock.Visibility = Visibility.Collapsed;
        }
        else
        {
            editableLabelControl.textBox.Visibility = Visibility.Collapsed;
            editableLabelControl.textBlock.Visibility = Visibility.Visible; 
        }
    }
}

现在在我的主应用程序中,我添加了如下控件:

<Controls:EditableLabelControl x:Name="testCtrl" EditableMode="{Binding Path=Editable}" TextBoxValue="John Smith" Grid.Row="0"/>

对于同一个应用程序,DataContext设置为self

DataContext="{Binding RelativeSource={RelativeSource Self}}"

背后的代码如下:

public partial class OrderInfoView : Window, INotifyPropertyChanged

{
    public OrderInfoView()
    {
        InitializeComponent();
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        Editable = !Editable;
    }

    private bool _editable = false;
    public bool Editable
    {
        get
        {
            return _editable;
        }
        set
        {
            _editable = value;
            OnPropertyChanged("Editable");
        }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged == null) return;

        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }


    public event PropertyChangedEventHandler PropertyChanged;
}

单击按钮不会执行任何操作:(我尝试了所有操作,并且没有骰子。非常感谢一些帮助!


我尝试了以下操作,但仍无效:

  public bool Editable
    {
        get { return (bool)GetValue(EditableProperty); }
        set { SetValue(EditableProperty, value); }
    }

    public static readonly DependencyProperty EditableProperty =
        DependencyProperty.Register("Editable", typeof(bool), typeof(OrderInfoView), new UIPropertyMetadata(false));

3 个答案:

答案 0 :(得分:2)

看起来您的解决方案可能比必要的更复杂。如果你想要做的就是让一个禁用的TextBox看起来像TextBlock,那么你可以使用触发器和模板来做到这一点。然后,您可以将该样式应用于所有文本框。

以下是该方法的一个示例:

<Window x:Class="WpfApplication25.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" 
        Height="300" 
        Width="300"
        >

    <Window.Resources>

        <!-- Disable TextBox Style -->
        <Style x:Key="_DisableTextBoxStyle" TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="TextBox">
                                <!-- 
                                Be sure to apply all necessary TemplateBindings between
                                the TextBox and TextBlock template.
                                -->
                                <TextBlock Text="{TemplateBinding Text}"
                                           FontFamily="{TemplateBinding FontFamily}"
                                           />
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>

    </Window.Resources>

    <StackPanel>
        <TextBox IsEnabled="{Binding IsChecked, ElementName=uiIsEnabled}"
                 Style="{StaticResource _DisableTextBoxStyle}"
                 />

        <ToggleButton x:Name="uiIsEnabled" Content="Enable" IsChecked="True" />
    </StackPanel>
</Window>

答案 1 :(得分:0)

INotifyPropertyChanged不适用于从DependencyObject派生的类。

OrderInfoView中的可编辑属性必须是依赖属性才能使绑定正常工作,虽然从技术上讲你的代码是正确的但我觉得WPF中的错误是当对象是依赖对象时它会忽略INotifyPropertyChanged事件,因为它在属性中搜索通知系统

<Controls:EditableLabelControl x:Name="testCtrl" 
EditableMode="{Binding Path=Editable,ElementName=userControl}" TextBoxValue="John Smith" Grid.Row="0"/>

在绑定标记中指定ElementName,并使用x命名usercontrol:FieldName或x:Name

答案 2 :(得分:0)

我刚刚遇到了其他搜索内容。

如果没有详细阅读你的帖子(没时间抱歉),在我看来,你遇到的问题与我在这里发布的问题类似: http://jonsblogat.blogspot.com/2009/11/wpf-windowdatacontext-and.html

简而言之,将主窗口的绑定移动到网格并使用相对绑定来查看是否可以解决问题。