禁用TabControl中的UserControl

时间:2015-08-06 08:41:50

标签: c# wpf xaml tabcontrol

我的应用程序包含TabControlTabItem个托管自定义UserControl的代码:

<TabControl>
    <TabItem Header="UC_1 and UC_2">
        <StackPanel>
            <local:UC_1/>
            <Separator/>
            <local:UC_2/>
        </StackPanel>
    </TabItem>
    <TabItem Header="UC_3">
        <local:UC_3/>
    </TabItem>
    <TabItem Header="UC_4">
        <local:UC_3/>
    </TabItem>
</TabControl>

UserControl对它们有许多不同的控制,如下所示:

<ScrollViewer>
    <StackPanel>
        <DockPanel>
            <TextBlock Text="Surname"/>
            <Border>
                <TextBox Text="{Binding Model.Surname}" />
            </Border>
        </DockPanel>
        <DockPanel>
            <TextBlock Text="Firstname" />
            <Border>
                <TextBox Text="{Binding Model.Firstname}" />
            </Border>
        </DockPanel>
    </StackPanel>
</ScrollViewer>

现在我想将整个TabControl设置为ReadOnly,具体取决于模型中的属性,因此用户仍然可以阅读但不能编辑控件的内容。
很遗憾,IsReadOnly不是TabControl的属性,也不是TabItemUserControl的属性。所以我决定改用IsEnabled - 属性。

但是,如果我禁用整个TabControl,则用户将无法在TabItems之间切换以读取数据,因为如果禁用这些数据则无法点击(这似乎是合法的,鉴于IsEnabled - 属性的含义。

所以,为了实现我的&#34;已禁用但仍然可点击的&#34; - TabItem,我尝试在Style内设置DataTrigger TabControl的资源,因此请停用UserControl内的TabItem而不是整个TabControlTabItem

<TabControl.Resources>
    <Style TargetType="{x:Type UserControl}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Model.TCEnabledProperty}" Value="9">
                <Setter Property="IsEnabled" Value="False"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</TabControl.Resources>

但这不起作用。

所以我改变了

<Style TargetType="{x:Type UserControl}"> 

<Style TargetType="{x:Type StackPanel}">

突然我得到了预期的行为(当然)如果给定的UserControlStackPanel托管所有其他控件,所有这些UserControl的情况并非如此。


现在的主要问题是:

为什么Style适用于TargetType = StackPanel而不适用于TargetType = UserControl?我不明白我可以访问内的 UserControl而不是UserControl本身。

如果没有其他选项,我只会向StackPanel添加一个包裹UserControl已经没有,但为了好奇,我想了解整个我在这里遇到的行为......

3 个答案:

答案 0 :(得分:1)

为什么不单独绑定每个TabItem的内容IsEnabled属性?

<TabItem Header="UC_1 and UC_2">
    <StackPanel IsEnabled="{Binding ...}"/> <!-- use converter if you can't create property called 'IsTCEnabled' in viewmodel -->
        <local:UC_1 />
        <Separator />
        <local:UC_2 />
    </StackPanel>
</TabItem>
<TabItem Header="UC_3">
    <local:UC_3 IsEnabled="{Binding ...}"/>
</TabItem>
<TabItem Header="UC_4">
    <local:UC_3 IsEnabled="{Binding ...}"/>
</TabItem>

您也可以创建样式以避免重复绑定:

<Style x:Key="TabContent" TargetType="FrameworkElement">
   <Setter Property="IsEnabled" Value="{Binding }" />
</Style>

<TabItem Header="UC_1 and UC_2">
    <StackPanel Style="{StaticResource TabContent}" />                      
        <local:UC_1 />
        <Separator />
        <local:UC_2 />
    </StackPanel>
</TabItem>
<TabItem Header="UC_3">
    <local:UC_3 Style="{StaticResource TabContent}" />
</TabItem>
<TabItem Header="UC_4">
    <local:UC_3 Style="{StaticResource TabContent}" />
</TabItem>

编辑:回答您的问题

  

为什么Style适用于TargetType = StackPanel但不适用于   TargetType = UserControl?

它很简单。 StackPanel样式有效,因为您已将StackPanel添加到第一个选项卡。 UserControl不起作用,因为您已将UC_1和UC_2添加到第二个选项卡。隐式样式不适用于继承的控件。 TargetType必须与元素的类型完全匹配。

答案 1 :(得分:0)

IsReadOnly依赖项属性添加到UserControl

<ScrollViewer>
    <StackPanel>
        <DockPanel>
            <TextBlock Text="Surname"/>
            <Border>
                <TextBox Text="{Binding Model.Surname}" />
            </Border>
        </DockPanel>
        <DockPanel>
            <TextBlock Text="Firstname" />
            <Border>
                <TextBlock x:Name="textBlock" Text="{Binding Model.Firstname}" />
                <TextBox x:Name="textBox" Text="{Binding Model.Firstname}"     />
            </Border>
        </DockPanel>
    </StackPanel>
</ScrollViewer>

和代码(可以使用绑定和转换器完成,x:Name - 方式只是更快的演示方式):

public bool IsReadOnly
{
    get { return (bool)GetValue(IsReadOnlyProperty); }
    set { SetValue(IsReadOnlyProperty, value); }
}
public static readonly DependencyProperty IsReadOnlyProperty =
    DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(MyUserControl), new PropertyMetadata(false, (d, e) =>
    {
        var userControl = (MyUserControl)s;
        var value = (bool)e.NewValue;
        userControl.textBlock.Visible = value ? Visibility.Visible : Visibility.Hidden;
        userControl.textBox.Visible = !value ? Visibility.Visible : Visibility.Hidden;
    }));

然后你应该可以在标签页中设置它:

<TabItem Header="MyUserControl">
    <local:MyUserControl IsReadOnly="{Binding SomeBinding}"/>
</TabItem>

答案 2 :(得分:0)

  

修改
  Liero为这个问题提供了更好的解决方案。我还在离开我的答案,因为当我想知道为什么我无法在我的视图中将Style应用于TargetType=UserControl时,我将基类与具体对象混淆,下面的文字可能帮助他人了解差异。

Sinatr回答的评论中的讨论引导我访问stackoverflow上的另一篇文章,在那里我找到了the solution to the question

为什么setter不适用于TargetType=UserControl

简短的回答是:

Style只能应用于具体对象

UserControl只是一个类,不是具体对象。具体对象是<local:UC_1/>

另一方面,StackPanels肯定具体对象,即使它们是在UserControl内的可视树下进一步托管,因此也是{{} 1}}可以应用。

此外,如果Style中的对象尚未设置Style,则Style似乎只能自上而下设置。{ 我试图从上到下设置的任何UserControl只会被视觉树内嵌套的Style再次覆盖(最后Style次胜利)。
这适用于StyleStyle中的对象设置的任何ResourceDirectory