【问题标题】:WPF User control binding issueWPF用户控件绑定问题
【发布时间】:2010-12-09 05:00:18
【问题描述】:

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

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

现在,我想在我的主窗口中拥有许多这样的控件,并将它们都绑定到一个 bool 属性。当通过按钮更改该属性时,我希望所有 TextBlocks 都变成 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));

【问题讨论】:

  • 我建议分解问题。您确定您的可编辑绑定有效吗?要对此进行测试,您可以将 {Binding Path=Editable} 绑定复制到常规 TextBlock 中,并查看单击按钮时是否切换真假。如果该绑定有效,则在您的 EditableModePropertyCallBack 方法中设置一个断点并确保它被命中。如果遇到断点,则单步执行它并确保它按预期执行。告诉我你得到了什么结果。
  • 我会试一试并发布更新。非常感谢您的帮助!

标签: wpf user-controls binding


【解决方案1】:

看起来您的解决方案可能比必要的复杂。如果您只想让禁用的 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>

【讨论】:

  • 这真的很酷,谢谢。我唯一的问题是,这个解决方案是否允许我做这样的事情:一旦其中的值改变文本框边框为红色。单击切换按钮时,下次显示文本框时,它会将边框恢复为原始值吗?另外,知道为什么我以前的解决方案不起作用吗?非常感谢!!!
  • 我不太确定您在问什么,但是您可以使用 Trigger 和 DataTrigger 做很多事情。例如,您可以使用触发器中的设置器更改边框画笔,以检查 Text 是否为 {x:Null} 或 Text.Length 为 0。
  • 谢谢!!当这正是我需要的时候,我还试图做一些过于复杂的事情。
【解决方案2】:

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

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

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

在绑定标签中指定 ElementName 并使用 x:FieldName 或 x:Name 命名您的用户控件

【讨论】:

  • 那也没用。可编辑也是主窗口的属性,而不是用户控件。并且主窗口的数据上下文设置为 self:DataContext="{Binding RelativeSource={RelativeSource Self}}
  • 然后将 elementname 设置为主窗口,给它起一个名字并尝试一下。
【解决方案3】:

我只是在寻找其他东西时遇到了这个问题。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-07
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    相关资源
    最近更新 更多