wpf 使用 ViewModel 中的多态性绑定到 XAML 中带参数的方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19980612/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 00:00:02  来源:igfitidea点击:

Binding to a method with parameter in XAML using polymorphism in ViewModel

wpfmvvmbinding

提问by NZJames

I have a TabControl with six tabs in my ResultView. The ViewModel that sits behind this View can be either a ResultTypeOneViewModel or ResultTypeTwoViewModel, each of which derives from ResultViewModel but you can interchangeably use the result viewer with either result type.

我的 ResultView 中有一个带有六个选项卡的 TabControl。位于此视图后面的 ViewModel 可以是 ResultTypeOneViewModel 或 ResultTypeTwoViewModel,它们中的每一个都派生自 ResultViewModel,但您可以交替使用具有任一结果类型的结果查看器。

The difference is that in ResultTypeOneViewModel, tabs 1 & 3 need to be visible and the rest hidden. In ResultTypeTwoViewModel, tabs 2, 3, 4, 5, 6 need to be visible and tab 1 hidden.

不同之处在于,在 ResultTypeOneViewModel 中,选项卡 1 和 3 需要可见,其余部分需要隐藏。在 ResultTypeTwoViewModel 中,标签 2、3、4、5、6 需要可见,标签 1 需要隐藏。

I wanted to do this via something like

我想通过类似的东西来做到这一点

<TabItem Name="1" Visibility={Binding IsTabVisible(0)}>
<TabItem Name="2" Visibility={Binding IsTabVisible(1)}>
<TabItem Name="3" Visibility={Binding IsTabVisible(2)}>
etc...

And have an abstract method declaration in ResultsViewModel such as

并在 ResultsViewModel 中有一个抽象方法声明,例如

public abstract Visibility IsTabVisible(int index);

And in ResultsOneViewModel have

在 ResultsOneViewModel 中有

public override Visibility IsTabVisible(int index)
{
    if (index == 0 || index == 2) return Visibility.Visible;
    return Visibility.Hidden;
}

And in ResultsTwoViewModel have

在 ResultsTwoViewModel 中有

public override Visibility IsTabVisible(int index)
{
    if (index == 0) return Visibility.Hidden;
    return Visibility.Visible;
}

But I cannot figure out how to call a method like this with a parameter through bindings iN WPF XAML.

但是我无法弄清楚如何通过绑定 iN WPF XAML 使用参数调用这样的方法。

Can anyone suggest how I can do this or if it's not possible via this method, another way I could solve this problem?

任何人都可以建议我如何做到这一点,或者如果通过这种方法无法实现,我可以通过另一种方式解决这个问题?

回答by Sheridan

To answer your question directly, you can use the ObjectDataProviderto call a method for you so you can work with the results:

要直接回答您的问题,您可以使用ObjectDataProvider为您调用一个方法,以便您可以使用结果:

xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Windows="clr-namespace:System.Windows;assembly=PresentationCore"

...

<Window.Resources>
    <ObjectDataProvider x:Key="IsTab1VisibleMethod" 
        ObjectType="{x:Type Windows:Visibility}" IsAsynchronous="True" 
        MethodName="IsTabVisible">
        <ObjectDataProvider.MethodParameters>
            <System:Int32>0</System:Int32>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

You should then be able to access the result like this (but you'd need one of these for each TabItem):

然后,您应该能够像这样访问结果(但您需要为每个结果之一TabItem):

<TabItem Visibility="{Binding Source={StaticResource IsTab1VisibleMethod}}" />

However, it's generally not good practice to manipulate UI properties such as Visibilityin code, so a better idea would be to use a BooleanToVisibilityConverterto Bindthe Visibilityproperties to boolvalues as @Highcore suggested. You can see an example of this in the Binding a Button Visibility to bool value in ViewModelpost here on StackOverflow.

然而,这通常不是好的做法来操作UI特性,例如Visibility代码,所以一个更好的主意是使用一个BooleanToVisibilityConverterBindVisibility属性bool值@Highcore建议。您可以在 StackOverflow 上的在 ViewModel 中将按钮可见性绑定到 bool 值的帖子中看到这样的示例。

In my opinion, an even better solution would be to simply provide one view for every view model.

在我看来,更好的解决方案是简单地为每个视图模型提供一个视图。

回答by Enzojz

A better suggestion to this question is to use style.DataTrigger in style of TabItem like this:

这个问题的一个更好的建议是在 TabItem 的样式中使用 style.DataTrigger ,如下所示:

<TabItem>
    <TabItem.Style>
        <Style target="{x:Type TabItem}">
            <Style.DataTriggers>
                <DataTrigger Binding="{Binding IsTabVisible}" Value="False">
                    <Setter Property="Visibility" Value = "Collapsed"/>
                </DataTrigger>
            </Style.DataTrigers>
        </Style>
    <TabItem.Style>
</TabItem>

回答by XLars

You can use an indexer property to be able to pass a single parameter to a property. Although it's probably not very intuitive to return a boolean value from an indexer property it works fine for me. Also keep in mind the indexer property looses it's expected functionality.

您可以使用索引器属性将单个参数传递给属性。尽管从索引器属性返回布尔值可能不是很直观,但它对我来说很好用。还要记住,索引器属性失去了它的预期功能。

    class MyClass
    {
        public bool this[int tabNumber]
        {
            get
            {
                // Do logic to determine visibility here or in a separate method
                return IsTabVisible(tabNumber);
            }
        }

        bool IsTabVisible(int tabNumber)
        {
            bool result;

            // Method logic...

            return result;
        }
    }

So in XAML you can use the class name and provide a parameter between square brackets.

因此,在 XAML 中,您可以使用类名并在方括号之间提供一个参数。

<TabItem Visibility="{Binding MyClass[0]}}"/>

If you need to raise a NotifyPropertyChanged for the indexer property use:

如果您需要为索引器属性引发 NotifyPropertyChanged,请使用:

    NotifyPropertyChanged("Item[]");

I don't know if this fits into the MVVM pattern but it could be useful for anyone who wants to bind to a method with a single parameter.

我不知道这是否适合 MVVM 模式,但对于想要绑定到具有单个参数的方法的任何人来说,它可能很有用。