首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UWP CommandBar结合

UWP CommandBar结合
EN

Stack Overflow用户
提问于 2018-03-22 08:27:06
回答 2查看 794关注 0票数 1

是否有可能将UWP CommandBar绑定到类似于ObservableCollection之类的东西上?

我想要实现的东西是将我的CommandBarNavigationView绑定到特定Page的对象上,以便AppBarButton根据当前的Page动态变化。

我试过的是:

MainPage.xaml

代码语言:javascript
复制
    <NavigationView.HeaderTemplate>
        <DataTemplate>
            <Grid>
                <CommandBar Grid.Column="1"
                        HorizontalAlignment="Right"
                        VerticalAlignment="Top"
                        DefaultLabelPosition="Right"
                        Background="{ThemeResource SystemControlBackgroundAltHighBrush}"  Content="{Binding Path=Content.AppBarButtonList, ElementName=rootFrame}">
                </CommandBar>
            </Grid>
        </DataTemplate>
    </NavigationView.HeaderTemplate>

SomePage.xaml.cs

代码语言:javascript
复制
    public ObservableCollection<AppBarButton> AppBarButtonList = new ObservableCollection<AppBarButton> {
        new AppBarButton { Icon = new SymbolIcon(Symbol.Accept), Label="Bla" },
        new AppBarButton{Icon=new SymbolIcon(Symbol.Add),Label="Add"}
    };

但是CommandBar什么也没有显示出来。

谢谢。

EN

回答 2

Stack Overflow用户

发布于 2018-03-22 08:29:55

我最初的解决方案是使用PrimaryCommands属性绑定命令,但结果是该属性是只读的。

我对这个问题的解决办法是使用行为。

首先从Microsoft.Xaml.Behaviors.Uwp.Managed添加一个来自NuGet的引用。

然后将以下行为添加到项目中:

代码语言:javascript
复制
public class BindableCommandBarBehavior : Behavior<CommandBar>
{
    public ObservableCollection<AppBarButton> PrimaryCommands
    {
        get { return (ObservableCollection<AppBarButton>)GetValue(PrimaryCommandsProperty); }
        set { SetValue(PrimaryCommandsProperty, value); }
    }

    public static readonly DependencyProperty PrimaryCommandsProperty = DependencyProperty.Register(
        "PrimaryCommands", typeof(ObservableCollection<AppBarButton>), typeof(BindableCommandBarBehavior), new PropertyMetadata(default(ObservableCollection<AppBarButton>), UpdateCommands));

    private static void UpdateCommands(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        if (!(dependencyObject is BindableCommandBarBehavior behavior)) return;
        var oldList = dependencyPropertyChangedEventArgs.OldValue as ObservableCollection<AppBarButton>;
        if (dependencyPropertyChangedEventArgs.OldValue != null)
        {
            oldList.CollectionChanged -= behavior.PrimaryCommandsCollectionChanged;
        }

        var newList = dependencyPropertyChangedEventArgs.NewValue as ObservableCollection<AppBarButton>;
        if (dependencyPropertyChangedEventArgs.NewValue != null)
        {
            newList.CollectionChanged += behavior.PrimaryCommandsCollectionChanged;
        }
        behavior.UpdatePrimaryCommands();
    }


    private void PrimaryCommandsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        UpdatePrimaryCommands();
    }


    private void UpdatePrimaryCommands()
    {
        if (PrimaryCommands != null)
        {
            AssociatedObject.PrimaryCommands.Clear();
            foreach (var command in PrimaryCommands)
            {
                AssociatedObject.PrimaryCommands.Add(command);
            }
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        if (PrimaryCommands != null)
        {
            PrimaryCommands.CollectionChanged -= PrimaryCommandsCollectionChanged;
        }
    }
}

此行为实质上创建了一个可绑定的假PrimaryCommands属性,并观察集合更改的事件。每当发生更改时,都会重新生成命令。

最后,代码中的问题是您的AppBarButtonList只是一个字段,而不是属性。像这样改变它:

代码语言:javascript
复制
public ObservableCollection<AppBarButton> AppBarButtonList { get; } = new ObservableCollection<AppBarButton> {
    new AppBarButton { Icon = new SymbolIcon(Symbol.Accept), Label="Bla" },
    new AppBarButton{Icon=new SymbolIcon(Symbol.Add),Label="Add"}
};

注意在赋值运算符之前添加的{get ;}

现在,您可以在XAML中使用以下行为:

代码语言:javascript
复制
<CommandBar>
    <interactivity:Interaction.Behaviors>
        <local:BindableCommandBarBehavior PrimaryCommands="{Binding Path=Content.AppBarButtonList, ElementName=rootFrame}" />
    </interactivity:Interaction.Behaviors>
</CommandBar>

这绝不是一个完美的解决方案,可以改进,以允许不同的集合类型绑定和更多,但它应该涵盖您的场景。另一种解决方案是实现命令栏的自定义版本,直接在类型上添加新的附加依赖项属性,但我使用行为使用户更清楚地知道,这是“添加”的功能,而不是内置的功能。

票数 3
EN

Stack Overflow用户

发布于 2018-06-22 14:16:26

我发现这个答案很有帮助。我做了一些更多的调整,比如使用DataTemplateSelector从可绑定数据源中删除UI引用(如"AppBarButton“)。

代码语言:javascript
复制
public class BindableCommandBarBehavior : Behavior<CommandBar>
{
    public static readonly DependencyProperty PrimaryCommandsProperty = DependencyProperty.Register(
        "PrimaryCommands", typeof(object), typeof(BindableCommandBarBehavior),
        new PropertyMetadata(null, UpdateCommands));

    public static readonly DependencyProperty ItemTemplateSelectorProperty = DependencyProperty.Register(
        "ItemTemplateSelector", typeof(DataTemplateSelector), typeof(BindableCommandBarBehavior),
        new PropertyMetadata(null, null));

    public DataTemplateSelector ItemTemplateSelector
    {
        get { return (DataTemplateSelector)GetValue(ItemTemplateSelectorProperty); }
        set { SetValue(ItemTemplateSelectorProperty, value); }
    }

    public object PrimaryCommands
    {
        get { return  GetValue(PrimaryCommandsProperty); }
        set { SetValue(PrimaryCommandsProperty, value); }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        if (PrimaryCommands is INotifyCollectionChanged notifyCollectionChanged)
        {
            notifyCollectionChanged.CollectionChanged -= PrimaryCommandsCollectionChanged;
        }
    }

    private void UpdatePrimaryCommands()
    {
        if (AssociatedObject == null)
            return;

        if (PrimaryCommands == null)
            return;

        AssociatedObject.PrimaryCommands.Clear();

        if (!(PrimaryCommands is IEnumerable enumerable))
        {
            AssociatedObject.PrimaryCommands.Clear();
            return;
        }


        foreach (var command in enumerable)
        {
            var template = ItemTemplateSelector.SelectTemplate(command, AssociatedObject);

            if (!(template?.LoadContent() is FrameworkElement dependencyObject))
                continue;

            dependencyObject.DataContext = command;

            if (dependencyObject is ICommandBarElement icommandBarElement)
                AssociatedObject.PrimaryCommands.Add(icommandBarElement);
        }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        UpdatePrimaryCommands();
    }

    private void PrimaryCommandsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        UpdatePrimaryCommands();
    }

    private static void UpdateCommands(DependencyObject dependencyObject,
        DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        if (!(dependencyObject is BindableCommandBarBehavior behavior)) return;
        if (dependencyPropertyChangedEventArgs.OldValue is INotifyCollectionChanged oldList)
        {
            oldList.CollectionChanged -= behavior.PrimaryCommandsCollectionChanged;
        }

        if (dependencyPropertyChangedEventArgs.NewValue is INotifyCollectionChanged newList)
        {
            newList.CollectionChanged += behavior.PrimaryCommandsCollectionChanged;
        }

        behavior.UpdatePrimaryCommands();
    }
}

DataTemplateSelector:

代码语言:javascript
复制
public class CommandBarMenuItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate CbMenuItemTemplate { get; set; }


    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        if (item is ContextAction)
        {
            return CbMenuItemTemplate;
        }

        return base.SelectTemplateCore(item, container);
    }
}

模板Xaml:

代码语言:javascript
复制
 <DataTemplate x:Key="CbMenuItemTemplate">
    <AppBarButton
        Command="{Binding Command}"
        Icon="Add"
        Label="{Binding Text}" />
</DataTemplate>

<viewLogic:CommandBarMenuItemTemplateSelector x:Key="CommandBarMenuItemTemplateSelector" 
                                              CbMenuItemTemplate="{StaticResource CbMenuItemTemplate}" />

用法:

代码语言:javascript
复制
  <CommandBar>
    <interactivity:Interaction.Behaviors>
       <viewLogic:BindableCommandBarBehavior ItemTemplateSelector="{StaticResource CommandBarMenuItemTemplateSelector}" PrimaryCommands="{Binding ContextActions}" />
    </interactivity:Interaction.Behaviors>
  </CommandBar>

其中ContextActions是我班的ObservableCollection ContextAction。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49423784

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档