XAML WPF(Avalonia)-是否在TabItem之外绘制控件(按钮)?

i7uq4tfw  于 2022-12-07  发布在  其他
关注(0)|答案(2)|浏览(256)

也许我想错了,但我的布局是在一个TabControl中有多个Expander,我想添加一个“全部展开”按钮。现在,逻辑上这个按钮应该在选项卡内,因为它将控制选项卡中的元素,所以它们应该被分组在一起。然而,从视觉上看,这将是一种空间浪费,因为我在标签标题栏上得到了很多空白空间(不确定术语是什么,带标签标题的行)。
所以,我尝试在标签内容之外添加一个按钮。canvas元素似乎是我需要使用的,它一直在重新定位元素,但它被切断了。用图片来解释要容易得多,所以x1c 0d1x

  • (如果仔细看,您可以看到按钮的位置,因为覆盖按钮的顶盖略微半透明)*

现在我可以通过将其移出TabItem来将其定位到我想要的位置,但之后我必须编写代码来查看哪个选项卡是焦点,并在它不是“当前”焦点时隐藏它。这对我来说听起来像是错误的方法,因为我唯一想做的事情就是移动一个“视图”类型的按钮。
我的主窗口轴:

<TabControl Grid.Row="1" Grid.Column="0" VerticalAlignment="Stretch">                   
    <TabItem Header="Current" ZIndex="1">
        <ScrollViewer Classes="CrawlersInAction">
            <StackPanel>
                <Canvas>
                    <Button Canvas.Right="10" Canvas.Top="-20" ZIndex="5">Expand All</Button>
                </Canvas>
                <!-- My very long template code for rendering the expanders -->
            </StackPanel>
        </ScrollViewer>
    </TabItem>
</TabControl>

我确实有HTML/CSS的背景,所以我认为Zindex会是窍门,并尝试在各个地方应用它,但没有任何运气。
PS:我使用的是Avalonia而不是WPF,但它几乎是一个跨平台的克隆,所以任何WPF的专有技术都可能超过1:1。

yzckvree

yzckvree1#

仔细想想,这个功能存在于ViewModel中,与Tab控件处于同一“级别”。

<Grid>
   <TabControl Items="{Binding MyTabViewModels}" SelectedItem={Binding SelectedTab} />
</Grid>

MyTabViewModel的示例上有一个集合:

public ObservableCollection<MyCollectionType> Items

项类MyCollectionType具有IsExpanded属性...

public bool IsExpanded {get;set;}

绑定到您的Expander控件IsExpanded属性。
把你的扣子塞进XAML

<Grid>
   <TabControl Items="{Binding MyTabViewModels}" />
   <Button Commmand={Binding ExpandAllCommand} />
</Grid>

现在,在ViewModel的基础上,ICommand可以执行以下操作:

public void ExpandAllCommandExecuted()
{
    foreach(var vm in SelectedTab.Items)
    {
        vm.IsExpanded = true;
    }
}

祝你好运,这都是伪代码,但说明了一个潜在的模式。

vktxenjb

vktxenjb2#

这个问题似乎是由于把我的<canvas>控件放在<scrollviewer>控件里面而引起的。我把它放在它外面,同时尝试了很多东西,它看起来像我想要的那样工作。按钮在标签栏(TabStrip)的顶部是可见的。
我的XAML现在是:

<TabControl Grid.Row="1" Grid.Column="0" VerticalAlignment="Stretch">
    <TabItem Header="Current">
        <StackPanel>
            <Canvas>
                <StackPanel Orientation="Horizontal" Canvas.Right="0" Canvas.Bottom="10" Spacing="5">
                    <Button Command="{Binding CollapseAll}" IsEnabled="{Binding !AllAreCollapsed}">Collapse All</Button>
                    <Button Command="{Binding ExpandAll}"   IsEnabled="{Binding !AllAreExpanded}">Expand All</Button>
                </StackPanel>
            </Canvas>

            <ScrollViewer Classes="CrawlersInAction">
                <StackPanel>
                    <ItemsControl Name="itemscontrol" Items="{Binding SiteInfos}" VerticalAlignment="Stretch">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Expander ExpandDirection="Down" IsExpanded="{Binding IsExpanded, Mode=TwoWay}" VerticalAlignment="Stretch">
                                    <!-- Ommited my very long template code -->
                                </Expander>
                            <DataTemplate>
                        <ItemsControl.ItemTemplate>
                    <ItemsControl>
                </StackPanel>
            </ScrollViewer>
        </StackPanel>
    </TabItem>
</TabControl>

最后,我在代码方面向SiteInfo类添加了一个“IsExpanded”属性,该属性用作扩展器IsExpanded属性的基础,并通过按照上面的XAML使其成为双向绑定来保持同步。SiteInfo上的代码如下:

public class SiteInfo : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        public static readonly bool StartIsExpanded = true;
        private bool _isExpanded = StartIsExpanded;
        public bool IsExpanded
        {
            get { return _isExpanded; }
            set
            {
                if (value != IsExpanded)
                {
                    _isExpanded = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsExpanded)));
                }
            }
        }

当我在MainWindowViewModel中创建我的SiteInfo对象时,我订阅了事件(siteInfo.PropertyChanged += SiteInfo_PropertyChanged;)。当接收到事件时,如果我的折叠或展开所有按钮应被禁用,它将发生变化,它将发送自己的PropertyChangedEvent,然后启用/禁用控件。

public class MainWindowViewModel : ViewModelBase, INotifyPropertyChanged
    {

        public new event PropertyChangedEventHandler? PropertyChanged;
        public ObservableCollection<SiteInfo> SiteInfos { get; } 
            = new ObservableCollection<SiteInfo>();

        //Change SiteInfo.StartExpanded if you want this changed.
        private bool _allAreExpanded = SiteInfo.StartIsExpanded;
        public bool AllAreExpanded
        {
            get => _allAreExpanded;
            set
            {
                if (_allAreExpanded != value)
                {
                    _allAreExpanded = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AllAreExpanded)));
                }
            }
        }
        //Change SiteInfo.StartExpanded if you want this changed.
        private bool _allAreCollapsed = !SiteInfo.StartIsExpanded;
        public bool AllAreCollapsed {
            get { return _allAreCollapsed; }
            set {
                if (_allAreCollapsed != value)
                {
                    _allAreCollapsed = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AllAreCollapsed)));
                }
            }
        }

        private void SiteInfo_PropertyChanged(object? sender, PropertyChangedEventArgs e)
        {
            if(e.PropertyName == nameof(siteInfo.IsExpanded))
            {
                AllAreCollapsed = AreAllCollapsed();
                AllAreExpanded = AreAllExpanded();
            }
        }

        public bool AreAllCollapsed()
        {
            return !SiteInfos.Any<SiteInfo>( siteInfo => siteInfo.IsExpanded );
        }

        public bool AreAllExpanded()
        {
            return !SiteInfos.Any<SiteInfo>( siteInfo => siteInfo.IsCollapsed);
        }

        public void CollapseAll()
        {
            foreach(SiteInfo siteInfo in SiteInfos)
            {
                siteInfo.IsExpanded = false;
            }
        }
        public void ExpandAll()
        {
            foreach (SiteInfo siteInfo in SiteInfos)
            {
                siteInfo.IsExpanded = true;
            }
        }
    }

我想我会添加我的代码的其余部分,以防有人谷歌这一点,并希望做类似的事情。
现在,当我的程序加载并且所有内容都设置为默认展开true时,“全部展开”被禁用,“全部折叠”被启用。将一个展开器更改为折叠状态将启用两个按钮,而折叠所有展开器将禁用"全部折叠“按钮。x1c 0d1x

相关问题