【问题标题】:How can I bind a command from my IntemsControl list to my main ViewModel?如何将 IntemsControl 列表中的命令绑定到主 ViewModel?
【发布时间】:2014-07-22 02:03:23
【问题描述】:

如何将 IntemsControl 列表中的命令绑定到主 ViewModel?

<Window x:Class="MemoryGame.MainWindow"
        ...
        DataContext="{Binding Main, Source={StaticResource Locator}}">
    <Window.Resources>
        <me:ColorConverter x:Key="ColorConverter"/>
    </Window.Resources>
    <Grid x:Name="LayoutRoot" Background="#FF44494D">
        <ItemsControl ItemsSource="{Binding GameBoard.CardList}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel IsItemsHost="True" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle x:Name="Card01" Fill="{Binding Converter={StaticResource ColorConverter}}" Height="100" Width="100" Margin="10,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Stroke="Black">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Click">
                                <i:InvokeCommandAction Command="{Binding SelectCardCommand, ???????????}" CommandParameter="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </Rectangle>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        ...

SelectCardCommand 在我的主窗口 ViewModel 中定义。我已经尝试添加 RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window} 但它不起作用。

---- 编辑更多信息----

在我的 DataContext ViewModel 我有这个:

public class MainViewModel : ViewModelBase
{
    private RelayCommand<string> _selectCardCommand;
    public RelayCommand<string> SelectCardCommand
    {
        get
        {
            return _selectCardCommand;
        }
    }

    public MainViewModel()
    {
        _selectCardCommand = new RelayCommand<string>((s) => DoSelectCardCommand(s));
        // GameBoard = new Board();
        // this.StartGame();
    }

    private void DoSelectCardCommand(string card)
    {
        // Code here
    }
}

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

    你可以使用两种方法

    使用RelativeSource

    <i:EventTrigger EventName="Click">
        <i:InvokeCommandAction Command="{Binding DataContext.SelectCardCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}}" 
                               CommandParameter="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/>
    </i:EventTrigger>
    

    或使用ElementName

    <i:EventTrigger EventName="Click">
        <i:InvokeCommandAction Command="{Binding DataContext.SelectCardCommand, ElementName=LayoutRoot}" 
                               CommandParameter="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/>
    </i:EventTrigger>
    

    编辑

    执行代码后我意识到了原因,因为矩形没有任何名为Click的事件所以它没有绑定,但是你可以绑定到UIElement.MouseDown

    另外,我想出了一种不同的方法来解决您的问题。

    我稍微修改了模板以使用 Button,并根据需要对按钮进行了模板化,还更改了 ItemsPanelTemplate,使其看起来更像一个记忆游戏

        <ItemsControl ItemsSource="{Binding GameBoard.CardList}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid IsItemsHost="True" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Command="{Binding DataContext.SelectCardCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}}"
                            CommandParameter="{Binding}">
                        <Button.Template>
                            <ControlTemplate>
                                <Rectangle Fill="{Binding Converter={StaticResource ColorConverter}}"
                                           Height="100"
                                           Width="100"
                                           Margin="10,10,0,0"
                                           Stroke="Black">
                                </Rectangle>
                            </ControlTemplate>
                        </Button.Template>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    

    命令

        #region SelectCardCommand
    
        public RelayCommand<Card> SelectCardCommand { get; private set; }
    
        #endregion
    
        public MainViewModel()
        {
            SelectCardCommand = new RelayCommand<Card>((s) => DoSelectCardCommand(s));
            GameBoard = new Board();
            this.StartGame();
        }
    
        private void DoSelectCardCommand(Card card)
        {
            if (card != null)
                card.Upside = true;
        }
    

    这也将帮助您删除 int.Parse(card.Substring(4,2)); 和其他字符串操作

    【讨论】:

    • 这是有效的。我的命令已绑定,但现在无法访问我的 DoSomething 方法。 Grrr XAML 对设计者来说很好,但对不关心图形界面的开发者来说是地狱。我想我更喜欢逐像素绘制。我更喜欢使用我的逻辑而不是我的记忆。
    • DoSomething 在哪里?你能张贴一张你想要达到的目标的大图吗?阻塞问题在哪里?使用 WPF 可能根本不需要绘制像素。
    • 我看不到实际问题,但是您可以使用选择器并绑定SelectedItem 属性,而不是执行选择卡命令。从代码中分析问题有点困难。您可以发布代码的工作示例吗?我可以看一下整体吗?
    • 您可以上传到任何文件共享服务并在此处或问题本身中发布链接。
    • 感谢您的帮助。我会按照你的修改。
    猜你喜欢
    • 2015-10-30
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 2012-02-23
    • 2016-10-18
    • 2021-10-25
    • 2010-12-05
    • 2017-06-15
    相关资源
    最近更新 更多